[英]How to read little endian integers from file in C++?
假设我有一个二进制文件; 它包含正二进制数,但以小端写成 32 位整数
我如何阅读这个文件? 我现在有这个。
int main() {
FILE * fp;
char buffer[4];
int num = 0;
fp=fopen("file.txt","rb");
while ( fread(&buffer, 1, 4,fp) != 0) {
// I think buffer should be 32 bit integer I read,
// how can I let num equal to 32 bit little endian integer?
}
// Say I just want to get the sum of all these binary little endian integers,
// is there an another way to make read and get sum faster since it's all
// binary, shouldnt it be faster if i just add in binary? not sure..
return 0;
}
这是一种适用于大端或小端架构的方法:
int main() {
unsigned char bytes[4];
int sum = 0;
FILE *fp=fopen("file.txt","rb");
while ( fread(bytes, 4, 1,fp) != 0) {
sum += bytes[0] | (bytes[1]<<8) | (bytes[2]<<16) | (bytes[3]<<24);
}
return 0;
}
如果您使用的是Linux,则应在此处查看 ;-)
关于有用的功能,例如le32toh
从CodeGuru :
inline void endian_swap(unsigned int& x)
{
x = (x>>24) |
((x<<8) & 0x00FF0000) |
((x>>8) & 0x0000FF00) |
(x<<24);
}
因此,您可以直接读取到unsigned int
,然后调用它。
while ( fread(&num, 1, 4,fp) != 0) {
endian_swap(num);
// conversion done; then use num
}
如果您正在处理短文件,我建议简单使用 class 字符串流,然后使用 function stoul。 下面的代码从 ifstream 中读取每个字节的字节(在本例中为 2 个字节),并将它们以十六进制形式写入字符串 stream 中。 然后感谢 stoul 将字符串转换为 16 位 integer:
#include <sstream>
#include <iomanip>
using namespace std;
ifstream is("filename.bin", ios::binary);
if(!is) { /*Error*/ }
is.unsetf(ios_base::skipws);
stringstream ss;
uint8_t byte1, byte2;
uint16_t val;
is >> byte1; is >> byte2;
ss << setw(2) << setfill('0') << hex << static_cast<size_t>(byte1);
ss << setw(2) << setfill('0') << hex << static_cast<size_t>(byte2);
val = static_cast<uint16_t>(stoul(ss.str(), nullptr, 16));
cout << val << endl;
例如,如果您必须从二进制文件中读取存储在 Big Endian (00 f3) 中的 16 位 integer,则将其放入字符串流 ("00f3") 中,然后将其转换为 integer (243)。 该示例以十六进制写入值,但它可以是十进制或八进制,甚至是二进制,使用 class 位集。 iomanip 函数(setw、setfill)用于为 sstream 提供正确的格式。 这种方法的缺点是,如果您必须处理大文件,它会非常慢。
您可以正常阅读代码。 但是,当您 go解释数据时,您需要进行正确的转换。
这可能会让人头疼,就好像你想让你的代码可移植一样,即在小端和大端机器上运行,你需要处理所有类型的组合:从小到大,从大到小,从小到小和大到大。 在最后两种情况下,无操作。
幸运的是,这一切都可以通过boost::endian 库自动化。 他们文档中的一个例子:
#include <iostream>
#include <cstdio>
#include <boost/endian/arithmetic.hpp>
#include <boost/static_assert.hpp>
using namespace boost::endian;
namespace
{
// This is an extract from a very widely used GIS file format.
// Why the designer decided to mix big and little endians in
// the same file is not known. But this is a real-world format
// and users wishing to write low level code manipulating these
// files have to deal with the mixed endianness.
struct header
{
big_int32_t file_code;
big_int32_t file_length;
little_int32_t version;
little_int32_t shape_type;
};
const char* filename = "test.dat";
}
int main(int, char* [])
{
header h;
BOOST_STATIC_ASSERT(sizeof(h) == 16U); // reality check
h.file_code = 0x01020304;
h.file_length = sizeof(header);
h.version = 1;
h.shape_type = 0x01020304;
// Low-level I/O such as POSIX read/write or <cstdio>
// fread/fwrite is sometimes used for binary file operations
// when ultimate efficiency is important. Such I/O is often
// performed in some C++ wrapper class, but to drive home the
// point that endian integers are often used in fairly
// low-level code that does bulk I/O operations, <cstdio>
// fopen/fwrite is used for I/O in this example.
std::FILE* fi = std::fopen(filename, "wb"); // MUST BE BINARY
if (!fi)
{
std::cout << "could not open " << filename << '\n';
return 1;
}
if (std::fwrite(&h, sizeof(header), 1, fi) != 1)
{
std::cout << "write failure for " << filename << '\n';
return 1;
}
std::fclose(fi);
std::cout << "created file " << filename << '\n';
return 0;
}
编译并执行 endian_example.cpp 后,test.dat 的十六进制转储显示:
01020304 00000010 01000000 04030201
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.