【问题标题】:How to store binary file data in structure?如何在结构中存储二进制文件数据?
【发布时间】:2017-09-06 07:04:51
【问题描述】:

大家好,

我有一个如下所示的文件(Material.dat),它是二进制文件,我想从文件中读取数据并放入我使用 GetRecord() 函数的结构中。

HANDLE hFileMac = ::CreateFile(_T("Material.dat"), GENERIC_READ, FILE_SHARE_READ, NULL,
  OPEN_EXISTING, FALSE ? FILE_FLAG_SEQUENTIAL_SCAN : FILE_ATTRIBUTE_NORMAL, NULL);

 if (!(hFileMac != INVALID_HANDLE_VALUE))
 {
  return;
 }

 GetRecord(hFileMac, RECORD_NUMBER, sizeof(Header), reinterpret_cast<void *>(&Header));

我的疑问是将什么作为记录号传递给 Get Record() 函数?

GetRecord(hFileMac, RECORD_NUMBER, sizeof(Header), reinterpret_cast(&Header));

int GetRecord(HANDLE hFile, int RecordNumber, int RecordSize, void *RecordPtr)
{
 if (RecordNumber <= 0 || RecordSize <= 0)
  return 1;
 LONG lOffset = (RecordNumber - 1) * RecordSize;

 if (SetFilePointer(hFile, lOffset, NULL, FILE_BEGIN) == 0xFFFFFFFF)
  return 2;

 DWORD dwSize;

 if (::ReadFile(hFile, RecordPtr, RecordSize, &dwSize, NULL) == 0)
  return 3;

 return 0;
}

【问题讨论】:

  • 您必须跟踪已阅读的条目数。可能二进制文件中的每个条目都具有相同的大小(如果不是,则此函数将不起作用,因为它假定每个元素的大小相同),因此提供 RecordNumber 允许偏移量计算在何处查找此特定条目。
  • google protobuf 可能是您的解决方案。
  • 是的,二进制文件中的每个条目都有相同的大小。如何跟踪条目数以及如何计算偏移量?能否请您让我理解清楚。
  • @RevanthRao 据我所知,您的函数读取编号为RecordNumber 的记录并正确执行所有计算。为了节省开支,您可能会考虑编写一个小测试程序来检查代码是否符合您的要求。 @Rogus 偏移量是从文件的开头计算和设置的,那么他为什么要跟踪已经读取的记录数呢?
  • @GertWollny 是的,函数读取编号为 RecordNumber 的记录。我应该传递什么作为记录号?

标签: c++ c++11 visual-c++


【解决方案1】:

首先按照您提出的方式回答问题:要将所有数据读入向量中,我建议更改代码以假设第一条记录的 RecordNumber=0:

LONG lOffset = RecordNumber * RecordSize;

然后,要将所有记录读入 std::vector,您可以执行类似的操作

struct Record {...}; 
typedef Record* RecordPtr; 
...
std::vector<Record> data_records; 
Record current; 

while (GetRecord(hFile, data_records.size(), sizeof(Record), &current) == 0 ) {
    data_records.push_back(current); 
}

现在考虑到您按顺序读取所有记录,您实际上可以忘记RecordNumber 和对SetFilePointer 的调用,因为文件读取位置应该由ReadFile 调用更新。

无论如何,为了更好的代码可移植性,最好使用 C++ 标准库中的文件 IO 函数,而不是 MS Windows 特定调用(如 WernerErasmus 建议的那样,详情请参阅 here)。

【讨论】:

    【解决方案2】:

    我会使用这种类型的界面:

    class Record {
      //Reads a single record from "from", incrementing the associated 
      // read pointer, and returning eof or bad, depending on whether record
      // state is consistent, and whether eof stream is reached
      std::istream& read(std::istream& from);
      //Writes a single record to "to"
      std::ostream& write(std::ostream& to);
    }
    
    struct MaterialStore {
      //Reads all records from "from", in sequence, using Record interface
      std::istream& read(std::istream& from);
    
      //Writes all records in "to" to, in sequence, using Record interface
      std::ostream& write(std::ostream& to);
    
      //Perhaps to perform that seeking for a specific record, the
      // Use Record interface for retrieval.
      std::iostream& seekRecord(std::iostream& stream, int index pos);
    
      const Record& getRecords(); //Returns all the records read
    }
    

    读/写是否是二进制的,取决于实现。阅读和写作总是连续进行的。可以读取特定记录,在这种情况下,必须在读取记录之前完成流指针操作。我添加了在流中寻找特定位置(无论是读取还是写入)的可能性,使用 Record 接口进行读取/写入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-22
      • 1970-01-01
      相关资源
      最近更新 更多