2010-08-22 6 views
9

Я создал простой пакет ресурсов для упаковки ресурсов для своей игры в один файл. Все шло хорошо, пока я не начал писать распаковщик. Я заметил, что файл .txt - 26 байт - что я упаковал, вышел из файла ресурсов в порядке, без каких-либо проблем, все данные сохранены. Однако при чтении файла .PNG, который я упаковал в файле ресурсов, первые 5 байтов были неповрежденными, а остальные были полностью аннулированы.fread Только первые 5 байт файла .PNG

Я проследил это до процесса упаковки, и я заметил, что fread только считывает первые 5 байтов файла .PNG, и я не могу на всю жизнь понять, почему. Он даже запускает «EOF», указывающий, что файл имеет длину всего 5 байтов, а на самом деле это 787 байт PNG небольшого полигона, 100 пикселей на 100 пикселей.

Я даже протестировал эту проблему, создав отдельное приложение, чтобы просто прочитать этот файл PNG в буфер, я получаю те же результаты и читаю только 5 байтов.

Вот код этого небольшого отдельного приложения:

#include <cstdio> 

int main(int argc, char** argv) 
{ 
    char buffer[1024] = { 0 }; 
    FILE* f = fopen("test.png", "r"); 
    fread(buffer, 1, sizeof(buffer), f); 
    fclose(f);  //<- I use a breakpoint here to verify the buffer contents 
    return 0; 
} 

Может кто-нибудь, пожалуйста, указать на мою глупую ошибку?

+1

Почему бы не использовать потоки C++? – GManNickG

+0

Почему существует нуль между скобками для «буфера»? –

+0

@Billy: Чтобы аннулировать буфер, я знаю, что это не стандартный способ. –

ответ

21

Может ли кто-нибудь указать мою глупую ошибку?

Платформа для Windows, я думаю?

Используйте это:

FILE* f = fopen("test.png", "rb"); 

вместо этого:

FILE* f = fopen("test.png", "r"); 

См msdn пояснения.

+0

Ничего себе. Огромное спасибо. –

+0

Обратите внимание, что «rb» находится в стандартном и портативном исполнении. Он отражает «rt», который запрашивает «текстовое» обращение с потоком, который является значением по умолчанию. Обработка текста на любом * nix такая же, как двоичная обработка. В Windows и нескольких других более неясных платформах они различаются. Короче говоря, если вы имеете дело с двоичными данными, всегда указывайте «rb» на 'fopen()'. – RBerteig

8

Расширение correct answer from SigTerm, вот некоторые фоны почему вы получили эффект, который вы сделали для открытия файла PNG в текстовом режиме:

Формат PNG объясняет его 8-byte file header следующим образом:

Первые восемь байтов файла PNG всегда содержат следующие значения:

 (decimal)    137 80 78 71 13 10 26 10 
    (hexadecimal)   89 50 4e 47 0d 0a 1a 0a 
    (ASCII C notation) \211 P N G \r \n \032 \n 

Эта подпись обе идентифицирует файл как файл PNG и обеспечивает немедленное обнаружение общих проблем передачи файлов. Первые два байта различают PNG-файлы в системах, которые ожидают, что первые два байта однозначно идентифицируют тип файла. Первый байт выбирается как значение, отличное от ASCII, для уменьшения вероятности того, что текстовый файл может быть неверно распознан как PNG-файл; Кроме того, он ловит неудачные передачи файлов, которые очищают бит 7. Байты с двух до четырех называют формат. CR-LF-последовательность ловит неудачные передачи файлов, которые изменяют последовательности строк новой строки. Символ control-Z останавливает отображение файла под MS-DOS. Финальный фид строки проверяет обратную проблему перевода CR-LF.

Я считаю, что в текстовом режиме вызов fread() был прерван при чтении шестого байта, который содержит символ Ctrl + Z.Ctrl + Z исторически использовался в MSDOS (и в CPM перед ним), чтобы указать конец файла, что было необходимо, потому что файловая система хранила размер файла как количество блоков, а не количество байтов.

При чтении файла в текстовом режиме вместо двоичного режима вы запускали защиту от случайного использования команды TYPE для отображения PNG-файла.

Одна вещь, которую вы могли бы сделать, помогла бы диагностировать эту ошибку - использовать по-разному fread(). Вы не проверили возвращаемое значение с fread(). Вам следует. Кроме того, вы должны назвать это так:

... 
size_t nread; 
... 
nread = fread(buffer, sizeof(buffer), 1, f); 

так что nread является счетчиком байтов, фактически записанных в буфер. Для PNG-файла в текстовом режиме он сказал бы вам в первом чтении, что он читает только 5 байтов. Поскольку файл не может быть таким маленьким, вы бы поняли, что что-то еще происходит. Оставшиеся байты буфера никогда не изменялись fread(), что было бы видно, если вы инициализировали буфер для некоторого другого значения заполнения.

Смежные вопросы