如何在写入二进制文件时跳过结构[c++]

How can i skip over structures when writing in a binary file [c++]

本文关键字:结构 c++ 二进制文件      更新时间:2023-10-16

我有一个结构:

struct Ticket
{
    bool IsReserved; // Is the seat resereved (true)
    time_t SoldOn; //When has the ticket been bought
    double Price; // Price of the ticket
    Ticket() {  IsReserved = 0; Price = 0; SoldOn = 0; }
};

我已经把它保存了很多次,因为我需要在二进制文件中,我正确地读取了它。我的问题是,当用户想要购买门票时,我如何才能只修改一个结构。例如,当他想购买第5个座位时,他应该去第5个结构并只更改该数据。我是这样做的。

std::cout<<"nPlease enter how many tickets would you like to purchase : n";
do
{   
    if(number<0 || number > freeSeats)
        std::cerr<<"Invalid input.try again: n";
    std::cin>>number;
}while(number<0 || number > freeSeats);
int *t = new int[number];
for(int i = 0; i<number; i++)
{
    int seat = 0;
    do
    {
        std::cout<<"Please enter seat "<<i<<" : ";
        std::cin>>seat;
        file.clear();
        file.seekg(0,std::ios::beg);
        for(int i =1; i <= seat; i++)
        {
            serializeTickets(file,ticket);
        }
        if(ticket.IsReserved == 1)
            std::cout<<"The ticket has already been reservedn";
    }while(ticket.IsReserved == 1);
    t[i] = seat;
}
file.close();
schedule.serializeTargetLine(choice);
std::ofstream myFile(ticketsFileName,std::ios::binary || std::ios::out);
for(int i = 0; i<number; i++)
{
    time_t timer(0);
    std::time(&timer);
    myFile.seekp(+(t[i] - 1)*sizeof(Ticket),std::ios::beg);
    ticket.IsReserved=1;
    ticket.Price = atof(schedule.getPrice().c_str());
    ticket.SoldOn = timer;
    myFile.write(reinterpret_cast<char*> (&ticket),sizeof(Ticket));
}
delete[] t;
myFile.close();

如果您正在使用GCC进行编译,我建议您在编译器标志中添加-Wall,以获得最大的编译器帮助。

问题似乎是你没有打开文件来写:

std::ofstream myFile(ticketsFileName,std::ios::binary || std::ios::out);

当你可能不想

std::ios::binary | std::ios::out

或(std::ios::binary | std::ios::out)

如果你打开完整的编译器警告,它会告诉你你有一个布尔操作,你可能不想有一个逻辑。

,是的,您可能应该在结构周围使用pragma pack。参见http://msdn.microsoft.com/en-us/library/ms253935(v=vs.80).aspx和https://stackoverflow.com/a/9852860/257645

注意,除非你的目标是旧的编译器,否则你可以这样做:
#pragma pack(push, 1)
struct ... {
    ...
};
#pragma pack(pop)

(短版本:它告诉编译器使用结构的内存表示,这种表示可能在运行时性能较差,但会为这样的存储创建较少的依赖环境的占用空间)

在写入文件时,我可能会在将结构体数据写入文件之前使用以下命令:

#pragma pack(1)

之后,只需要使用sizeof(ticket) * seat作为从文件开头开始的寻道偏移量。

file.seekg((sizeof(ticket) * seat), std::ios::beg);

这看起来可能是一个真正的数据库的工作,它将已经为您计算出所有这些繁琐的细节(当然还会有其他繁琐的细节)。

也就是说,你的代码乍一看应该可以工作(除了kfsone指出的| vs ||问题)。如果你允许我挑剔一点:

  • std::vector应该优先于array-new,因为它封装了最容易出错的部分。
  • 从技术上讲,直接将Ticket结构体从文件中移到/移出是违反标准的,因为它有一个构造函数。
  • 您可能想要考虑使用同时为读和写打开的std::fstream,而不是打开同一个文件两次。在读写文件时,很多事情都可能出错。您的代码应该优雅地处理这些事情。例如,
    • read()和write()允许读/写的字节比指定的要少
    • 如果查找超过了文件末尾,可能会失败。