вставка std::string в произвольное местоположение в std::fstream

#c #file-io #stl #fstream

#c #file-io #stl #fstream

Вопрос:

У меня есть приложение Visual Studio 2008 C , в котором я хотел бы вставить строку в произвольную точку в файле, используя std::fstream . Размер файла может достигать 100 МБ, поэтому я не хочу полностью считывать его в память, изменять его и перезаписывать новый файл.

 /// Insert some data in to a file at a given offset
/// @param file stream to insert the data
/// @param data string to insert
/// @param offset location within the file to insert the data
void InsertString( std::fstreamamp; file, const std::stringamp; data, size_t offset );
  

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

Каков наиболее эффективный способ достижения этой цели?

Ответ №1:

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

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

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

Ответ №2:

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

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

Комментарии:

1. Если вы выполняете много вставок, вам следует создать временную структуру данных, которая буферизует все вставки. Таким образом, вы сдвигаете и выполняете запись только один раз.

Ответ №3:

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