[英]Reading\Writing Structured Binary File in C++
我想讀取\\寫入具有以下結構的二進制文件:
該文件由“ RECORDS”組成。 每個“記錄”具有以下結構:我將使用第一個記錄作為示例
在這種情況下,LENGHT字段值為22(將0x00 0x16轉換為十進制),因此CONTENT將包含20(22-2)個字節。 我的目標是一張一張地讀取每條記錄,然后將其寫入輸出文件。 其實我有一個讀取功能和寫入功能(一些偽代碼):
private void Read(BinaryReader binaryReader, BinaryWriter binaryWriter)
{
byte START = 0x5A;
int decimalLenght = 0;
byte[] content = null;
byte[] length = new byte[2];
while (binaryReader.PeekChar() != -1)
{
//Check the first byte which should be equals to 0x5A
if (binaryReader.ReadByte() != START)
{
throw new Exception("0x5A Expected");
}
//Extract the length field value
length = binaryReader.ReadBytes(2);
//Convert the length field to decimal
int decimalLenght = GetLength(length);
//Extract the content field value
content = binaryReader.ReadBytes(decimalLenght - 2);
//DO WORK
//modifying the content
//Writing the record
Write(binaryWriter, content, length, START);
}
}
private void Write(BinaryWriter binaryWriter, byte[] content, byte[] length, byte START)
{
binaryWriter.Write(START);
binaryWriter.Write(length);
binaryWriter.Write(content);
}
如您所見,我已經為C#編寫了代碼,但是我真的不知道如何使用C ++。 有人能指出我正確的方向嗎?
您需要使用std::ifstream
並以二進制模式 ( std::ios_base::binary
)打開文件。
peek
非常相似,但是如果無法提取任何字符,則返回eof
而不是-1
。 read
將使您能夠將給定數量的字節讀取為一個值。 請注意,您熟悉的某些類型( byte
, type[]
)在C ++中不存在或工作不同。 您可以為后者使用std::vector
,但您需要自己定義byte
。
我想我會按此順序做一些事情:
struct record {
static const int start = '\x5a';
std::vector<char> data; // you might prefer unsigned char.
};
std::istream &operator>>(std::istream &is, record &r) {
char ch;
short len;
is.get(ch);
verify(ch == record::start);
is.read((char *)&len, sizeof(len));
r.data.resize(len);
is.read(&r.data[0], len);
return is;
}
std::ostream &operator<<(std::ostream &os, record const &r) {
os << record::start;
short len = (short)r.data.size();
os.write((char *)&len, sizeof(len));
os.write(&r.data[0], len);
return os;
}
要處理記錄文件,就像您在“ Read
顯示的一樣(讀取,處理和寫入數據的名稱很差,BTW),讓我們首先定義一個仿函數來處理文件中的單個記錄:
class process_record {
record operator()(record r) {
// code to process a single record goes here
// it will take one record as input, and return the processed record.
}
}
然后,要處理文件,我們將使用如下代碼:
std::transform(std::istream_iterator<record>(infile),
std::istream_iterator<record>(),
std::ostream_iterator<record>(outfile, ""),
process_record());
[注意:為了簡潔起見,我在這里使用了C樣式的強制類型轉換,但是在實際代碼中,我可能會使用static_cast
代替。]
好的,根據您的回答,我做了一些實驗:
string sFile = "C:\Test.bin";
static const int START_BYTE = '\x5a';
char tempByte;
ifstream inputFile (sFile, ios::in);
inputFile.open( sFile, ios::binary );
while (!inputFile.eof())
{
inputFile.get(temptByte);
cout << "Value of Byte " << hex << static_cast<int>(tempByte) << " hexadecimal" << endl;
}
但是,輸出始終顯示為:ffffffcc,或者如果未轉換為-52。
如果我做對了,我的代碼應該一次讀取一個字節的文件,並打印出十六進制的字節值。 我錯了嗎 ?
謝謝大家,這是我能夠開發的解決方案:
// TestCPP003.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "boost\program_options.hpp"
namespace po = boost::program_options;
#include "Util.h"
using namespace std;
int main(int argc, char* argv[])
{
po::options_description desc("Allowed options");
desc.add_options()
("h", "produce help message")
("i", po::value<string>(), "input file")
("o", po::value<string>(), "output file");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("h"))
{
cout << desc << endl;
return 0;
}
po::notify(vm);
if (vm.count("i"))
{
cout << vm["i"].as<string>() << "\n";
}
string sInputFile = vm["i"].as<string>();
if (fileExists(sInputFile.c_str()))
{
cout << "file exists: <" << sInputFile << ">" << endl;
}
else
{
cout << "file not exists: <" << sInputFile << ">" << endl;
cout << "RETURN CODE: 8" << endl;
return 8;
}
string sOutputFile = vm["o"].as<string>();
static const int START_BYTE = '\x5a';
static const int AFP_RECORD_HEADER_SIZE = 1;
static const int AFP_RECORD_LENGTH_SIZE = 2;
char * afpHeaderBlock = new char[1];
char * afpLengthBlock;
unsigned int afpRecordLength = 0;
char * afpContentBlock;
ifstream inputStream(sInputFile, ios::in|ios::binary);
ofstream outputStream(sOutputFile, ios::out|ios::binary);
if (inputStream.is_open() && outputStream.is_open())
{
while (inputStream.read(afpHeaderBlock, AFP_RECORD_HEADER_SIZE))
{
//cout << ToHex(string(afpHeaderBlock, AFP_RECORD_HEADER_SIZE), true) << endl;
if (START_BYTE == afpHeaderBlock[0])
{
cout << "0x5A Found!" << endl;
}
else
{
cout << "0x5A not Found! - AFP Error" << endl;
}
outputStream.write(afpHeaderBlock, AFP_RECORD_HEADER_SIZE);
afpLengthBlock = new char[AFP_RECORD_LENGTH_SIZE];
afpRecordLength = 0;
inputStream.read(afpLengthBlock, AFP_RECORD_LENGTH_SIZE);
//cout << ToHex(string(afpLengthBlock, AFP_RECORD_LENGTH_SIZE), true) << endl;
afpRecordLength = (afpRecordLength << 8) + static_cast<const unsigned char&>(afpLengthBlock[0]);
afpRecordLength = (afpRecordLength << 8) + static_cast<const unsigned char&>(afpLengthBlock[1]);
//cout << "AFP Record Length: " << afpRecordLength << endl;
outputStream.write(afpLengthBlock, AFP_RECORD_LENGTH_SIZE);
afpContentBlock = new char[afpRecordLength - AFP_RECORD_LENGTH_SIZE];
inputStream.read (afpContentBlock, afpRecordLength - AFP_RECORD_LENGTH_SIZE);
outputStream.write(afpContentBlock, afpRecordLength - AFP_RECORD_LENGTH_SIZE);
}
inputStream.close();
outputStream.flush();
outputStream.close();
}
cout << "RETURN CODE: 0" << endl;
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.