Читать бинарный файл с ++ - PullRequest
8 голосов
/ 28 мая 2011

Я пытаюсь прочитать изображение в массив символов.Вот моя попытка:

ifstream file ("htdocs/image.png", ios::in | ios::binary | ios::ate);
ifstream::pos_type fileSize;
char* fileContents;
if(file.is_open())
{
    fileSize = file.tellg();
    fileContents = new char[fileSize];
    file.seekg(0, ios::beg);
    if(!file.read(fileContents, fileSize))
    {
        cout << "fail to read" << endl;
    }
    file.close();

    cout << "size: " << fileSize << endl;
    cout << "sizeof: " << sizeof(fileContents) << endl;
    cout << "length: " << strlen(fileContents) << endl;
    cout << "random: " << fileContents[55] << endl;
    cout << fileContents << endl;
}

И это вывод:

size: 1944
sizeof: 8
length: 8
random: ?
?PNG

Кто-нибудь может мне это объяснить?Есть ли в конце 8 символ конца файла?Этот пример был взят из cplusplus.com

Работает Mac OS X и компилируется с XCode.

Ответы [ 5 ]

10 голосов
/ 28 мая 2011
  1. Возвращает размер файла.размер вашего image.png равен 1944 bytes.

    cout << "size: " << fileSize << endl;

  2. Возвращает sizeof(char*), что * 8 для вашей среды. Обратите внимание, что размер любого указателя всегда одинаков в любой среде.

    cout << "sizeof: " << sizeof(fileContents) << endl;

  3. Файл, который вычтение - это двоичный файл, поэтому он может содержать 0 в качестве допустимых данных.Когда вы используете strlen, он возвращает длину до тех пор, пока не встретится 0, который в случае вашего файла равен 8.

    cout << "length: " << strlen(fileContents) << endl;

  4. Возвращает символ в 56th location (помните, что индексирование массива начинается с 0) от начала файла.

    cout << "random: " << fileContents[55] << endl;

Предложение:

Не забудьте освободить динамическое выделение памяти для fileContents, используя:

delete[] fileContents;

, если вы этого не сделаете,в итоге вы создадите утечка памяти .

3 голосов
/ 28 мая 2011

fileSize - количество байтов в файле.

sizeof (fileContents) - возвращает размер указателя на символ *.

strlen (fileContents) - подсчитывает количество символов, пока не будет найден символ со значением '0'. Это очевидно после всего лишь 8 символов - поскольку вы читаете двоичные данные, это не является неожиданным результатом.

cout << fileContents - подобно strlen, cout записывает символы, пока не будет найден символ со значением '0'. Из вывода видно, что некоторые символы не могут быть напечатаны. </p>

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

vector< char > fileContents;

{
  ifstream file("htdocs/image.png", ios::in | ios::binary | ios::ate);
  if(!file.is_open())
    throw runtime_error("couldn't open htdocs/image.png");

  fileContents.resize(file.tellg());

  file.seekg(0, ios::beg);
  if(!file.read(&fileContents[ 0 ], fileContents.size()))
    throw runtime_error("failed to read from htdocs/image.png");
}

cout << "size: " << fileContents.size() << endl;

cout << "data:" << endl;
for( unsigned i = 0; i != fileContents.size(); ++i )
{
  if( i % 65 == 0 )
    cout << L"\n';

  cout << fileContents[ i ];
}
3 голосов
/ 28 мая 2011

Этот мой ответ на другой вопрос должен быть именно тем, что вы ищете (особенно вторая часть о чтении его в vector<char>, который вы должны предпочесть массиву.

Что касается вашего вывода:

  • sizeof(fileContents) возвращает размер char *, который в вашей системе равен 8 (я думаю, 64-битный)
  • strlen останавливается на первом '\0', как и оператор вывода.
2 голосов
/ 28 мая 2011

Что вы ожидаете? Файлы png являются двоичными, поэтому они могут содержать где-то символ '\0' (символ с числовым значением 0).

Если вы обрабатываете содержимое png-файла как строку ('\0' terminated array of characters) и печатаете его как строку, то он остановится после того, как встретит первый символ '\0'.

Так что в коде нет ничего плохого, fileContents правильно содержит файл png (размером 1944 байта)

size: 1944 // the png is 1944 bytes
sizeof: 8  // sizeof(fileContents) is the sizeof a pointer (fileContents type is char*) which is 8 bytes
length: 8  // the 9th character in the png file is '\0' (numeric 0)
random: ?  // the 56th character in the png file
?PNG       // the 5th-8th character is not printable, the 9th character is '\0' so cout stop here
0 голосов
/ 28 мая 2011

Рекомендуется использовать unsigned char для использования с двоичными данными. Случайно выбранный символ может не отображаться должным образом в окне консоли из-за ограничений в поддерживаемых шрифтах. Также вы можете проверить то же самое, напечатав его в шестнадцатеричном формате и открыть тот же файл в шестнадцатеричном редакторе, чтобы проверить это. Пожалуйста, не забудьте удалить память, выделенную после использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...