MyOldAccount Ответов: 1

Размер файла больше, чем должен быть, добавляются дополнительные новые строки


ВСТУПЛЕНИЕ:

Я читаю из текстового файла с помощью ReadFile. Буфер, переданный в ReadFile, отправляется на стандартный вывод с помощью cout. Стандартный вывод перенаправляется в текстовый файл.

ПРОБЛЕМА:

Хотя мой код "работает", никакие данные не теряются, результирующий файл больше исходного.

При открытии в блокноте все кажется прекрасным, но при открытии в блокноте++ я отчетливо вижу добавленные дополнительные строки. Эти строки являются новыми строками (\n).

MVCE, который воспроизводит это поведение, представлен ниже.

#include <iostream>
#include <windows.h>

int main()
{
    HANDLE hFile = ::CreateFile("C:\\123.txt", 
        GENERIC_READ,
        FILE_SHARE_READ | 
        FILE_SHARE_WRITE | 
        FILE_SHARE_DELETE,
        NULL, 
        OPEN_EXISTING, 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);

    if (INVALID_HANDLE_VALUE == hFile) 
        return ::GetLastError();

    char buffer[256];
    DWORD bytesRead = 1,  // dummy value so while loop can work
        bytesWritten = 0; // needed for WriteFile, not for cout version

    //======== so WriteFile outputs to console, not needed for cout version
    HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);

    if (INVALID_HANDLE_VALUE == hStandardOutput)
    {
        std::cout << "GetStdHandle error code = " << ::GetLastError() << std::endl;
        ::CloseHandle(hFile);
        return ::GetLastError();
    }
    //============================
    while(bytesRead)
    {
        // '\0' terminate buffer, needed for cout only
        ::memset(buffer, '\0', sizeof(buffer)); 

        if (!::ReadFile(hFile, 
            buffer, 
            sizeof(buffer) - 1, // - 1 for '\0', not needed when using WriteFile
            &bytesRead, NULL))
        {
            std::cout << "ReadFile error code = " << ::GetLastError() << std::endl;
            break;
        }
        /*============= Works fine
        if(!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL))
        {
            std::cout << "WriteFile error code = " << ::GetLastError() << std::endl;
            break;
        }*/
        //------------- comment out when testing WriteFile 
        std::cout << buffer;  // extra lines...
        // std::cout.write(buffer, bytesRead); // extra lines as well...
        //----------------------------------------
    }
    ::CloseHandle(hFile);
    return 0;
}


ВОПРОС:

Что вызывает вышеописанное поведение? Как это исправить?

Что я уже пробовал:

Когда я печатаю этот пост, я бесцельно гуглю, надеясь найти какую-нибудь подсказку.

Я подозреваю, что проблема заключается в том, что при выводе \n кажется, что Windows также вставляет \r, но я не уверен.

Richard MacCutchan

Сколько дополнительных строк вы видите в выходном файле? Вполне возможно, что последний прочитанный блок не заполняет буфер, но когда вы отправляете его в std:: out, он содержит дополнительные новые строки. То, что вы делаете, - не лучший способ скопировать текстовый файл из одного места в другое.

MyOldAccount

Сколько дополнительных строк вы видите в выходном файле? Примерно 10% от размера файла. Изучив файл, я обнаружил, что файл заполнен \r\r\n вместо \n. Следующая ссылка, раздел двоичный и текстовый режимы, по-видимому, объясняет, почему: http://en.cppreference.com/w/cpp/io/c#Binary_and_text_modes

Richard MacCutchan

Да, потому что вы эффективно читаете его в двоичном режиме.

MyOldAccount

Я согласен, но тогда std::cout.write(buffer, bytesRead); в моем примере кода должно работать, не так ли? Тем не менее, я получаю тот же результат. Это должна быть подробная информация о реализации, указанная в ссылке... Я думаю ReadFile должно быть в паре с WriteFile в этом случае, так как только тогда я получаю правильный вывод...

Richard MacCutchan

Именно так. Как я уже говорил, ReadFile читает файл в байтовом режиме (эффективно читает в двоичном), поэтому символы новой строки не интерпретируются.

1 Ответов

Рейтинг:
1

Arthur V. Ratz

Причина следующей проблемы, насколько я могу понять, на самом деле последний вызов функции ReadFile API. На самом деле во время последнего вызова функции Вы читаете за пределами файла.


Richard MacCutchan

Не правда, смотрите мой последний комментарий.