Удаление и замена определенной строки в файле .txt

#c #file-handling

#c #обработка файлов

Вопрос:

Я борюсь с моим проектом на C , связанным с обработкой файлов, и мне нужна одна помощь.

Вот мой movies.txt файл

 SNO, Name, NoOfPeopleLiked
1, The Shawshank Redemption, 77 
2, The Godfather, 20        
3, Into The Wild, 35
4, The Dark Knight, 55      
5, 12 Angry Men, 44     
6, Schindler's List, 33
7, The Lord of the Rings: The Return of the King, 25
8, Pulp Fiction, 23
9, The Good, the Bad and the Ugly, 32   
10, The Lord of the Rings: The Fellowship of the Ring, 56
 

Я хочу удалить конкретную строку, просто введя название фильма в этой строке. Например, когда я ввожу название фильма «12 разгневанных мужчин«. Вся строка № 5 должна быть удалена и заменена обновленной строкой , имеющей увеличенные NoOfPeopleLiked значения от 5, 12 Angry Men, 44 до 5, 12 Angry Men, 45 .
Как я могу удалить эту конкретную строку и обновлять понравившееся значение всякий раз, когда я ввожу название фильма?


Но когда я ввожу название фильма, все строки удаляются до строки № 6, и выходной файл выглядит следующим образом.


     , Schindler's List, 33
7, The Lord of the Rings: The Return of the King, 25
8, Pulp Fiction, 23
9, The Good, the Bad and the Ugly, 32   
10, The Lord of the Rings: The Fellowship of the Ring, 56
 

Пожалуйста, помогите мне решить эту проблему?
Вот мой код:

 void search()
{
    ifstream file;
    file.open("movies.txt");
    cout << "Enter the name of Movie : " << ' ';
    getline(cin, search_movie);
    if (file.is_open())
    {
        while (getline(file, line, ','))
        {
            if ((line.find(search_movie, 0)) != string::npos)
            {
                file >> liked;
                file >> serial;
                cout << serial << " The movie '" << search_movie << "' has been found in database and " << liked << " people like this movie" << endl;
                cout << "Do you like it as well (y/n)" << ' ';
                char z;
                cin >> z;
                if (z == 'y' || z == 'Y')
                {
                    update(search_movie, file);
                }
            }
        }
    }
    else
    {
        cout << "your file could not be opened" << endl;
    }
    file.close();
}
 

     void update(string search_movie, ifstreamamp; file1)
    {
        ofstream temp;
        string linee;
        temp.open("temp.txt", ios::out);
        while (getline(file1, linee))
        {
            cout << linee << endl;
            if (line.substr(0, search_movie.size()) != search_movie)
            {
                temp << linee << endl;
            }
        }
        file1.close();
        temp.close();
        remove("movies.txt");
        rename("temp.txt", "movies.txt");
    }
};
 

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

1. Простая стратегия для такого рода задач. 1) Считайте весь файл в вектор или массив. 2) Внесите необходимые изменения в вектор (или массив) 3) Запишите весь вектор (или массив) обратно в файл. То, как вы пытаетесь это сделать, не может работать.

2. Вам нужно скопировать все содержимое первого файла, удалить одну строку, а затем вывести остальное в тот же файл

3. В вашем коде есть еще одна проблема, которую вы еще не заметили. Там, где вы читаете имя, вы читаете с остановкой на запятой. Поэтому, когда вы пытаетесь прочитать (для одного примера): «9, хорошее, плохое и уродливое, 32 «, в качестве заголовка будет указано только «Хорошее». Оттуда похоже, что он попытается обработать the Bad and the ugly, 32 как количество лайков, что, вероятно, будет работать не очень хорошо.

4. @john 1) чтение всего файла в вектор потенциально не очень хорошая идея, поскольку файл может быть огромным. Конечно, для этого потребуется проверить размер и прочитать его по частям. 2) Нет необходимости записывать весь файл обратно, вам нужно записать только остальную часть файла, начиная с измененной позиции. Это также может быть дорогостоящим, если файл огромен и изменяется в начале. Я написал ответ, как это можно сделать, не перезаписывая большие фрагменты файла.

Ответ №1:

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

 #include <fstream>
#include <iostream>
#include <string>
 
int main()
{
    std::fstream fileMovies{"sample.txt",
                            std::ios_base::in | std::ios_base::out | std::ios_base::binary};
    if (!fileMovies.is_open())
    {
        std::cerr << "Failed to open file" << std::endl;
        return -1;
    }

    std::string movieName{};
    std::getline(std::cin, movieName);

    std::string line{};
    line.reserve(256);

    long long int pos = fileMovies.tellp();
    for (line; std::getline(fileMovies, line);)
    {
        if (line.find(movieName) != std::string::npos)
            break;
        line.clear();
        pos = fileMovies.tellp();
    }

    if (fileMovies.eof())
    {
        std::cerr << "Failed to find the movie by name" << std::endl;
        return -1;
    }

    long long int curPos = fileMovies.tellp();

    // TODO: check format
    long long int commaPos = line.rfind(',');
    fileMovies.seekp(pos   commaPos   2);

    int liked = 0;
    fileMovies >> liked;
    fileMovies.seekp(pos   commaPos   2);
    fileMovies <<   liked;

    return 0;
}
 

Вывод:

 PS C:devbuildseditfileRelease-Visual Studiobin> cat .sample.txt
SNO, Name, NoOfPeopleLiked
1, The Shawshank Redemption, 77
2, The Godfather, 20
3, Into The Wild, 35
4, The Dark Knight, 55
5, 12 Angry Men, 44
6, Schindler's List, 33
7, The Lord of the Rings: The Return of the King, 25
8, Pulp Fiction, 23
9, The Good, the Bad and the Ugly, 32
10, The Lord of the Rings: The Fellowship of the Ring, 56
PS C:devbuildseditfileRelease-Visual Studiobin> .main.exe
Angry
PS C:devbuildseditfileRelease-Visual Studiobin> cat .sample.txt
SNO, Name, NoOfPeopleLiked
1, The Shawshank Redemption, 77
2, The Godfather, 20
3, Into The Wild, 35
4, The Dark Knight, 55
5, 12 Angry Men, 45
6, Schindler's List, 33
7, The Lord of the Rings: The Return of the King, 25
8, Pulp Fiction, 23
9, The Good, the Bad and the Ugly, 32
10, The Lord of the Rings: The Fellowship of the Ring, 56
 

Имейте в виду, что вы не можете добавлять новые символы в середине файла (и вы не можете их стереть). Вы можете перезаписать существующие только в текущей позиции.
Поэтому, чтобы это работало правильно, вы должны использовать количество лайков с конечными пробелами или в формате like 0045 .
Кроме того, обратите внимание, что вы должны использовать std::fstream с флагами in | out | binary . Двоичный файл необходим для правильного подсчета текущей позиции.