Почему моя программа дает разные результаты в Windows и Linux, о чтении файлов с помощью ifstream? - PullRequest
5 голосов
/ 22 марта 2012

У меня есть программа, показанная следующим образом.Для этого у меня есть несколько вопросов:

1). Почему это приводит к разным результатам на разных платформах? Я вставлю скриншоты позже.

2). Я использую метод fail (), чтобы проверить, не произошел ли сбой file.read ().Это правильно? Я использую метод fail (), потому что эта веб-страница говорит следующее:

Функция возвращает true, если установлен либо failbit, либо badbit.По крайней мере один из этих флагов устанавливается, когда какая-то ошибка , отличная от достижения конца файла, возникает во время операции ввода.

Но позже я прочитал эту страницу об istream:: read () здесь .Он говорит, что eofbit и failbit всегда будут установлены одновременно .. Означает ли это, что нормальная ситуация EOF также приведет к тому, что fail () вернет true?Похоже, это конфликтует с «кроме достижения конца файла» ..

Может ли кто-нибудь помочь мне уточнить, как я должен использовать эти методы?Должен ли я использовать bad () вместо этого?

Моя программа

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

#ifdef WIN32
char * path="C:\\Workspace\\test_file.txt";
#else
char * path="/home/robin/Desktop/temp/test_file.txt";
#endif

int main(int argc, char * argv[])
{
    ifstream file;

    file.open(path);
    if (file.fail())
    {
        cout << "File open failed!" << endl;
        return -1;  // If the file open fails, quit!
    }

    // Calculate the total length of the file so I can allocate a buffer
    file.seekg(0, std::ios::end);
    size_t fileLen = file.tellg();
    cout << "File length: " << fileLen << endl;
    file.seekg(0, std::ios::beg);

    // Now allocate the buffer
    char * fileBuf = new (std::nothrow) char[fileLen+1];
    if (NULL == fileBuf)
        return -1;
    ::memset((void *)fileBuf, 0, fileLen+1);    // Zero the buffer

    // Read the file into the buffer
    file.read(fileBuf, fileLen);
    cout << "eof: " << file.eof() << endl
         << "fail: " << file.fail() << endl
         << "bad: " << file.bad() << endl;
    if (file.fail())
    {
        cout << "File read failed!" << endl;
        delete [] fileBuf;
        return -1;
    }

    // Close the file
    file.close();

    // Release the buffer
    delete [] fileBuf;

    return 0;
}

Содержимое test_file.txt (показано с помощью "vim -b". Это очень простой файл):

test_file.txt content

Результат в Windows (Visual Studio 2008 SP1):

Windows result

Результат в Linux (gcc 4.1.2):

Linux result

Ответы [ 2 ]

9 голосов
/ 22 марта 2012

Означает ли это, что нормальная ситуация EOF также приведет к тому, что fail () вернет true? Похоже, что это конфликтует с «кроме достижения конца файла».

Я рекомендую использовать ссылку, которая не полна ошибок.

http://en.cppreference.com/w/cpp/io/basic_ios/fail говорит:

Возвращает true, если произошла ошибка в связанном потоке. В частности, возвращает true, если в rdstate() установлено badbit или failbit.

И стандарт C ++ гласит:

Возвращает: true, если бит сбоя или badbit установлен в rdstate().

Нет ничего, кроме конца файла. Операция, которая пытается прочитать после конца файла, также приведет к установке failbit. eofbit служит только для того, чтобы отличить эту конкретную причину сбоя от других (и это не так полезно, как может показаться на первый взгляд).


Я использую метод fail(), чтобы проверить, не завершился ли «file.read ()». Это правильно?

Вы должны просто протестировать с преобразованием в bool.

if(file) { // file is not in an error state

Это синоним !fail(), но его удобнее использовать, потому что вы можете использовать его для непосредственного тестирования результата операции чтения без лишних скобок (такие вещи, как !(stream >> x).fail() становятся неудобными):

if(file.read(fileBuf, fileLen)) { // read succeeded

Вы заметите, что все операции чтения в потоках возвращают сам поток, что позволяет вам это делать.


Почему он дает разные результаты на разных платформах?

Разница между Windows и Linux заключается в том, что файл открыт в текстовом режиме: символы новой строки будут преобразованы без вывода сообщений при реализации. Это означает, что комбинация "\r\n" (используется в Windows для перевода строки) будет преобразована в один символ '\n' в Windows, в результате чего файл будет иметь только 8 символов. Обратите внимание, что vim показывает ^M в конце первой строки: это часть '\r'. В Linux новая строка - просто '\n'.

Вам следует открыть файл в двоичном режиме, если вы хотите сохранить оригинал как есть:

file.open(path, std::ios_base::in | std::ios_base::binary);
2 голосов
/ 22 марта 2012

Полагаю, проблема здесь с другим исполнением заключается в соглашении между DOS (Window) и UNIX.

В DOS строка заканчивается на <CR><LF>, и это читается / записывается вместе как '\n'. Таким образом, в Windows ваш файл находится в конце, а в UNIX нет, так как остался один символ.

...