#c #file #bin
#c #файл #bin
Вопрос:
Я хочу прочитать bin-файл размером менее 2 МБ.
На данный момент мой код для чтения bin-файла выглядит следующим образом:
Редактировать:
#define MAX_BYTES_IN_FILE 500000 // ~ 2mb
#define ERROR_FILE 1
int get_byte_from_file(FILE *stream, unsigned char *dataarray) {
int counter = 0;
while ((dataarray[counter] = fgetc(stream)) != EOF) {
counter = 1;
}
return counter;
}
Main выглядит так для примера использования функции.
int main(int argc, char **argv) {
FILE *datei;
unsigned int number_of_bytes;
unsigned char *dataarray;
dataarray = (unsigned char *)malloc(sizeof(unsigned char) * MAX_BYTES_IN_FILE);
datei = fopen(argv[1], "rb");
number_of_bytes = get_byte_from_file(datei, dataarray);
for (int i = 0; i < number_of_bytes; i )
printf("%x ", dataarray[i]);
return 0;
}
Возможно, я допустил простую ошибку, но не могу ее увидеть, ошибка все еще: Segmentation fault (core dumped)
Комментарии:
1. Этот массив может быть слишком большим для размещения в стеке. Не уверен, для чего вам это вообще нужно
2. Хммм. Этот массив совершенно бесполезен. Вы используете его только для чтения одного символа и немедленного присвоения его
dataarray[counter]
. Почему бы вместо этого не заменить его однимchar
? Или используйтеdataarray
в качестве буфера для чтения данных (не по 1 байту за раз, а большими порциями) непосредственно в этот буфер3. В Microsoft Windows размер стека по умолчанию равен 1 МБ. В Linux размер стека по умолчанию составляет (я полагаю) 8 МБ. Однако эти значения могут быть настроены. Таким образом, ваша программа, скорее всего, сбой из-за переполнения стека , потому что локальные переменные / массивы хранятся в стеке. По этой причине я предлагаю вам вместо этого использовать динамическое выделение памяти, например, функцию
malloc
.4. Может быть еще одна причина ошибки сегментирования. Откуда вы знаете, насколько велик буфер, на который
dataarray
указывает точка? Помимо сбоя вашего стека, вы также можете записывать за пределы при копировании символа в этот буфер.5. Ваш измененный код также неверен:
fgetc
возвращаетint
, а неunsigned char
. Какunsigned char
вообще можно было бы сохранитьEOF
?
Ответ №1:
Этой строки достаточно для сбоя вашей программы:
while ((dataarray[counter] = fgetc(stream)) != EOF) {
Давайте пройдемся по нему шаг за шагом:
-
fgetc(stream)
считывает байт и возвращает его значение илиEOF
. Поскольку байт может иметь любое возможное значение,fgetc()
возвращает большееint
значение, которое может содержатьEOF
значение, отличное от любого значения байта, которое может быть найдено в файле. -
Вы присваиваете это
int
значениеunsigned char
.EOF
Значение будет урезано до этого типа данных. -
Значение присваивания имеет тип
unsigned char
, и преобразованноеEOF
значение больше не равноEOF
. Таким образом, сравнение всегда завершается неудачей, и ваша программа продолжает извлекать данные до тех пор, пока буфер не переполнится и не начнут происходить неприятные вещи.
Вам нужно сохранить результат fgetc()
в int
переменной, пока вы не убедитесь, что это действительно не EOF
значение.
Ответ №2:
Может быть, что-то вроде этого.
void *readfile(FILE *fi, long *filesize)
{
void *buff;
fseek(fi, 0, SEEK_END);
*filesize = ftell(fi);
fseek(fi, 0, SEEK_SET);
buff = malloc(*filesize);
if(buff)
{
fread(buff, 1, *filesize, fi);
}
return buff;
}
Вам нужно добавить проверки на ошибки — я этого не делал, поскольку это только идея.
И ваше использование:
int main(int argc, char **argv) {
FILE *datei;
long number_of_bytes;
unsigned char *dataarray;
datei=fopen(argv[1],"rb");
dataarray = readfile(datei, amp;number_of_bytes);
for (int i=0;dataarray amp;amp; i<number_of_bytes;i )
printf("%hhx ",dataarray[i]);
return 0;
}
Комментарии:
1. Это бесполезно, когда вы представляете только рабочий код в качестве ответа и никогда не объясняете, что OP сделал неправильно. Таким образом, они не могут учиться, они только становятся вуду-кодерами, которые зависят от StackOverflow для исправления своих кодов.
2. @cmaster-переустановите monica Не только это, код не обязательно будет работать. Он абсолютно не проверяет ошибки, и использование
fseek()
/ftell()
для определения размера файла в потоке может привести к сбою многими способами — чтение из каналаfseek()
до конца двоичного потока в некоторых системах не работает, в Windows, гдеlong
всего 32 бита, если произойдет сбой для файлов размером 2 ГБ или больше, и т.д.3.
long
возможно, недостаточно большой, чтобы вместить размер файла.4. @AndrewHenle OP читает файл ~ 2 МБ. Достаточно долго. Для целей операций fseek / ftell достаточно
5. @P__J__ Для целей операций fseek / ftell достаточно хорош До тех пор, пока этого не произойдет. Ошибочный код — это ошибочный код, даже если ошибка не вызвана.
Ответ №3:
Причина, по которой вы получаете ошибку сегментации, заключается в неправильном распределении: вы выделяете MAX_BYTES_IN_FILE
байты вместо unsigned int
элементов. При распределении массив содержит только MAX_BYTES_IN_FILE / sizeof(unsigned int)
элементы, тогда как файл, вероятно, имеет длину MAX_BYTES_IN_FILE * sizeof(unsigned int)
байт.
Вы считываете байты из файла (значения между 0
и 255
), но используете unsigned int
элементы. В чем логика? Содержит ли файл 32-разрядные значения или отдельные байты?
Как только вы сможете подтвердить, что содержимое файла точно совпадает с представлением массива в памяти, вы можете использовать fread()
для чтения всего файла за один вызов.