Я пытаюсь запустить программу для замены определенных данных в файле. Соответствующие части файла, которые нужно заменить, выглядят следующим образом:
1 Information 15e+10
2 Information 2e+16
3 Information 6e+2
И так далее.
Эти файлы могут быть очень большими в диапазоне нескольких гигабайт и, насколько мне известно, из-за этого с использованием буфера всего файла и перезаписи всего файла невозможно/необоснованно. Ну, все в порядке, я просто хочу заменить значения (например, 15e+10
).
Все это прекрасно работает с простыми ios::in|ios::out
и tellp()
если я tellp()
значение с аналогичным размером (15e+10
→ 12e+12
) или даже если его размер меньше, чем я могу просто добавьте дополнительное пространство, которое можно игнорировать по строке (например, 15e+10
→ 4e+10
). Но я столкнулся с проблемой, если мне нужно заменить значение значением, длина которого больше, чем уже в файле (например, 6e+2
→ 16e+10
), он будет писать поверх нового символа строки или начать писать поверх информацию в следующей строке.
Я искал на форумах, и все говорят, что вы можете либо перезаписать в файле, либо добавить в конец файла, либо вы можете буферизовать и воссоздать весь файл. В любом случае, я могу достичь своей цели правильно записать значение, не создавая файл?
Если нет, то как я могу открыть 2 файла (1 вход 1 вывод), если несколько файлов, о которых идет речь, слишком велики для памяти?
Примечание. Я также хотел бы избежать использования boost::
поскольку мне нужно иметь возможность запускать это в системе без библиотеки boost.
Откройте поток для чтения из входного (IN) файла и второго потока (OUT) для записи в новый файл вывода (tmp).
Чтение из IN и запись в OUT. Когда вы получите значение от IN, которое вы хотите заменить, замените OUT на значение вместо значения, которое вы получили от IN.
Когда синтаксический анализ завершен, замените первый файл вторым (tmp) файлом.
Будет ли это работать для вас?
Вы можете использовать seekp
для перехода к местоположению и переписать его с помощью <<
Пример:
example.txt (|? | = 1 байт данных)
| A | B | C |\п | 1 | 2 | 3 | D | E | F |\п | 4 | 5 | 6 |
//Somewhere in the code
fstream file;
open("example.txt");
//Somehow find the character distance and store it into "distance"
seekp(distance);//If distance = 0, it will go to "A" like rewind() but easier for me
Если расстояние равно 4, следующий символ будет перезаписан: 1
file << "987";
И файл будет
| | B | C |\п | 9 | 8 | 7 | D | E | F |\n | 4 | 5 | 6 |
НО только проблема здесь, когда вам нужно увеличить/уменьшить размер:
Увеличение:
Вы перезапишете другого персонажа, чтобы создать временную строку для хранения остальной части данных или разделить ее на меньший фрагмент, если данные слишком велики, как
| | B | C |\п | 9 | 8 | 7 | D | E | F |\n | 4 | 5 | 6 |
string tempstring;
seekp(distance);
file >> tempstring;
seekp(distance);
file << content << tempstring; //content is the data
Уменьшение:
Самое простое решение - записать NULL-символ \0
в избыточное пространство, например
| | B | C |\п | 1 | \ 0 | \ 0 | D | E | F |\n | 4 | 5 | 6 |
Единственный побочный эффект - размер файла такой же, как и раньше
Используйте lseek()/fseek() для "перехода" в заданную позицию в файле.