如何在 C++ 中使用文件流将无符号 __int8 数组正确读取和写入二进制文件
How to read and write correctly unsigned __int8 array to binary file using filestream in C++
我正在使用生成器生成无符号 __int8 的随机序列,然后使用 ofstream.write() 和此方法将它们写入文件;
void CDataGenerator::GenerateRandom(std::string outputFileName, int length, bool UseEntireRange, int max) {
std::ofstream file;
file.open(outputFileName, std::ifstream::out | std::ifstream::binary);
int count = 0;
unsigned __int8* buf = new unsigned __int8[length];
while (count < length-1) {
int number = 0;
if (UseEntireRange)
number = rand();
else {
int rnd = rand();
number = (int)((double)rnd / RAND_MAX * max);
}
int capacity = 0;
if (number == 0)
capacity = 1;
else
capacity = (int)(floor(log10(number)) + 1);
for (int i = 0; i < capacity; ++i) {
if (count >= length - 2)
break;
buf[count] = ((unsigned __int8)(number / (int)pow(10, capacity - i - 1)));
number %= (int)pow(10, capacity - i - 1);
++count;
}
++count;
buf[count] = BCD_SEPARATOR;
}
file.write((__int8*)&buf[0], length);
delete[] buf;
file.close();
}
哪里const static unsigned __int8 BCD_SEPARATOR = 0xff;
然后我尝试用下面的方法读取文件
unsigned __int8* CModel::GetRawData(std::string inputFileName, int &length) {
std::ifstream file(inputFileName, std::ifstream::ate | std::ifstream::binary);
length = file.tellg();
file.close();
file.open(inputFileName, std::ifstream::in | std::ifstream::binary);
unsigned __int8* result = new unsigned __int8[length];
file.read((__int8*)&result[0], length);
file.close();
return result;
}
我的测试生成器创建这样的序列
0x0 0xFF 0x5 0x6 0xFF 0x1 0x9 0xFF 0x8 0xFF
但是从阅读流中我得到
0x0 0xCD 0x5 0x6 0xCD 0x1 0x9 0xCD 0x8 0xCD
顺序。
很明显,所有的 0xff 都被替换为 0xcd。它是否与 (__int8*) 演员有关,我该如何解决?
根据 Visual Studio 使用的 CRT 调试堆的知识(我只是假设您正在使用 Visual Studio),可以很好地猜测 0xCD 值来自未初始化的堆内存。那么问题就变成了:为什么你会在输出中看到这个?要找出原因,您可以使用 debugger/read 代码简单地单步执行 GenerateRandom 函数。
由此可见问题所在:
for (int i = 0; i < capacity; ++i) {
if (count >= length - 2)
break;
buf[count] = ((unsigned __int8)(number / (int)pow(10, capacity - i - 1)));
number %= (int)pow(10, capacity - i - 1);
++count; //Increment count ONCE
}
++count; //Increment count a SECOND time
buf[count] = BCD_SEPARATOR;
问题在于,当程序离开此处显示的 for 循环时,计数已经递增一次,因此您的 "count" 已经在缓冲区中的下一个未初始化 __int8 处。然后在将 BCD_SEPARATOR 写入缓冲区中的 "count" 位置之前再次递增 "count" 。这会导致程序跳过您实际想要 BCD_SEPARATOR.
的位置
下一个问题就变成了,因为在将 BCD_SEPARATOR 写入缓冲区之后和下次进入上面所示的 for 循环之间,您没有递增 "count",您立即覆盖 BCD_SEPARATOR.
解决这个问题的方法可能是像这样简单地交换东西:
buf[count] = BCD_SEPARATOR;
++count;
我正在使用生成器生成无符号 __int8 的随机序列,然后使用 ofstream.write() 和此方法将它们写入文件;
void CDataGenerator::GenerateRandom(std::string outputFileName, int length, bool UseEntireRange, int max) {
std::ofstream file;
file.open(outputFileName, std::ifstream::out | std::ifstream::binary);
int count = 0;
unsigned __int8* buf = new unsigned __int8[length];
while (count < length-1) {
int number = 0;
if (UseEntireRange)
number = rand();
else {
int rnd = rand();
number = (int)((double)rnd / RAND_MAX * max);
}
int capacity = 0;
if (number == 0)
capacity = 1;
else
capacity = (int)(floor(log10(number)) + 1);
for (int i = 0; i < capacity; ++i) {
if (count >= length - 2)
break;
buf[count] = ((unsigned __int8)(number / (int)pow(10, capacity - i - 1)));
number %= (int)pow(10, capacity - i - 1);
++count;
}
++count;
buf[count] = BCD_SEPARATOR;
}
file.write((__int8*)&buf[0], length);
delete[] buf;
file.close();
}
哪里const static unsigned __int8 BCD_SEPARATOR = 0xff;
然后我尝试用下面的方法读取文件
unsigned __int8* CModel::GetRawData(std::string inputFileName, int &length) {
std::ifstream file(inputFileName, std::ifstream::ate | std::ifstream::binary);
length = file.tellg();
file.close();
file.open(inputFileName, std::ifstream::in | std::ifstream::binary);
unsigned __int8* result = new unsigned __int8[length];
file.read((__int8*)&result[0], length);
file.close();
return result;
}
我的测试生成器创建这样的序列 0x0 0xFF 0x5 0x6 0xFF 0x1 0x9 0xFF 0x8 0xFF 但是从阅读流中我得到 0x0 0xCD 0x5 0x6 0xCD 0x1 0x9 0xCD 0x8 0xCD 顺序。 很明显,所有的 0xff 都被替换为 0xcd。它是否与 (__int8*) 演员有关,我该如何解决?
根据 Visual Studio 使用的 CRT 调试堆的知识(我只是假设您正在使用 Visual Studio),可以很好地猜测 0xCD 值来自未初始化的堆内存。那么问题就变成了:为什么你会在输出中看到这个?要找出原因,您可以使用 debugger/read 代码简单地单步执行 GenerateRandom 函数。
由此可见问题所在:
for (int i = 0; i < capacity; ++i) {
if (count >= length - 2)
break;
buf[count] = ((unsigned __int8)(number / (int)pow(10, capacity - i - 1)));
number %= (int)pow(10, capacity - i - 1);
++count; //Increment count ONCE
}
++count; //Increment count a SECOND time
buf[count] = BCD_SEPARATOR;
问题在于,当程序离开此处显示的 for 循环时,计数已经递增一次,因此您的 "count" 已经在缓冲区中的下一个未初始化 __int8 处。然后在将 BCD_SEPARATOR 写入缓冲区中的 "count" 位置之前再次递增 "count" 。这会导致程序跳过您实际想要 BCD_SEPARATOR.
的位置下一个问题就变成了,因为在将 BCD_SEPARATOR 写入缓冲区之后和下次进入上面所示的 for 循环之间,您没有递增 "count",您立即覆盖 BCD_SEPARATOR.
解决这个问题的方法可能是像这样简单地交换东西:
buf[count] = BCD_SEPARATOR;
++count;