Как отредактировать и перезаписать определенное местоположение в файле на C ++
Вопрос
Я создаю программное обеспечение для бронирования авиабилетов, и я мало что знаю о Visual C ++.Я использую простой компилятор "TCWIN45".В моей программе я хочу использовать обработку файлов, и мне удается сохранить все входные данные в текстовый файл.мне нужно добавить опцию поиска и опцию модификации.если пользователь выберет поиск и введет имя, то как я могу получить доступ к определенному количеству строк?потому что мои файлы содержат записи о нескольких пассажирах, но я хочу показать данные только одного из них.то же самое относится и к модификации.Я хочу получить доступ к определенному местоположению или строке, а также перезаписать их.пожалуйста, предложите мне самый простой способ.
Это мой код для сохранения всех записей в одном текстовом файле:
ofstream thefile("ID.txt" , ios::app);
thefile<<"\n\nDay : "<<p1[i].day<<"\nFlight Date : "<<p1[i].date<<"\nFlight Type : "<<p1[i].type<<"\nReturn Date : "<<p1[i].rdate<<"\nDeparture Place : "<<p1[i].from<<"\nDestination : "<<p1[i].to<<"\nClass Type : "<<p1[i].clas<<"\nTime of Flight : "<<p1[i].time<<"\nTitle : "<<p1[i].prefix<<"\nFirst Name : "<<p1[i].fname<<"\nLast Name : "<<p1[i].lname<<"\nDate of Birth : "<<p1[i].dob<<"\nPassport Number : "<<p1[i].ppt_no<<"\nExpiry Date : "<<p1[i].edate<<"\n Contact Number : "<<p1[i].cont<<"\nMeal Type : "<<p1[i].meal<<"\n\n------------------------------";
Решение
Али, это можно сделать в плоском файле, если ты действительно не хочешь использовать базу данных.Хитрость заключается в том, чтобы либо:1.) иметь все записи одинакового размера ИЛИ 2.) иметь "заголовок записи", который предоставляет "достаточную" информацию для возможности несериализации записи с жесткого диска.Если вы храните записи разных типов, "достаточной" информацией может быть размер записи или тип записи для целей RTTI.Я считаю полезным также сохранять идентификатор для каждой записи, чтобы я мог хранить таблицу индексов для смещений записей.
Если ваши записи имеют разный размер, то функции сериализации вашей записи должны быть способны справиться с этим.На самом деле, сделать это тривиально.
Таблица индексов - это таблица смещений файлов.
typedef uint16_t record_id;
typedef long offset_t;
offset_t indices[ MAX_RECORDS ];
typedef struct _record {
uint16_t type;
uint16_t id;
offset_t next;
offset_t prev;
} record;
typedef struct _header {
uint32_t count;
offset_t first_record;
offset_t deleted_record;
} header;
Итак, чтобы найти положение записи, вы находите смещение в файле, которое называется indexes[record_id].Добавление записи похоже на добавление узла в связанный список, но узлы находятся в файле.Удаление записей - это немного сложная задача.Вы должны использовать "ленивое удаление" для удаления записей, и позже эти удаленные записи будут использованы повторно.Вы даже можете написать функцию сжатия, которая удалит все удаленные записи из файла, чтобы освободить неиспользуемое пространство.
Ограничения этого метода заключаются в том, что вы можете выполнять поиск только по идентификатору записи.Если у вас есть другая информация, вам нужно будет сгенерировать дополнительные структуры данных для поддержки этого.
У меня есть доступный код, который делает это на C, если вам нужен рабочий пример.Однако сделать это с нуля возможно, но НЕ СТОИТ ЗАТРАЧЕННЫХ УСИЛИЙ.Просто используйте базу данных, такую как Sqlite или MySQL - это сэкономит время!
Пример кода
Другие советы
От ваших комментариев до других ответов, вам не кажется лучшим способом сделать это вообще хранить данные в текстовом файле. Вы, вероятно, захотите Reservation
класс, который содержит всю информацию для резервации. Затем используйте какую -то коллекцию для хранения всех резерваций. Написание в текстовый файл просто добавляет огромное количество ненужных сложности.
Что-то вроде этого:
class Reservation
{
std::string day;
std::string date;
std::string flightType;
std::string meal;
/* ... */
};
Было бы еще лучше, если бы вы сделали отдельные занятия для каждого из членов класса (например, Day
класс, а FlightType
класс и т. д.).
Затем вы бы использовали какой -то Map
Чтобы получить доступ к конкретному бронированию и изменить его членов.
Вы, вероятно, захотите определить reservation
класс, который представляет собой единое резервирование, и data
класс, который содержит все ваши данные, как vector
из reservation
с Класс данных захочет выполнить функцию члена, которая принимает std::ostream
По ссылке и сохраняет резервирование в текстовом файле (самая легкая - одна переменная на строку). Также понадобится функция участника, которая принимает std::istream
Ссылка и считывается в данных из текстового файла.
Основная часть вашей программы (я делаю тонны предположений здесь) загрузить файл в data
класс с std::istream
Функция члена и просит пользователя какого -то идентификатора. Затем вы называете функцию участника data
что проверяет все элементы в data
S вектор, пока он не найдет соответствующий идентификатор (по ссылке) и позволяет пользователю изменить некоторые участники. Тогда это вызывает std::ostream
Участник снова снова, чтобы сохранить изменения.
Потоки обрабатываются так. В этом примере я не использую data
Класс или вектор, так как этот вопрос выглядит подозрительно, как домашняя работа, но это показывает сложные части обработки файлов.
#include <string>
#include <iostream>
#include <fstream>
class Reservation {
std::string ID;
std::string date;
public:
//default constructor
Reservation()
{}
//helpful constructor
Reservation(std::string _id, std::string _date)
:ID(_id), date(_date)
{}
//copy constructor
Reservation(const Reservation& b)
:ID(b.ID), date(b.date)
{}
//move constructor
Reservation(Reservation&& b)
:ID(std::move(b.ID)), date(std::move(b.date))
{}
//destructor
~Reservation()
{}
//assignment operator
Reservation& operator=(const Reservation& b)
{
ID = b.ID;
date = b.date;
return *this;
}
//move operator
Reservation& operator=(Reservation&& b)
{
ID = std::move(b.ID);
date = std::move(b.date);
return *this;
}
//save
std::ostream& save(std::ostream& file) {
file << ID << '\n';
file << date << '\n';
return file; //be in the habit of returning file by reference
}
//load
std::istream& load(std::istream& file) {
std::getline(file, ID);
std::getline(file, date);
return file; //be in the habit of returning file by reference
}
};
int main() {
Reservation reserve; //create a Reservation to play with
{ //load the reservation from loadfile
std::ifstream loadfile("myfile.txt");
reserve.load(loadfile);
}
//display the reservation
reserve.save(cout);
{ //save the reservation to a different file
std::ofstream savefile("myfile2.txt");
reserve.save(savefile);
}
return 0;
}