В окнах возможно через API писать в середину файла, не перезаписывая данных и не имея необходимость переписывать все после этого?
Если это возможно тогда, что я полагаю, что это, очевидно, фрагментирует файл; сколько раз я могу сделать это, прежде чем это станет серьезной проблемой?
Если не возможно, какой подход обычно проявляется? Перезапись всего после точки вставки становится препятствующей действительно быстро с большим (т.е., гигабайты) файлы.
Примечание: Я не могу избежать необходимости писать в середину. Думайте о приложении как о текстовом редакторе для огромных файлов, где пользователь вводит материал и затем сохраняет. Я также не могу разделить файлы в нескольких меньших.
Я не знаю никакого способа сделать это если промежуточным результатом, который вам нужен, является плоский файл, который может быть использован другими приложениями, кроме редактора. Если вы хотите получить плоский файл, вам придется обновлять его от точки изменения до конца файла, поскольку на самом деле это просто последовательный файл.
Но курсив здесь выделен по уважительной причине. Если вы можете контролировать формат файла, у вас есть некоторые возможности. Некоторые версии MS Word имели функцию быстрого сохранения, при которой они не переписывали весь документ, а добавляли дельта-запись в конец файла. Затем, при повторном чтении файла, он применял все дельты по порядку, так что в итоге получался правильный файл. Это, очевидно, не сработает, если сохраненный файл должен быть немедленно использован другим приложением, которое не понимает формат файла.
Я предлагаю не хранить файл как текст. Использовать промежуточную форму, которую можно эффективно редактировать и сохранять, а затем сделать шаг, который преобразует ее в пригодный для использования текстовый файл нечасто (например, при выходе из редактора). Таким образом, пользователь сможет сохранять столько, сколько захочет, но затратная по времени операция не будет иметь такого большого влияния".
Помимо этого, есть и другие возможности.
Сопоставление памяти (а не загрузка) файла может обеспечить эффективность, которая ускорит работу. Вероятно, вам все равно придется переписывать файл до конца, но это будет происходить на более низком уровне ОС.
Если основная причина, по которой вам нужно быстрое сохранение, заключается в том, чтобы позволить пользователю продолжать работу (а не в том, чтобы файл был доступен другому приложению), вы можете передать операцию сохранения в отдельный поток и немедленно вернуть управление пользователю. Тогда вам потребуется синхронизация между двумя потоками, чтобы предотвратить изменение пользователем данных, которые еще не были сохранены на диск.
Я заметил как ответ paxdiablo о работе с другими приложениями, так и комментарий Matteo Italia об устанавливаемых файловых системах. Это заставило меня понять, что есть еще одно нетривиальное решение.
Используя точки повторной обработки, вы можете создать «виртуальный» файл из базового файла и дельт. Любое приложение, не знающее об этом методе, увидит непрерывный диапазон байтов, поскольку дельты применяются на лету фильтром файловой системы. Для небольших дельт (всего <16 КБ) дельта-информация может храниться в самой точке повторной обработки; большие дельты могут быть помещены в альтернативный поток данных. Нетривиально конечно.
Вероятно, самый эффективный способ сделать это (если вы действительно хотите это сделать) - вызвать ReadFileScatter()
для чтения фрагментов до и после точки вставки, вставить новые данные в середину списка FILE_SEGMENT_ELEMENT[3]
и вызвать WriteFileGather()
. Да, это связано с перемещением байтов на диске. Но вы оставляете сложные части на усмотрение ОС.
Реальный ответ - нет. Ваш единственный реальный выбор - это переписать с момента модификации или создать более сложный формат, который использует что-то вроде индекса, чтобы указать, как расположить записи в предполагаемом порядке.
С чисто теоретической точки зрения, вы могли бы сделать это как раз при правильных обстоятельствах. Используя FAT (например, но большинство других файловых систем имеют хотя бы некоторую степень сходства), вы можете напрямую управлять FAT. FAT - это в основном связанный список кластеров, составляющих файл. Вы можете изменить этот связанный список, чтобы добавить новый кластер в середину файла, а затем записать новые данные в этот добавленный кластер.
Обратите внимание, что я сказал чисто теоретически. Выполнение такого рода манипуляций в полностью незащищенной системе, такой как MS-DOS, было бы трудным, но граничащим с разумом. В большинстве новых систем вообще довольно сложно внести изменения. Большинство современных файловых систем также (значительно) сложнее, чем FAT, что усложняет реализацию. Теоретически это все еще возможно - на самом деле, сейчас совершенно безумно даже размышлять, где когда-то это было почти разумным.
Я не уверен в формате вашего файла, но вы можете сделать его основанным на "записи".
Что-то похожее на файловую систему.
Чтобы добавить новые данные, вы добавляете их в конец и обновляете индекс (добавляете id в список).
Вам нужно придумать, как обрабатывать удаление записи и обновление.
Если записи имеют одинаковый размер, то для удаления можно просто пометить ее пустой и в следующий раз использовать ее повторно с соответствующим обновлением индексной таблицы.
Если вы используете .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);