我一直在互联网上搜索用c ++读取二进制文件的方法,我找到了两个有用的片段:
No.1:
#include <iostream>
#include <fstream>
int main(int argc, const char *argv[])
{
if (argc < 2) {
::std::cerr << "Usage: " << argv[0] << "<filename>\n";
return 1;
}
::std::ifstream in(argv[1], ::std::ios::binary);
while (in) {
char c;
in.get(c);
if (in) {
// ::std::cout << "Read a " << int(c) << "\n";
printf("%X ", c);
}
}
return 0;
}
结果:
6C 1B 1 FFFFFFDC F FFFFFFE7 F 6B 1
2号:
#include <stdio.h>
#include <iostream>
using namespace std;
// An unsigned char can store 1 Bytes (8bits) of data (0-255)
typedef unsigned char BYTE;
// Get the size of a file
long getFileSize(FILE *file)
{
long lCurPos, lEndPos;
lCurPos = ftell(file);
fseek(file, 0, 2);
lEndPos = ftell(file);
fseek(file, lCurPos, 0);
return lEndPos;
}
int main()
{
const char *filePath = "/tmp/test.bed";
BYTE *fileBuf; // Pointer to our buffered data
FILE *file = NULL; // File pointer
// Open the file in binary mode using the "rb" format string
// This also checks if the file exists and/or can be opened for reading correctly
if ((file = fopen(filePath, "rb")) == NULL)
cout << "Could not open specified file" << endl;
else
cout << "File opened successfully" << endl;
// Get the size of the file in bytes
long fileSize = getFileSize(file);
// Allocate space in the buffer for the whole file
fileBuf = new BYTE[fileSize];
// Read the file in to the buffer
fread(fileBuf, fileSize, 1, file);
// Now that we have the entire file buffered, we can take a look at some binary infomation
// Lets take a look in hexadecimal
for (int i = 0; i < 100; i++)
printf("%X ", fileBuf[i]);
cin.get();
delete[]fileBuf;
fclose(file); // Almost forgot this
return 0;
}
结果:
6C 1B 1 DC F E7 F 6B 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A1 D 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
xxd /tmp/test.bed
的结果:
0000000: 6c1b 01dc 0fe7 0f6b 01 l......k.
ls -l /tmp/test.bed
-rw-rw-r-- 1 user user 9 Nov 3 16:37 test.bed
第二种方法是在开头给出正确的十六进制代码,但似乎文件大小错误,第一种方法是搞乱字节。
这些方法看起来非常不同,也许在c ++中有很多方法可以做同样的事情?专业人士是否有成语?
答案 0 :(得分:1)
您当然希望将char
对象转换为unsigned char
,然后再将它们作为整数值处理!问题是char
可能会被签名,在这种情况下,负值会在您投射时转换为负int
。显示为十六进制的负int
将有两个以上的十六进制数字,前导的数字可能都是“f”。
我没有立即发现为什么第二种方法的大小错误。但是,读取二进制文件的C ++方法很简单:
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
std::vector<unsigned char> bytes;
{
std::ifstream in(name, std::ios_base::binary);
bytes.assign(std::istreambuf_iterator<char>(in >> std::noskipws),
std::istreambuf_iterator<char>());
}
std::cout << std::hex << std::setfill('0');
for (int v: bytes) {
std::cout << std::setw(2) << v << ' ';
}
答案 1 :(得分:1)
你的方法都是C和C ++的奇怪组合(实际上,第二种只是普通的C);仍然,第一种方法大多是正确的,但你必须使用unsigned char
作为c
,否则任何超过0x7f的字节都被读为负数,这会导致输出错误。 1
要以“C ++方式”正确地执行和,您应该已经完成了:
std::cout<<std::hex<<std::setfill('0');
...
if (in)
std::cout << std::setw(2)<<int(c) << "\n";
第二个获得“签名”正确,但它主要是C.快速解决方法是修复100
循环中的for
,将其替换为fileSize
。但一般来说,将整个文件加载到内存中只是为了以十六进制转储其内容是一个拙劣的想法;你通常做的是在固定大小的缓冲区中一次读取一个文件并将其转换为。
get
返回int
;如果它大于0x7f
,则在分配时会溢出char
,并且通常会导致某些负值。然后当它传递给printf
时,它会被符号扩展(因为传递给vararg函数的任何有符号整数参数被扩展为int
),但由于{{unsigned int
而被解释为%X
1}}参数。 (所有这些假设2的补码算术,非信令整数溢出和签名char
)答案 2 :(得分:0)
在第一种情况下,您打印char(已签名),而在第二种情况下,您使用unsigned char执行相同操作。 %X将字符扩展为整数,这会导致差异。
答案 3 :(得分:0)
在搜索为什么@Roland Illig的答案(现已删除)不起作用时,我找到了以下解决方案,不确定它是否符合专业标准,但它到目前为止给出了正确的结果,并允许检查文件的起始n字节:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
int main(int argc, const char *argv[])
{
if (argc < 3) {
::std::cerr << "usage: " << argv[0] << " <filename>\n";
return 1;
}
int nbytes = std::stoi(argv[2]);
char buffer[nbytes];
std::streamsize size = nbytes;
std::ifstream readingFile(argv[1], std::ios::binary);
readingFile.read(buffer, (int)size);
std::streamsize bytesread = readingFile.gcount();
unsigned char rawchar;
if (bytesread > 0) {
for (int i = 0; i < bytesread; i++) {
rawchar = (unsigned char) buffer[i];
printf("%02x ", (int) rawchar);
}
printf("\n");
}
return 0;
}
我从wibit.com得到的另一个答案:
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, const char* argv[])
{
ifstream inBinaryFile;
inBinaryFile.open(argv[1], ios_base::binary);
int currentByte = inBinaryFile.get();
while(currentByte >= 0)
{
printf("%02x ", currentByte);
currentByte = inBinaryFile.get();
}
printf("\n");
inBinaryFile.close();
return 0;
}