कोड का निम्न भाग फ़ाइल में विभिन्न स्थानों पर अधिलेखित करने और फ़ाइल में संलग्न करने का प्रयास करता है। हालांकि, यह काम नहीं लग रहा है। मैंने कई तरीकों की कोशिश की है और नतीजा या तो ओवरराइटिंग है या फ़ाइल के अंत में सबकुछ जोड़ रहा है लेकिन दोनों एक साथ नहीं हैं। क्या सी ++ में ऐसा करना संभव है? या, यह है कि इसे पूरा करने के लिए हमें फ़ाइल को अलग-अलग मोड में बार-बार खोलने की आवश्यकता है?

int main() {
  fstream f("a.dat", ios::out | ios::app);
  f.seekp(ios::beg);
  f << "hello world";
  f.seekp(ios::end);
  f << "works";
  return 0;
}
2
r.v 3 मार्च 2011, 06:20
आपके उपयोग के लिए प्रासंगिक नहीं हो सकता है, लेकिन यह इंगित करने योग्य है कि, आईआईआरसी, परिशिष्ट मोड में ओएस स्वयं फ़ाइल में लिखने के अनुरोधों के बीच कुछ सिंक प्रदान करता है, इसलिए प्रत्येक लेखक की सामग्री को किसी क्रम में वहां पहुंचने की गारंटी है। यदि आप अपने आप को किसी अन्य मोड में जोड़ते हैं, तो आपको दौड़ की स्थितियों पर विचार करने की आवश्यकता है जहां आपको अंत मिलता है, फिर कोई अन्य प्रक्रिया अंत में लिखती है, फिर आप अन्य प्रक्रिया या थ्रेड के डेटा को लिखते और समाप्त करते हैं। यदि यह आपके लिए एक समस्या है, तो आप वास्तव में फ़ाइल को बंद/फिर से खोलना चाहते हैं, या दो अलग-अलग हैंडल रख सकते हैं - केवल एक परिशिष्ट मोड का उपयोग कर रहा है।
 – 
Tony Delroy
3 मार्च 2011, 07:03
क्या आप जो कह सकते हैं उसका मतलब यह हो सकता है कि सी ++ ऐसी चीज प्रदान नहीं करता जैसा मैं ढूंढ रहा हूं?
 – 
r.v
3 मार्च 2011, 07:09
2
सी ++ - या कोई भी भाषा - केवल फाइल मैनिपुलेशन के लिए ऑपरेटिंग सिस्टम सुविधाओं तक पहुंच प्रदान कर सकती है (जब तक कि आप फाइल सिस्टम ड्राइवर को स्वयं नहीं लिख रहे हों)। अधिकांश ऑपरेटिंग सिस्टम पर, एक विशेष एपेंड मोड होता है जो प्रक्रियाओं/धागे के बीच दौड़ की स्थिति को संभालता है, और जैसा कि आप जानते हैं कि सी ++ आपको इसका उपयोग करने देता है। यदि यह आपके अनुरूप नहीं है, लेकिन आपके पास दौड़ की स्थिति होगी, तो आपको स्वयं को सिंक करना होगा ... सहयोगी प्रक्रियाओं के बीच साझा स्मृति में एक म्यूटेक्स का उपयोग करना, या एक म्यूटेक्स कहीं भी अगर धागे का एक गुच्छा है।
 – 
Tony Delroy
3 मार्च 2011, 07:17

3 जवाब

सबसे बढ़िया उत्तर

यदि आप फ़ाइल खोलते समय ios::app निर्दिष्ट करते हैं तो सभी लिखने वाले हमेशा फ़ाइल के अंत में जाएंगे - यह मूल रूप से ऐसा है जैसे हर लिखने से पहले f.seekp(ios::end) था।

ऐसा लगता है कि इसके बजाय आप जो चाहते हैं वह ios::ate है। यह खोले जाने के तुरंत बाद फ़ाइल के अंत की तलाश करेगा, लेकिन जब/यदि आप फ़ाइल में कहीं और खोजते हैं और लिखते हैं, तो लेखन अंत के बजाय फ़ाइल में वर्तमान बिंदु पर जाएगा।

संपादित करें 3: मैंने अंत तक वापस जाने और वहां और जोड़ने के लिए कोड जोड़ा है:

#include <fstream>
#include <iostream>

int main() { 
    std::fstream f("test.txt", std::ios::in | std::ios::out | std::ios_base::ate);

     f << " added to end.";
     f.seekp(0, std::ios::beg);
     f << "Original";
     f.seekp(0, std::ios::end);
     f << " Final.";

     return 0;
}

"test.txt" फ़ाइल की सामग्री के रूप में निम्नलिखित के साथ प्रारंभ करना:

Initial  Value.

प्रोग्राम चलाने के बाद, फ़ाइल में शामिल होना चाहिए:

Original value. added to end. Final.

तो, "समाप्त करने के लिए जोड़ा गया।" स्पष्ट रूप से पर्याप्त हो जाता है, अंत में जोड़ा जाता है। हम फिर शुरुआत में वापस खोजते हैं, और "प्रारंभिक" (इसके बाद के दो रिक्त स्थान में से एक) को "मूल" के साथ अधिलेखित कर देते हैं।

एक तरफ के रूप में, मुझे यह जोड़ना चाहिए कि जब मैंने कल रात पोस्ट किया था तो मैं स्पष्ट रूप से कम से कम आधा सो रहा था - मैं पूरी तरह से इस तथ्य से चूक गया कि आपने केवल पैरामीटर पर आपूर्ति की थी जब आपने seekp को कॉल किया था। केवल एक पैरामीटर के साथ, यह फ़ाइल में ऑफ़सेट के रूप में लेता है। दुर्भाग्य से, std::ios::beg, std::ios::cur और std::ios::end साधारण पूर्णांक मान हैं, इसलिए एक प्रकार की त्रुटि देने के बजाय (जैसा कि आप वास्तव में चाहेंगे) यह केवल मान ले रहा था। em> उन गणनाओं का, और उन्हें फ़ाइल में ऑफ़सेट के रूप में उपयोग करना। विशुद्ध रूप से भाग्य से, std::ios::beg का स्पष्ट रूप से मूल्य 0 (कम से कम मेरे कार्यान्वयन पर) है, इसलिए यह "काम" करता है, लेकिन केवल दुर्घटना से। दो मापदंडों के साथ (जैसा कि ऊपर दिए गए कोड में है) पहला ऑफसेट है, और दूसरा यह संदर्भ बिंदु (शुरुआत, वर्तमान स्थिति या अंत) है जिससे वह ऑफसेट शुरू होता है।

4
Jerry Coffin 3 मार्च 2011, 20:09
आपके कोड वाली फ़ाइल में मुझे जो अंतिम परिणाम मिलता है, वह New to end. है। ऐसा लगता है कि मानों को अधिलेखित कर दिया गया था। आपके कोड से ios::in हटाने के बाद मुझे यह परिणाम मिला है। अपना कोड चलाना जैसा मुझे दिया गया है New Value। मैं जी ++ का उपयोग कर रहा हूँ।
 – 
r.v
3 मार्च 2011, 07:06
@ r.v: क्षमा करें - मैंने संपादन खराब कर दिया है। मुझे विश्वास है कि यह अब ठीक हो गया है। मैंने इसे वीसी ++ और जी ++ दोनों के साथ परीक्षण किया है, और एक ही परिणाम प्राप्त किया है। जैसा कि ऊपर उल्लेख किया गया है, हालांकि, यह फ़ाइल में पहले से ही कुछ सामग्री के साथ शुरू होने की अपेक्षा करता है। इसके बिना, आपको इसे काम करने के लिए std::ios::in को हटाना होगा, और इसे "Originalo end" बनाना चाहिए।
 – 
Jerry Coffin
3 मार्च 2011, 09:07
तुम सही हो। यह सही है। फिर भी, अगर मैं पुट पॉइंटर को ios :: पर फिर से ले जाता हूं, तो यह संलग्न नहीं होता है बल्कि ओवरराइट करता है। उदाहरण के लिए, Original में लिखने के बाद यदि मैं f.seekp(std::ios::end); f<< " Finally"; कहूं। यह अब और भी जटिल प्रतीत होता है।
 – 
r.v
3 मार्च 2011, 19:30
कोड के लिए धन्यवाद। एक और सवाल। फ़ाइल ओपन मोड में std::ios::in का उपयोग करना आवश्यक प्रतीत होता है, भले ही हम फ़ाइल से नहीं पढ़ रहे हों। अगर मैं इस ध्वज का उपयोग नहीं करता हूं तो मुझे अलग परिणाम मिलते हैं। यह मुझे सोचने पर मजबूर कर देता है कि या तो भाषा स्तर पर या OS स्तर पर क्या हो रहा है। क्या आप उस पर और प्रकाश डाल सकते हैं?
 – 
r.v
4 मार्च 2011, 23:24
@ r.v: भले ही आप फ़ाइल से डेटा का उपयोग नहीं कर रहे हैं, दृश्यों के पीछे यह अभी भी डेटा पढ़ रहा है। एक विशिष्ट डिस्क केवल सेक्टर-आकार के विखंडू के गुणकों में डेटा को पढ़ने या लिखने की अनुमति देती है। किसी सेक्टर में डेटा को संशोधित करने के लिए, उसे एक पढ़ना/संशोधित/लिखना चक्र करना होता है।
 – 
Jerry Coffin
5 मार्च 2011, 01:42

क्या आप उस फ़ाइल में कहीं डेटा सम्मिलित करना चाह रहे हैं जो अंत नहीं है? मेरे अनुभव में, कम से कम fstreams के साथ कोई प्रविष्टि नहीं है। यह एक सरणी में डेटा लिखने जैसा है। बस सरणी की शुरुआत और अंत के बीच कहीं एक पॉइंटर होने और वहां लिखने से सम्मिलित नहीं होता है, यह ओवरराइट करता है।

इसे ऐसे संभालें जैसे आप किसी सरणी के बीच में डेटा डालेंगे। सम्मिलन के लिए जगह बनाने के लिए आपको डेटा को आगे बढ़ाना होगा।

गणना करें कि आपको सम्मिलन के लिए कितनी जगह की आवश्यकता होगी और सम्मिलन बिंदु के बाद सभी डेटा को बफर में पढ़ें, उस बफर में डेटा को फ़ाइल में वापस लिखें जब आप अपने लेखन सूचक को आगे की जगह से आगे ले जाएं ' डालने की आवश्यकता होगी। फिर, अपने राइट पॉइंटर को वापस उस स्थान पर ले जाएँ जहाँ आप सम्मिलित करना चाहते हैं और वह डेटा लिखें जिसे आप सम्मिलित करने की योजना बना रहे हैं।

  1. सम्मिलन डेटा लंबाई की गणना करें।
  2. सम्मिलन बिंदु की तलाश करें।
  3. बाकी फाइल को बफर में पढ़ें।
  4. सम्मिलन बिंदु की तलाश करें।
  5. सम्मिलन डेटा लिखें।
  6. बाकी फ़ाइल बफर से लिखें।

संपादित करें: अनुरोधित कोड उदाहरण:

#include <fstream>

int main(int argc, char* argv[])
{
    std::fstream FileStream;

    // Initial write.
    FileStream.open("Test.txt", std::ios::out | std::ios::trunc);
    FileStream << "OLDDATAOLDDATA";
    FileStream.close();

    // Prepare data to insert.
    const char InsertionData[] = "newdata";
    const unsigned int InsertionDataLength = strlen(InsertionData);

    // Insertion write.
    FileStream.open("Test.txt", std::ios::in | std::ios::out | std::ios::ate);

    std::ios::pos_type InsertionPosition = 7; // 7 is the start index of the second "OLDDATA".
    FileStream.seekg(0, std::ios::end);
    std::ios::pos_type EndPosition = FileStream.tellg();

    // Read rest of file.
    const unsigned int RestOfFileDataLength = EndPosition - InsertionPosition;
    char* const RestOfFileData = new char[RestOfFileDataLength];
    FileStream.seekg(InsertionPosition);
    FileStream.read(RestOfFileData, RestOfFileDataLength);

    // Rewrite rest of file.
    FileStream.seekp(InsertionPosition);
    FileStream.write(InsertionData, InsertionDataLength);
    FileStream.write(RestOfFileData, RestOfFileDataLength);
    delete[] RestOfFileData;

    FileStream.close();
}

कुछ नोट्स। जितनी जल्दी आप फ़ाइल में सम्मिलित करते हैं, उतना ही महंगा होता है क्योंकि आपको इसके बाद सब कुछ स्थानांतरित करने की आवश्यकता होती है। इसका मतलब यह भी है कि बड़ी फ़ाइलों को सम्मिलित करना अधिक महंगा होता है। यदि आप कई प्रविष्टियां करने जा रहे हैं, तो आप प्रत्येक प्रविष्टि का ट्रैक रखने का प्रयास कर सकते हैं और उन्हें तब तक स्थगित कर सकते हैं जब तक कि किसी प्रकार का फ्लश कमांड नहीं कहा जाता है, जिस बिंदु पर शेष फ़ाइल का केवल 1 प्रमुख पढ़ना/लिखना आवश्यक है, इसके बजाय प्रत्येक प्रविष्टि कॉल के लिए एक। आदर्श रूप से, आपको इसे किसी प्रकार के अपने स्वयं के आवरण में लपेटना चाहिए।

5
sehe 13 मई 2011, 12:04
शायद मैंने अपने प्रश्न में इसे स्पष्ट नहीं किया। मैंने इसे अभी संपादित किया है। यह सम्मिलन नहीं है जो मैं चाहता हूं। मैं सिर्फ अलग-अलग स्थानों पर ओवरराइट करना चाहता हूं और साथ ही फाइल में जोड़ना चाहता हूं। मैं इन दोनों के एक साथ संभव होने की उम्मीद कर रहा था। किसी भी मामले में, आप जो कहते हैं वह फ़ाइल का विस्तार कर रहा है, शायद संलग्न करके (आप एक नई फ़ाइल नहीं बना रहे हैं, है ना?) क्या आप मुझे इसके लिए एक कामकाजी नमूना कोड दे सकते हैं?
 – 
r.v
3 मार्च 2011, 19:06
@r.v नमूना जोड़ा गया। कोई नई फ़ाइल आवश्यक नहीं है। यह मूल सम्मिलन तर्क दिखाता है। ध्यान रहे कि प्रत्येक प्रविष्टि महंगी है। आदर्श रूप से, आप अपने सभी इंसर्शन को बफर कर देंगे और उन्हें अंत तक स्थगित कर देंगे, क्योंकि प्रत्येक रीड-एंड-राइट-रेस्ट-ऑफ-फाइल तेजी से महंगी हो जाती है क्योंकि फाइल बड़ी होती है और इंसर्शन पॉइंट पहले होता है।
 – 
Sion Sheevok
4 मार्च 2011, 02:10
नमूने के लिए धन्यवाद। मैं देखता हूं कि आप नई फ़ाइल की आवश्यकता के बिना फ़ाइल का विस्तार करने में सक्षम हैं और मेरे कोड में ऐसी चीज़ का उपयोग करने में सक्षम हो सकते हैं।
 – 
r.v
4 मार्च 2011, 23:21

आपको क्या जानना होगा:

  • संलग्न मोड फ़ाइल के अंत में लिखता है, इससे कोई फर्क नहीं पड़ता कि आप क्या चाहते हैं
  • अन्य लेखन विधियों में भी, फ़ाइल की शुरुआत में लिखना प्रीपेन्ड नहीं होता है, यह ओवरराइट कर देता है। यह सी ++ की "गलती" नहीं है क्योंकि यह फाइल सिस्टम है। यह फ़ाइल हेरफेर के काम करने का तरीका है, और लगभग हर प्लेटफॉर्म और हर भाषा के लिए यही स्थिति होगी।
  • यदि आप वास्तव में अन्य स्थानों पर टेक्स्ट सम्मिलित करना चाहते हैं, तो आपको संभवतः फ़ाइल को मेमोरी में पढ़ना होगा, उसमें हेरफेर करना होगा, फिर फ़ाइल को डिस्क पर फिर से लिखना होगा। या कुछ मामलों में फ़ाइल में हेरफेर करने के लिए sed जैसे कुछ का उपयोग करना समझ में आता है।

फ़ाइल प्रीप्रेंड क्षमताएं प्रदान करने वाली भाषाएं दुर्लभ हैं। जब तक आप sed जैसी विशेष प्रयोजन वाली भाषाओं की गिनती नहीं करते हैं, जो किसी भी लेकिन फ़ाइल हेरफेर के लिए अच्छी नहीं हैं, मुझे नहीं पता। ऐसी भाषाएं हो सकती हैं जो आप जिस तरह से उम्मीद कर रहे थे वह करते हैं, लेकिन मुझे किसी के बारे में पता नहीं है।

1
Darryl 3 मार्च 2011, 10:36
मैं देखता हूं कि कुछ ओएस/एफएस बाधाएं होनी चाहिए जिसके कारण सी ++ कुछ अनुमति नहीं दे रहा है। मुझे बस ओवरराइट करने और फ़ाइल में संलग्न करने की आवश्यकता थी। स्वयं संलग्न करने की अनुमति है। लेकिन क्या फ़ाइल में विभिन्न स्थानों पर संलग्न करना और (उसी मोड में) ओवरराइट करना संभव है?
 – 
r.v
3 मार्च 2011, 19:09