القراءة من ملف نصي حتى يكرر EOF السطر الأخير [نسخة مكررة]

StackOverflow https://stackoverflow.com/questions/21647

  •  09-06-2019
  •  | 
  •  

سؤال

الأتى سي ++ يستخدم الكود أ com.ifstream كائن لقراءة الأعداد الصحيحة من ملف نصي (الذي يحتوي على رقم واحد في كل سطر) حتى يصل EOF.لماذا يقرأ العدد الصحيح في السطر الأخير مرتين؟كيف يمكن اصلاح هذا؟

شفرة:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

input.txt:

10  
20  
30

انتاج |:

10  
20  
30  
30

ملحوظة:لقد تخطيت كل رموز التحقق من الأخطاء لإبقاء مقتطف الشفرة صغيرًا.يظهر السلوك أعلاه على أنظمة Windows (Visual C++) وcygwin (gcc) وLinux (gcc).

هل كانت مفيدة؟

المحلول

فقط تابع عن كثب سلسلة الأحداث.

  • الاستيلاء على 10
  • الاستيلاء على 20
  • الاستيلاء على 30
  • الاستيلاء على EOF

انظر إلى التكرار الثاني إلى الأخير.لقد أمسكت بـ 30، ثم واصلت التحقق من وجود EOF.لم تصل إلى EOF لأن علامة EOF لم تتم قراءتها بعد ("بمعنى ثنائي"، موقعها المفاهيمي يقع مباشرة بعد السطر 30).لذلك يمكنك الاستمرار في التكرار التالي.x لا يزال 30 من التكرار السابق.الآن تقرأ من الدفق وتحصل على EOF.يبقى x 30 ويتم رفع ios::eofbit.يمكنك الإخراج إلى stderr x (وهو 30، تمامًا كما في التكرار السابق).بعد ذلك، عليك التحقق من وجود EOF في حالة الحلقة، وهذه المرة تكون خارج الحلقة.

جرب هذا:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

بالمناسبة، هناك خطأ آخر في التعليمات البرمجية الخاصة بك.هل سبق لك أن حاولت تشغيله على ملف فارغ؟السلوك الذي تحصل عليه هو لنفس السبب بالضبط.

نصائح أخرى

يعجبني هذا المثال، والذي يتجاهل حاليًا علامة الاختيار التي يمكنك إضافتها داخل الكتلة while:

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

لست متأكدا من مدى أمانها ...

هناك نهج بديل لهذا:

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));

يحتاج نمط EOF إلى قراءة أولية من أجل "تمهيد" عملية فحص EOF.ضع في اعتبارك أن الملف الفارغ لن يتم تعيين EOF الخاص به في البداية حتى القراءة الأولى.سوف تلتقط القراءة الأولية EOF في هذه الحالة وتتخطى الحلقة بالكامل بشكل صحيح.

ما تحتاج إلى تذكره هنا هو أنك لن تحصل على EOF حتى المحاولة الأولى لقراءة البيانات المتوفرة للملف.لن تؤدي قراءة الكمية الدقيقة من البيانات إلى وضع علامة على EOF.

يجب أن أشير إلى ما إذا كان الملف فارغًا، لكان من الممكن طباعة الكود المحدد لأن EOF سيمنع تعيين القيمة على x عند الدخول إلى الحلقة.

  • 0

لذا أضف قراءة أولية وانقل قراءة الحلقة إلى النهاية:

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}

بدون إجراء الكثير من التعديلات على الكود الأصلي، يمكن أن يصبح:

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

لكنني أفضل الحلين الآخرين أعلاه بشكل عام.

int x;
ifile >> x

while (!iFile.eof())
{  
    cerr << x << endl;        
    iFile >> x;      
}

في نهاية السطر الأخير، يكون لديك حرف سطر جديد، لا يمكن قراءته بواسطة عامل التشغيل >> وهو ليس نهاية الملف.من فضلك قم بالتجربة واحذف السطر الجديد (آخر حرف في الملف) - لن تحصل على التكرار.للحصول على كود مرن وتجنب التأثيرات غير المرغوب فيها، ما عليك سوى تطبيق أي حل يقدمه المستخدمون الآخرون.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top