Как уменьшить размер файла fstream в c++

Как лучше всего обрезать конец файла fstream в C++ 11

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

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

Когда пользователь закроет этот файл, он останется и будет перезагружен, когда он снова откроет проект.

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

Переписать его, когда пользователь сохраняет, может быть вариантом, но это все еще не так привлекательно.

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

Есть ли простой вызов для этого в fstream API?

Я использую неправильную библиотеку? Обратите внимание: я хочу придерживаться чего-то общего STL, которое я предпочитаю, поэтому я могу сохранить код как можно более кроссплатформенным.

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

Спасибо за вашу помощь Андре

2
0
1 469
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

// Somewhere in the begining of your code:
std::ofstream *file = new std::ofstream();
file->open("/home/user/my-audio/my-file.dat");
// ...... long story of writing data .......

// Lets say, we are on a one millin byte now (in the file)
int current_file_pos = 1000000;
// Your last chunk size:
int last_chunk_size = 12345;
// Your chunk, that you are saving
char *last_chunk = get_audio_chunk_to_save();
// Writing chunk
file->write(last_chunk, last_chunk_size);
// Moving pointer:
current_file_pos += last_chunk_size;
// Lets undo it now!
current_file_pos -= last_chunk_size;
file->seekp(current_file_pos);
// Now you can write new chunks from the place, where you were before writing and unding the last one!
// .....
// When you want to finally write file to disk, you just close it
file->close();
// And when, truncate it to the size of current_file_pos
truncate("/home/user/my-audio/my-file.dat", current_file_pos);

К сожалению, вам придется написать кроссплатформенную функцию обрезать, которая будет вызывать SetEndOfFile в Windows и обрезать в Linux. Это достаточно просто с использованием макросов препроцессора.

Да, учитывая, что мне все еще 11 лет, я решил, что мне придется это сделать. В большинстве случаев это не будет проблемой.

Andre .M 26.10.2018 22:51
Ответ принят как подходящий

Is there a simple call for this in the fstream API?

Если у вас есть компилятор C++ 17, используйте std::filesystem::resize_file. В прежних стандартах в стандартной библиотеке такого не было.

Со старыми компиляторами ... в Windows вы можете использовать SetFilePointer или SetFilePointerEx, чтобы установить текущую позицию на желаемый размер, а затем вызвать SetEndOfFile. В Unix вы можете использовать truncate или ftruncate. Если вам нужен переносимый код, вы можете использовать Boost.Filesystem. С этого проще всего перейти на std::filesystem в будущем, потому что std::filesystem в основном определялся на его основе.

Спасибо! К сожалению, мне все еще 11 лет, но теперь у меня есть стимул перейти на 17, и я благодарен за стандартную вежливость 17 за то, что дал мне то, что мне нужно.

Andre .M 26.10.2018 22:49

Другие вопросы по теме