Перейти к определенной точке двоичного файла в C (используя fseek), а затем читать из этого места (используя fread) - PullRequest
7 голосов
/ 25 марта 2012

Мне интересно, если это лучший способ решить мою проблему.

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

После использования Google я пришел к выводу, что лучше всего использовать fseek () для перемещения в положение смещения, а затем использовать fread () для считывания количества байтов изэта позиция.

Правильно ли я думаю об этом?И если так, как лучше поступить?то есть как объединить их вместе.

Если я не прав, что бы вы посоветовали мне сделать вместо этого?

Заранее большое спасибо за вашу помощь.

Мэтт

Редактировать :

Я следовал руководству по fread () и настроил его следующим образом:

    `#include <stdio.h>
    int main()
    {
      FILE *f;
      char buffer[11];
      if (f = fopen("comm_array2.img", "rt"))
      {
        fread(buffer, 1, 10, f);
        buffer[10] = 0;
        fclose(f);
        printf("first 10 characters of the file:\n%s\n", buffer);
      }
      return 0;
    }`

Поэтому я использовал файл 'comm_array2.img 'и прочитайте первые 10 символов из файла.

Но из того, что я понимаю, это идет от начала файла, я хочу перейти от некоторого места в файле (смещение)

Имеет ли это больше смысла?

Редактировать номер 2:

Похоже, что я немного потемнел, и все, что нужно (кажется из моегопопытка) состоит в том, чтобы поместить fseek () перед fread (), который есть в приведенном выше коде, и он ищет это место, а затем читает оттуда.

Ответы [ 3 ]

2 голосов
/ 25 марта 2012

Если вы используете файловые потоки вместо файловых дескрипторов, то вы можете написать себе (простую) функцию, аналогичную системному вызову POSIX pread().

Вы можете легко эмулировать его, используя потоки вместо файловых дескрипторов 1 . Возможно, вам следует написать себе такую ​​функцию (которая немного отличается от той, которую я предложил в комментарии):

size_t fpread(void *buffer, size_t size, size_t mitems, size_t offset, FILE *fp)
{
     if (fseek(fp, offset, SEEK_SET) != 0)
         return 0;
     return fread(buffer, size, nitems, fp);
}

Это разумный компромисс между соглашениями pread() и fread().


Как будет выглядеть синтаксис вызова функции? Например, чтение со смещения 732, а затем снова со смещения 432 (оба с начала файла) и файлового потока с именем f.

Поскольку вы не сказали, сколько байтов нужно прочитать, я собираюсь брать 100 каждый раз. Я предполагаю, что целевые переменные (буферы) равны buffer1 и buffer2, и что они достаточно большие.

if (fpread(buffer1, 100, 1, 732, f) != 1)
    ...error reading at offset 732...
if (fpread(buffer2, 100, 1, 432, f) != 1)
    ...error reading at offset 432...

Счетчик возврата - это количество полных единиц по 100 байт каждая; либо 1 (получил все), либо 0 (что-то пошло не так).

Есть и другие способы написания этого кода:

if (fpread(buffer1, sizeof(char), 100, 732, f) != 100)
    ...error reading at offset 732...
if (fpread(buffer2, sizeof(char), 100, 432, f) != 100)
    ...error reading at offset 432...

Это читает 100 одиночных байтов каждый раз; тест гарантирует, что вы получили все 100 из них, как и ожидалось. Если вы захватите возвращаемое значение во втором примере, вы сможете узнать, сколько данных вы получили. Было бы очень удивительно, если бы первое чтение прошло успешно, а второе не удалось; какой-то другой программе (или потоку) пришлось бы обрезать файл между двумя вызовами fpread(), но, как известно, более забавные вещи происходили.


1 Эмуляция не будет идеальной; вызов pread() обеспечивает гарантированную атомарность, которую не обеспечит комбинация fseek() и fread(). Но на практике это редко будет проблемой, если только у вас нет нескольких процессов или потоков, одновременно обновляющих файл, когда вы пытаетесь расположить и прочитать его.

1 голос
/ 25 марта 2012

Это часто зависит от расстояния между деталями, которые вас интересуют.Если вы пропускаете / игнорируете несколько байтов между интересующими вас частями, часто проще просто прочитать эти данные и игнорировать прочитанное, чем использовать fseek, чтобы пропустить их.Типичный способ сделать это - определить структуру, содержащую как данные, которые вам нужны, так и заполнители для тех, которые вам не нужны, прочитать в структуре, а затем просто использовать части, которые вам интересны:

struct whatever {
   long a;
   long ignore;
   short b;
} w;

fread(&w, 1, sizeof(w), some_file);

// use 'w.a' and 'w.b' here.

Однако, если есть какое-то большое расстояние между частями, которые вас интересуют, есть вероятность, что ваша первоначальная идея использовать fseek, чтобы добраться до важных частей, будет проще.

0 голосов
/ 25 марта 2012

Ваша теория звучит правильно.Открывать, искать, читать, закрывать.

Создать структуру для данных, которые вы хотите прочитать, и передать указатель на read () выделенной памяти структуры.Скорее всего, вам понадобится #pragma pack (1) или аналогичный в структуре, чтобы предотвратить проблемы смещения.

...