Чтение двоичного файла по 1 байту за раз - PullRequest
18 голосов
/ 23 мая 2011

Я пытаюсь прочитать двоичный файл в C 1 байт за раз, и после поиска в Интернете в течение нескольких часов я все еще не могу заставить его извлечь что-либо, кроме мусора и / или ошибки сегмента.Обычно двоичный файл имеет формат списка длиной 256 элементов, а каждый элемент имеет длину 1 байт (целое число без знака между 0 и 255).Я пытаюсь использовать fseek и fread, чтобы перейти к «индексу» в двоичном файле и получить это значение.Код, который у меня есть на данный момент:

unsigned int buffer;

int index = 3; // any index value

size_t indexOffset = 256 * index;
fseek(file, indexOffset, SEEK_SET);
fread(&buffer, 256, 1, file);

printf("%d\n", buffer);

Прямо сейчас этот код дает мне случайные числа мусора и ошибки сегмента.Любые подсказки относительно того, как я могу заставить это работать правильно?

Ответы [ 5 ]

16 голосов
/ 23 мая 2011

В вашем коде вы пытаетесь прочитать 256 байтов по адресу одного целого. Если вы хотите читать по одному байту за раз, вызовите fread(&buffer, 1, 1, file); (см. fread ).

Но более простым решением будет объявить массив байтов, прочитать его все вместе и обработать после этого.

14 голосов
/ 23 мая 2011

Ваш запутанный байт с int .Общий термин для байта - это unsigned char .Большинство байтов имеют ширину 8 бит.Если данные, которые вы читаете, имеют размер 8 бит, вам нужно будет прочитать 8 бит:

#define BUFFER_SIZE 256

unsigned char buffer[BUFFER_SIZE];

/* Read in 256 8-bit numbers into the buffer */
size_t bytes_read = 0;
bytes_read = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file_ptr);
// Note: sizeof(unsigned char) is for emphasis

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

Вот пример дополнительной информации, необходимой для чтения 1 байта:

Tell OS to read from the file.
OS searches to find the file location.
OS tells disk drive to power up.
OS waits for disk drive to get up to speed.
OS tells disk drive to position to the correct track and sector.
-->OS tells disk to read one byte and put into drive buffer.
OS fetches data from drive buffer.
Disk spins down to a stop.
OS returns 1 byte to your program.

В вашей программе вышеупомянутые шаги будут повторяться 256 раз.По совету всех, строка, помеченная "->", будет читать 256 байтов.Таким образом, накладные расходы выполняются только один раз вместо 256 раз для получения одинакового количества данных.

3 голосов
/ 23 мая 2011
unsigned char buffer; // note: 1 byte
fread(&buffer, 1, 1, file);

Пора читать мужчин, которым я верю.

0 голосов
/ 23 мая 2011

Пара проблем с кодом в его нынешнем виде.

Прототип для fread:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

Вы установили размер 256 (байт) и счетчик 1Это хорошо, это означает, что «прочитайте один кусок из 256 байтов, поместите его в буфер».

Однако ваш буфер имеет длину порядка 2-8 байтов (или, по крайней мере, значительно меньше, чем256 байт), поэтому у вас переполнение буфера.Возможно, вы захотите использовать fred (& buffer, 1, 1, file).

Кроме того, вы записываете байтовые данные в указатель типа int.Это будет работать с одним порядком байтов (фактически, с прямым порядком байтов), так что вы будете в порядке с архитектурой Intel, и из этого выучите вредные привычки, которые вернутся и укусят вас, на днях.

Старайтесь изо всех сил записывать только байтовые данные в байтовое хранилище, а не в целые или плавающие числа.

0 голосов
/ 23 мая 2011

Вы пытаетесь прочитать 256 байтов в 4-байтовую целочисленную переменную, называемую «буфер».Вы перезаписываете следующие 252 байта других данных.

Кажется, что buffer должно быть либо unsigned char buffer[256];, либо вы должны делать fread(&buffer, 1, 1, f), и в этом случае buffer должно быть unsigned char buffer;.

В качестве альтернативы, если вам нужен только один символ, вы можете просто оставить buffer как int ( unsigned не требуется, потому что C99 гарантирует разумный минимальный диапазон для простого int) ипросто скажи:

buffer = fgetc(f);
...