Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Чтение данных из бинарного файла в массив, проблема с интерпретацией данных 
:(
    Опции темы
Steuermann
Дата 7.11.2010, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 16.8.2008

Репутация: нет
Всего: нет



Здравствуйте! 

Помогите, пожалуйста, с задачей.
 
Есть бинарный файл. Нужно прочитать из него данные в массив. Проблема в том, что файл может интерпретироваться как последовательность 8, 16 или 32-битных целых чисел. Числа какого типа содержатся в файле заранее не известно. Если бы там были только 8-битные числа, то я бы сделал так:

Код

char *data = malloc(num_of_elements);

fread(data, size_of_element, num_of_elements, fp);


Подскажите, пожалуйста, как написать с учетом того, что числа могут быть 8, 16 или 32-битные.
PM MAIL   Вверх
586
Дата 7.11.2010, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2243
Регистрация: 8.5.2006

Репутация: 8
Всего: 146



Код
short *data = malloc(num_of_elements*sizeof(short));
fread(data, sizeof(short), num_of_elements, fp);

для int аналогично.
PM   Вверх
leniviy
Дата 7.11.2010, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: нет
Всего: 5



Что вам мешает получить size_of_element как параметр?
PM MAIL   Вверх
Steuermann
Дата 7.11.2010, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 16.8.2008

Репутация: нет
Всего: нет



Цитата(586 @ 7.11.2010,  16:09)
Код
short *data = malloc(num_of_elements*sizeof(short));
fread(data, sizeof(short), num_of_elements, fp);

для int аналогично.

А потом выбирать один из случаев в зависимости от size_of_element?

P.S. Забыл сказать, что size_of_element известен после запуска программы (например, вводится с клавиатуры).
PM MAIL   Вверх
leniviy
Дата 7.11.2010, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: нет
Всего: 5



Что потом с этим массивом делаете? 
PM MAIL   Вверх
Steuermann
Дата 7.11.2010, 21:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 16.8.2008

Репутация: нет
Всего: нет



Цитата(leniviy @ 7.11.2010,  16:38)
Что потом с этим массивом делаете?

Для начала хотя бы на экран его вывести.
PM MAIL   Вверх
leniviy
Дата 7.11.2010, 22:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: нет
Всего: 5



а вы темплейты проходили? Может это на них задачка?
Код

#include <stdio.h>
#include <malloc.h>

// выводит массив на экран
template<typename _t> 
void printarray(_t *a, int num_of_elements) {
  for(int i = 0; i<num_of_elements; i++) {
    printf("%d ", (int)a[i]); // если вместо printf cout << , то кастовать в int не нужно
  }
  printf("\n");
}

int main() {
  int num_of_elements = 10;
  int size_of_element = 2; // short (не 16)
  FILE* fp = NULL;

  // на этом этапе тип не важен, поэтому void
  void *data = malloc(size_of_element * num_of_elements);

  // я заменил fread на цикл
  //fread(data, size_of_element, num_of_elements, fp);
  for (int i = 0; i < size_of_element * num_of_elements; i++) {
    ((char*)data)[i] = i;
  }
  
  switch(size_of_element) {
  case 1:
    printarray((char*)data, num_of_elements); // кастуем в char*, чтобы вызвать printarray для типа char*
    break;
  case 2:
    printarray((short*)data, num_of_elements);
    break;
  case 4:
    printarray((int*)data, num_of_elements);
    break;
  }

  return 0;
}



Это сообщение отредактировал(а) leniviy - 7.11.2010, 22:19
PM MAIL   Вверх
Steuermann
Дата 8.11.2010, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 16.8.2008

Репутация: нет
Всего: нет



leniviy
Спасибо за ответ. Но мне хотелось бы найти более изящное решение.

Я тут подумал, нельзя ли всегда выделять память под int (ведь максимальный размер чисел, которые могут быть в файле - 32 бита):

Код

int *data = malloc(num_of_elements*sizeof(int));


а потом читать из файла в эту память:

Код

fread(data, size_of_element, num_of_elements, fp);


Только, наверное, придется делать какие-то преобразования типов. Или так не получится?
PM MAIL   Вверх
mes
Дата 8.11.2010, 00:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



читайте в байтовый массив, а потом кастуете  в массив нужных значений. : int* int_data = (int*)byte_data;

Цитата(Steuermann @  7.11.2010,  23:09 Найти цитируемый пост)
Я тут подумал, нельзя ли всегда выделять память под int (ведь максимальный размер чисел, которые могут быть в файле - 32 бита):

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

Цитата(leniviy @  7.11.2010,  21:15 Найти цитируемый пост)
а вы темплейты проходили? Может это на них задачка?

судя по фрагментам кода задача на чистом С, а там нет темплейтов..


Это сообщение отредактировал(а) mes - 8.11.2010, 00:33


--------------------
PM MAIL WWW   Вверх
Steuermann
Дата 8.11.2010, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 16.8.2008

Репутация: нет
Всего: нет



mes

Вот так?

Код

char* byte_data = malloc(num_of_elements);

fread(byte_data, sizeof(char), num_of_elements, fp);

int* int_data = (int*)byte_data;



Цитата(mes @  8.11.2010,  00:29 Найти цитируемый пост)
можно, а можно выделять нужное кол-во после того как введут значение размера типа..


Не могли бы Вы рассказать поподробнее, как это сделать?

Цитата(mes @  8.11.2010,  00:29 Найти цитируемый пост)
судя по фрагментам кода задача на чистом С, а там нет темплейтов..


Да, хорошо бы без темплейтов.
PM MAIL   Вверх
xvr
Дата 8.11.2010, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(Steuermann @  8.11.2010,  00:09 Найти цитируемый пост)
Я тут подумал, нельзя ли всегда выделять память под int (ведь максимальный размер чисел, которые могут быть в файле - 32 бита):
Можно
Цитата(Steuermann @  8.11.2010,  00:09 Найти цитируемый пост)
а потом читать из файла в эту память:
Тоже можно, но осторожно  smile 

Цитата(Steuermann @  8.11.2010,  00:09 Найти цитируемый пост)
Только, наверное, придется делать какие-то преобразования типов. Или так не получится? 
Не получится. Читать придется поэлементно и складывать в массив -

Код

int i;
int *data = malloc(num_of_elements*sizeof(int));
memset(data,0,num_of_elements*sizeof(int));
for(i=0;i<num_of_elements;++i)
 fread(&data[i],size_of_element, 1, fp);

PM MAIL   Вверх
Steuermann
Дата 8.11.2010, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 16.8.2008

Репутация: нет
Всего: нет



xvr
Спасибо Вам большое за совет! 

Но теперь есть еще одна проблема. Если в двоичный файл записать, например, число FFFB, то после чтения 2-х байт на экран выводится: 65531 вместо ожидаемого числа -5. Как я понимаю, это связано с тем, что int 32-х битный. Если выделять память под short, то все хорошо, выводится -5.

Вывожу на экран так:

Код

for (i = 0; i < num_of_elements; i++){
   printf("%d\n", data[i]);
}


Подскажите, пожалуйста, как правильно сделать вывод.
PM MAIL   Вверх
baldina
Дата 8.11.2010, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Код

printf("%hd\n", (short)data[i]);

PM MAIL   Вверх
xvr
Дата 8.11.2010, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(Steuermann @  8.11.2010,  17:57 Найти цитируемый пост)
Если в двоичный файл записать, например, число FFFB, то после чтения 2-х байт на экран выводится: 65531 вместо ожидаемого числа -5. 
Мой код предназначался для чтения беззнаковых величин. Если нужны знаковые, то нужно делать расширение знака, как то так:

Код

int i;
int *data = malloc(num_of_elements*sizeof(int));
memset(data,0,num_of_elements*sizeof(int));
for(i=0;i<num_of_elements;++i)
 {
   int j=0;
   fread(&j,size_of_element, 1, fp);
   j<<=32-8*size_of_element;
   j>>=32-8*size_of_element;
   data[i]=j;
 }


PM MAIL   Вверх
Dov
Дата 9.11.2010, 00:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


аСинизатор
***


Профиль
Группа: Завсегдатай
Сообщений: 1721
Регистрация: 10.5.2003
Где: Эрец-Исраэль

Репутация: 11
Всего: 88



Как-то так:
Код

union UN
{
    int   in;
    short sh;
    char  ch[4];
};

UN readBin(int size, FILE * f)
{
    UN  un;

    for(int i = 0; i < size; i++)
        un.ch[i] = getc(f);

    return un;    
}

int main()
{
    FILE * file;
    UN     un;
    int    size_of_elem;
    long   num = 0xFFFB;

    file = fopen("file_name.bin", "wb+");
    fwrite(&num, 4, 1, file);
    fclose(file);
    
    file = fopen("file_name.bin", "rb");
    printf("Enter size of element: ");
    scanf("%d", &size_of_elem);

    un = readBin(size_of_elem, file);
    
    printf("%d", size_of_elem == 2 ? un.sh : size_of_elem == 4 ? un.in : 0);
    puts("");
    fclose(file);

    return 0;
}



--------------------
Тут вечности запах томительный,
И свежие фрукты дешевые, 
А климат у нас – изумительный, 
И только соседи – #уевые. 
                           Игорь Губерман.
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0688 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.