Удалить элемент вектора с помощью fstream C

#c #vector #fstream

Вопрос:

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

 #include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <fstream>
using namespace std;

void Menu()
{
    cout << "******************" << endl;
    cout << "1 - Add student" << endl;
    cout << "2 - Delete student" << endl;
    cout << "3 - All students" << endl;
    cout << "******************" << endl;
}

struct School
{
    string Name;
    string remove;
    int Ages;
    int Option;
};

int main()
{
    ofstream Myfile("practiceFile.txt", ios::app);

    School Students;
    vector <string> Names;

    if(!Myfile.is_open())
    {
        cout << "Error opening file" << endl;
    }

    if(Myfile.is_open())
    {
        Menu();
        cout << endl;
        cout << "Option: ";
        cin >> Students.Option;
        cin.ignore();

        if(Students.Option == 1)
        {
            cout << "Enter name: ";
            getline(cin, Students.Name);
            Names.push_back(Students.Name);

            for(int i = 0; i < Names.size(); i  )
            {
                Myfile << Names[i] << endl;
            }
        }

        if(Students.Option == 2)
        {
            cout << "Enter name: ";
            getline(cin, Students.remove);
            
            for(int i = 0; i < Names.size(); i  )
            {
                if(Students.remove == Names[i])
                {
                    auto itr = find(Names.begin(), Names.end(), Students.remove);
                    if(itr != Names.end())
                    {
                        Names.erase(itr);
                    }
                }
            }     
        }
    }

    string line;
    ifstream NewFile("practiceFile.txt", ios::in);

    while(NewFile >> line)
    {
        if(Students.Option == 3)
        {
            cout << line << endl;
        }         
    } 
}
 

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

1. Удалите его из вектора, а затем запишите весь файл, используя содержимое вектора.

Ответ №1:

Есть несколько способов, которыми вы могли бы это сделать.

  1. Переписывайте файл всякий раз, когда список обновляется, используя вектор в качестве «руководства» для написания предостережения здесь заключается в том, что если в какой-либо момент ваш код вызовет исключение, файл останется в неопределенном состоянии, что может привести к потере ваших данных. Пример:
 std::vector<std::string> Names;
std::ofstream MyFile("practiceFile.txt", std::ios::app);

// add or remove names

// clear the file using truncate mode
MyFile.close();
MyFile.open("practiceFile.txt", std::ios::trunc | std::ios::out);
// write out the whole list of names
for (autoamp; Name : Names)
    MyFile << Name << std::endl;
 
  1. Другим (вероятно, лучшим) способом была бы запись во временный файл, единственное предостережение здесь заключается в том, что если временный файл существует, вы будете перезаписывать все, что в нем есть
 std::vector<std::string> Names;
std::ofstream MyFile("practiceFile.txt", std::ios::app);

// add or remove names

// create a temp file
std::ofstream TempFile("practiceFile_temp.txt", std::ios::trunc | std::ios::out);

// write out the whole list of names
for (autoamp; Name : Names)
    TempFile << Name << std::endl;

// close all open files
TempFile.close();
MyFile.close();

// delete the old file
std::remove("practiceFile.txt");

// move the temp file to the new file
std::rename("practiceFile_temp.txt", "practiceFile.txt")
 

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

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

Как упоминал Тед Лингмо, лучшим подходом для второго метода было бы использование std::filesystem::rename , которое автоматически удалит старый файл и заменит его новым. Кроме того, есть дополнительное преимущество наличия исключений C , которые вы можете распространять на абонентов, если вам когда-нибудь это понадобится:

 std::vector<std::string> Names;
std::ofstream MyFile("practiceFile.txt", std::ios::app);

// add or remove names

// create a temp file
std::ofstream TempFile("practiceFile_temp.txt", std::ios::trunc | std::ios::out);

// write out the whole list of names
for (autoamp; Name : Names)
    TempFile << Name << std::endl;

// close all open files
TempFile.close();
MyFile.close();

// move the temp file to the new file
std::filesystem::rename("practiceFile_temp.txt", "practiceFile.txt");
 

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

1. Однако я бы не стал удалять старый файл. Просто позвольте переименованию разорвать его связь.

2. @TedLyngmo из cppreference : «Если имя файла new_filename существует, поведение определяется реализацией».

3. Спасибо за ваш ответ, я собираюсь проверить это сейчас. @msimonelli

4. Правда. Я бы использовал std::filesystem::rename вместо этого. Использование thst гарантирует атомарное удаление старого файла и переименование нового.

5. Я боролся с #include <файловой системой> . Я не могу заставить это работать в моем визуальном коде. Я пытался обновить свой визуальный код до C 17, но не могу. Мои конфигурации показывают, что я перешел на C 17, но я все еще получаю в своем сборнике: «Содержимое <файловой системы> доступно только с C 17 или более поздней версией». Что я могу сделать ? @msimonelli