Запись в середину файла (не перезаписывая данные)

В окнах возможно через API писать в середину файла, не перезаписывая данных и не имея необходимость переписывать все после этого?

Если это возможно тогда, что я полагаю, что это, очевидно, фрагментирует файл; сколько раз я могу сделать это, прежде чем это станет серьезной проблемой?

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


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

9
задан Thomas Bonini 7 March 2010 в 21:53
поделиться

6 ответов

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

Но курсив здесь выделен по уважительной причине. Если вы можете контролировать формат файла, у вас есть некоторые возможности. Некоторые версии MS Word имели функцию быстрого сохранения, при которой они не переписывали весь документ, а добавляли дельта-запись в конец файла. Затем, при повторном чтении файла, он применял все дельты по порядку, так что в итоге получался правильный файл. Это, очевидно, не сработает, если сохраненный файл должен быть немедленно использован другим приложением, которое не понимает формат файла.

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

Помимо этого, есть и другие возможности.

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

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

8
ответ дан 4 December 2019 в 14:28
поделиться

Я заметил как ответ paxdiablo о работе с другими приложениями, так и комментарий Matteo Italia об устанавливаемых файловых системах. Это заставило меня понять, что есть еще одно нетривиальное решение.

Используя точки повторной обработки, вы можете создать «виртуальный» файл из базового файла и дельт. Любое приложение, не знающее об этом методе, увидит непрерывный диапазон байтов, поскольку дельты применяются на лету фильтром файловой системы. Для небольших дельт (всего <16 КБ) дельта-информация может храниться в самой точке повторной обработки; большие дельты могут быть помещены в альтернативный поток данных. Нетривиально конечно.

0
ответ дан 4 December 2019 в 14:28
поделиться

Вероятно, самый эффективный способ сделать это (если вы действительно хотите это сделать) - вызвать ReadFileScatter() для чтения фрагментов до и после точки вставки, вставить новые данные в середину списка FILE_SEGMENT_ELEMENT[3] и вызвать WriteFileGather(). Да, это связано с перемещением байтов на диске. Но вы оставляете сложные части на усмотрение ОС.

0
ответ дан 4 December 2019 в 14:28
поделиться

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

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

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

4
ответ дан 4 December 2019 в 14:28
поделиться

Я не уверен в формате вашего файла, но вы можете сделать его основанным на "записи".

  • Записывайте данные кусками и присваивайте каждому куску идентификатор.
  • Id может быть смещением данных в файле.
  • В начале файла вы можете иметь заголовок со списком идентификаторов, чтобы чтобы вы могли читать записи по порядке.
  • В конце "списка идентификаторов" можно указать на другое место в файле (и id/offset), где хранится другой список идентификаторов

Что-то похожее на файловую систему.

Чтобы добавить новые данные, вы добавляете их в конец и обновляете индекс (добавляете id в список).

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

Если записи имеют одинаковый размер, то для удаления можно просто пометить ее пустой и в следующий раз использовать ее повторно с соответствующим обновлением индексной таблицы.

2
ответ дан 4 December 2019 в 14:28
поделиться

Если вы используете .NET 4, попробуйте использовать файл с привязкой к памяти, если у вас есть приложение, похожее на редактор - это может быть то, что нужно. Что-то вроде этого (я не вводил это в VS, поэтому не уверен, правильно ли я понял синтаксис):

MemoryMappedFile bigFile = MemoryMappedFile.CreateFromFile(
   new FileStream(@"C:\bigfile.dat", FileMode.Create),
       "BigFileMemMapped",
       1024 * 1024,
       MemoryMappedFileAccess.ReadWrite);
MemoryMappedViewAccessor view = MemoryMapped.CreateViewAccessor();
int offset = 1000000000;
view.Write<ObjectType>(offset, ref MyObject);
0
ответ дан 4 December 2019 в 14:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: