Изменить файл (без режимов fseek или +) или объединить два файла с минимальным копированием - PullRequest
1 голос
/ 30 ноября 2011

Я записываю аудиофайл на карту памяти SD / MMC в режиме реального времени, в формате WAVE , работая на плате ARM.Упомянутая карта (и должна оставаться) в формате FAT32.Я могу написать правильный файл WAVE просто отлично, при условии, что я знаю, сколько я собираюсь написать заранее .

Я хочу иметь возможность помещать данные заполнителя в блокВ поле «Размер данных» RIFF и блоков данных запишите мои аудиоданные, а затем вернитесь и обновите поле «Размер данных блока» в этих двух фрагментах, чтобы они имели правильные значения, но ...

У меня есть рабочая файловая система и некоторые функции stdio, с некоторыми оговорками:

  • fwrite () поддерживает r, w и a, но не любые режимы +.
  • fseek () не работает в режиме записи.

Я не писал реализации вышеуказанных функций (я использую RL-FLashFS от ARM), и я не уверен, чтоОбоснование ограничений / частичной реализации есть.Добавление недостающей функциональности лично, вероятно, является вариантом, но я хотел бы избежать его, если это возможно (мне больше не нужны эти функции, я не предвижу их и не могу позволить себе тратить на это слишком много времени).Переключение на другую реализацию также здесь не вариант.

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

I может записать файл с необработанными чередованными аудиоданными в нем, отслеживая, сколько байтов я записываю, закройте его, затем снова откройте его длячтение, откройте второй файл для записи, запишите заголовок во второй файл и скопируйте аудиоданные.То есть, я мог бы постобработать его в правильно отформатированный допустимый файл WAVE.Я сделал это, и он отлично работает. Но Я хочу избежать пост-обработки больших объемов данных, если это вообще возможно.

Возможно, я мог бы каким-то образом объединить два файла на месте?(Т.е. запишите данные, затем запишите чанки в отдельный файл, затем соедините их в файловой системе, избегая значительной части времени, затрачиваемого на копирование потенциально огромных объемов данных.) Я понимаю, что, если возможно, это все равно будет включатьнекоторое копирование из-за блочной ориентации хранилища.

Предложения?

РЕДАКТИРОВАТЬ: Я действительно должен был упомянуть об этом, но здесь не работает ОС.У меня есть некоторые функции stdio, работающие поверх уровня аппаратной абстракции, и это все.

Ответы [ 2 ]

3 голосов
/ 30 ноября 2011

Это должно быть возможно, но это включает в себя написание набора процедур манипулирования таблицами FAT.

Концепция FAT проста: файл хранится в цепочке «кластеров» - блоков фиксированного размера. Кластеры не должны быть смежными на диске. Запись каталога для файла включает в себя идентификатор первого кластера. FAT содержит одно значение для каждого кластера, которое является либо идентификатором следующего кластера в цепочке, либо маркером «конец цепи» (EOC).

Таким образом, вы можете объединить файлы вместе, изменив маркер EOC первого файла, чтобы он указывал на головной кластер второго файла.

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

  • Определить размер кластера FAT (S)
  • Определить размер заголовка WAV с точностью до первого байта данных (F)
  • Записать входящие данные во временный файл. Закрывается, когда заканчивается поток.
  • Создать новый файл с нужным именем.
  • Откройте временный файл для чтения и скопируйте заголовок в новый файл, правильно заполняя поля размера (как вы делали ранее).
  • Запись min(S-F, bytes_remaining) в новый файл.
  • Закройте новый файл.
  • Если байтов не осталось, все готово,
  • еще,
    • Считать FAT и каталог в память.
    • Прочитайте каталог, чтобы получить
      • первый кластер временного файла (T1) (со всеми данными),
      • первый кластер wav-файла (W1). (с правильным заголовком)
    • Прочитайте запись FAT для T1, чтобы найти второй временный кластер (T2).
    • Изменить запись FAT для W1 с «EOC» на T2.
    • Изменить запись FAT для T1 с T2 на «EOC».
    • Поменяйте местами записи FileSize для двух файлов в Каталоге.
    • Записать FAT и каталог обратно на диск.
    • Удалить временный файл.

Конечно, к тому времени, когда вы это сделаете, вы, вероятно, уже достаточно хорошо поймете файловую систему для реализации fseek(fp,0,SEEK_SET), что должно дать вам достаточно функциональности для исправления заголовка с помощью стандартных библиотечных вызовов.

1 голос
/ 30 ноября 2011

Мы работаем по тому же сценарию, что и вы, в нашем приложении для записи проектов. Поскольку длина файла неизвестна - мы пишем заголовок RIFF с длиной 0 в начале (для резервирования места) и при закрытии - возвращаемся в позицию 0 (с помощью fseek) и пишем правильный заголовок. Таким образом, я думаю, что вы должны отладить, почему fseek не работает в режиме записи , иначе вы не сможете выполнить эту задачу эффективно.

Кстати, вам лучше воспользоваться внутренними обходными путями в файловой системе, такими как объединение блоков и т. Д. - это вряд ли возможно, не будет переносимым и может принести вам новые проблемы. Давайте вместо этого будем использовать стандартные и проверенные методы.

Обновление

(После выяснения, что ваша FS является RL-FlashFS от ARM), почему бы не использовать rewind http://www.keil.com/support/man/docs/rlarm/rlarm_rewind.htm вместо fseek?

...