Перезаписать только определенную часть файла

Я знаю, что это был спрос один раз, но Я не понял ответа.

Допустим, у меня есть такой файл:

Guest list:
jon
mary
paul
luke
Table list:

А то, например, я хочу изменить имена гостей. Я понял, что мне нужно искать строку «Список гостей», а затем перезаписывать все между «Список гостей» и «Список столов». Но я понятия не имею, как это сделать.

Я использую C++ и предпочитаю использовать fstream :D

Спасибо !

редактировать:

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


person Lockhead    schedule 30.03.2011    source источник
comment
Можете ли вы дать ссылку на ответ, который вы не поняли? Кроме того, вы можете загрузить весь файл в память или он такой большой?   -  person Björn Pollex    schedule 30.03.2011
comment
Я бы не стал пытаться обновлять части файла - просто прочитайте все и снова запишите все. Обновление частей текстового файла слишком подвержено ошибкам и утомительно.   -  person trojanfoe    schedule 30.03.2011
comment
@Space Это вопрос: stackoverflow.com/questions/2530274/ Я понял, что делать в целом, но понятия не имею, как переходить на разные строки. И да, я могу загрузить весь файл в память. @trojanfoe Вы имеете в виду полную перезапись файла?   -  person Lockhead    schedule 30.03.2011


Ответы (3)


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

  • Прочитайте исходный файл построчно, пока не найдете разделитель «Список гостей:», скопировав каждую строку во временный файл.
  • Запишите новый список гостей во временный файл.
  • Читайте строки из исходного файла, пока не найдете разделитель «Список таблиц:».
  • Прочитайте исходный файл построчно до конца, копируя каждую строку во временный файл.
  • Удалите исходный файл. (Или переименуйте его, добавив к его имени резервное расширение.)
  • Переименуйте временный файл в имя исходного файла.
person Diomidis Spinellis    schedule 30.03.2011
comment
Я попробую сделать что-то подобное. Тем не менее, я хочу быть уверен, что делаю это правильно, потому что у меня почти нет опыта работы с файлами на C++. Если бы вы могли написать фрагмент кода, выполняющий шаги, которые вы упомянули, я был бы очень признателен. Спасибо! - person Lockhead; 30.03.2011

Если вы можете разместить весь файл в памяти (как указал Space), прочитайте его, используя ifstream, и, используя ofstream, запишите строку «Список гостей» и все новые имена. Это не единственный способ, но самый удобный.

person jonsca    schedule 30.03.2011

Итак, вот некоторый код (такие проблемы не так просты, как кажутся на первый взгляд):

#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <iterator>
#include <algorithm>

int main()
{
    std::list<std::string> data;

    // load data from file line-by-line
    { // you can make this a function if you want
        std::ifstream file("test.txt");
        std::string buffer;
        while(std::getline(file, buffer))
            data.push_back(buffer);
    } // end of scope - file gets closed for us

    // find end of guest-list - this is where new guests are added
    std::list<std::string>::iterator guest_list_end = 
        std::find(data.begin(), data.end(), "Table list:");

    data.remove("mary"); // remove mary from guest-list
    data.insert(guest_list_end, "betty"); // append betty to guest-list
    data.insert(guest_list_end, "harry"); // append harry to guest-list

    // write entire file back
    std::ofstream file("test.txt");
    std::copy(data.begin(), data.end(), 
        std::ostream_iterator<std::string>(file, "\n"));
}

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

Этот код также предполагает, что за гостем следует список таблиц. Если это изменится, вам придется изменить оператор find.

person Björn Pollex    schedule 30.03.2011
comment
Спасибо! Я хочу спросить только об одном: что, если вы понятия не имеете, какие данные находятся между списком гостей и списком таблиц, а список гостей не находится в начале файла? - person Lockhead; 30.03.2011