C++读写二进制文件

本文介绍如何使用C++进行二进制文件的读写操作,并提供示例代码,同时讲解了不同文件打开模式的区别及二进制文件复制的方法。

 

 

摘要:

使用C++读写二进制文件,在开发中操作的比较频繁,今天有幸找到一篇文章,遂进行了一些试验,并进行了部分的总结。

 

使用C++操作文件,是研发过程中比较频繁的,因此进行必要的总结和封装还是十分有用的。今天在网上找到一篇,遂进行了部分的试验,以记之,备后用。

 

本文读写文件均使用文件流进行操作,主要使用的类是ifstream, ofstream, 使用时,请务必包含文件fstream。如下:

#include <fstream>

 

 

写二进制文件

写二进制文件应该使用ofstream类,文件的打开模式一定要是 binary,如果传入的不是 binary, 文件将以ASCII方式打开。

 

下面是示例代码,用于写入文件。

 

std::ofstream fout("a.dat", std::ios::binary);

 

int nNum = 20;

std::string str("Hello, world");

 

fout.write((char*)&nNum, sizeof(int));

fout.write(str.c_str(), sizeof(char) * (str.size()));

 

fout.close();

 

而写文本文件则比较简单,如下:

 

std::ofstream fout("b.dat");

 

int nNum = 20;

std::string str("Hello, world");

 

fout << nNum << "," << str << std::endl;

 

fout.close();

  

 

读二进制文件

读取二进制文件可以使用ifstream 类来进行,文件的打开模式一定要是 binary,如果传入的不是 binary, 文件将以ASCII方式打开。

 

下面是示例代码:

 

std::ifstream fin("a.dat", std::ios::binary);

 

int nNum;

char szBuf[256] = {0};

 

fin.read((char*)&nNum, sizeof(int));

fin.read(szBuf, sizeof(char) * 256);

 

std::cout << "int = " << nNum << std::endl;

std::cout << "str = " << szBuf << std::endl;

 

fin.close();

 

而读取文本文件则比较简单:

 

std::ifstream fin("b.dat");

 

int nNum;

char szBuf[256] = {0};

 

fin >> nNum >> szBuf;

 

std::cout << "int = " << nNum << std::endl;

std::cout << "str = " << szBuf << std::endl;

 

fin.close();

 

文件的打开模式

文件操作时,如果不显示指定打开模式,文件流类将使用默认值。

<fstream> 中定义了如下打开模式和文件属性:

 ios::app // 从后面添加

 ios::ate // 打开并找到文件尾

 ios::binary // 二进制模式I/O(与文本模式相对)

 ios::in // 只读打开

 ios::out // 写打开

 ios::trunc // 将文件截为 长度

可以使用位操作符 OR 组合这些标志,比如

 ofstream logFile("log.dat", ios::binary | ios::app);

 

 

二进制文件的复制

这里我实现了一个二进制文件的复制操作,用于验证读写的正确性,示例代码如下:

 

 

后记

由于文本文件本质上也是磁盘上的一个个二进制编码,因此,读写二进制文件的代码同样可以读写文本文件,在文件类型不是很明确的读写操作中,直接使用二进制读写比较可取,如果可以直接判断文件类型,则可以分别对待。

关于读取文本文件,请参照http://blog.csdn.net/lightlater/archive/2011/04/15/6326338.aspx

 

 

 

参考文献:

C++进行简单的文件I/O操作(http://www.vckbase.com/document/viewdoc/?id=1439 )

百度文库(http://wenku.baidu.com/view/9faa23db50e2524de5187eb3.html

 

 

 

 

<think> 我们被要求提供C++读写二进制文件的方法。根据引用[1]和[2],我们需要注意在Windows和Linux下可能有不同的行为,尤其是文本模式和二进制模式的区别。引用[3]提供了一个读取二进制文件的例子,包括如何获取文件大小和一次读入整个文件。 我们将分步骤讲解: 1. 读写二进制文件的基本步骤。 2. 注意文本模式与二进制模式的区别(重点)。 3. 如何一次读取整个二进制文件(高效方法)。 4. 写入二进制文件的方法。 同时,我们将生成相关问题。 注意:在Windows和Linux下,二进制模式(`std::ios::binary`)是非常重要的,因为在文本模式下,Windows会将换行符`\n`转换为`\r\n`,而在Linux下则不会。同样,读取时也会进行反向转换。这会导致二进制数据被破坏,如引用[1]中所述。 ### 1. 读取二进制文件 以下是一个读取二进制文件的完整示例: ```cpp #include <fstream> #include <iostream> int main() { // 以二进制方式打开文件 std::ifstream infile("input.bin", std::ios::binary); if (!infile.is_open()) { std::cerr << "无法打开文件" << std::endl; return 1; } // 定位到文件末尾以获取文件大小 infile.seekg(0, std::ios::end); std::streamsize file_size = infile.tellg(); infile.seekg(0, std::ios::beg); // 回到文件开头 // 分配内存 char* buffer = new char[file_size]; // 读取整个文件 if (infile.read(buffer, file_size)) { // 成功读取,现在buffer中包含所有二进制数据 std::cout << "成功读取 " << file_size << " 字节" << std::endl; } else { std::cerr << "读取错误,仅读取了 " << infile.gcount() << " 字节" << std::endl; } // 关闭文件 infile.close(); // 处理buffer中的二进制数据... // 释放内存 delete[] buffer; return 0; } ``` ### 2. 写入二进制文件 写入二进制文件的示例: ```cpp #include <fstream> #include <iostream> int main() { // 准备一些二进制数据(示例:一个整数数组) int data[] = {1, 2, 3, 4, 5}; const std::streamsize data_size = sizeof(data); // 以二进制方式写入文件 std::ofstream outfile("output.bin", std::ios::binary); if (!outfile.is_open()) { std::cerr << "无法打开文件" << std::endl; return 1; } // 写入整个数组 if (outfile.write(reinterpret_cast<const char*>(data), data_size)) { std::cout << "成功写入 " << data_size << " 字节" << std::endl; } else { std::cerr << "写入错误" << std::endl; } // 关闭文件 outfile.close(); return 0; } ``` ### 重要注意事项 1. **模式选择**:读写二进制文件必须使用二进制模式(`std::ios::binary`),否则在Windows下会因换行符转换导致数据损坏[^1][^2]。 2. **跨平台问题**:二进制文件在不同平台间可能存在字节序(Endianness)差异,如需要跨平台使用,需考虑字节序转换。 3. **文件大小限制**:一次性读取整个文件要求文件大小不超过可用内存。对于大文件,应采用分块读写。 4. **类型安全**:使用`reinterpret_cast`需要确保类型转换的正确性,避免未定义行为。 ### 分块读写大文件 对于大文件,不宜一次性读入内存,可分批读写: ```cpp // 读取大文件(每次读取1MB) constexpr std::streamsize chunk_size = 1024 * 1024; char chunk[chunk_size]; while (infile.read(chunk, chunk_size)) { std::streamsize bytes_read = infile.gcount(); // 处理bytes_read字节的数据... } if (infile.eof()) { // 处理最后一块(小于chunk_size) std::streamsize last_chunk_size = infile.gcount(); // 处理last_chunk_size字节的数据... } ``` ### 总结 - 读二进制文件:打开文件(二进制模式)→读取(或分块读取)→关闭文件。 - 写二进制文件:打开文件(二进制模式)→写入→关闭文件。 - 关键点:避免文本模式操作二进制文件,防止数据损坏[^2]。 §§相关问题§§ 1. 如何在C++中处理大二进制文件的分块读写? 2. 如何解决跨平台二进制文件的字节序问题? 3. C++二进制文件操作有哪些常见错误及如何避免? 4. 如何将结构体直接写入二进制文件?需要注意什么? </think> ### C++ 读写二进制文件实现方法 #### 一、二进制文件读写核心要点 1. **模式选择** 必须使用 `std::ios::binary` 模式打开文件,避免系统自动转换特殊字符(如 Windows 将 `\n` 转 `\r\n`)[^1][^2]: ```cpp // 正确方式 std::ofstream outfile("data.bin", std::ios::binary); std::ifstream infile("data.bin", std::ios::binary); ``` 2. **数据类型处理** 二进制文件直接操作字节流,需使用 `reinterpret_cast` 转换数据类型: ```cpp int data = 12345; // 写入 outfile.write(reinterpret_cast<char*>(&data), sizeof(data)); // 读取 infile.read(reinterpret_cast<char*>(&data), sizeof(data)); ``` 3. **文本 vs 二进制模式差异** | 操作类型 | 文本模式 | 二进制模式 | |----------------|--------------------------|------------------------| | 换行符处理 | 自动转换(`\n` ↔ `\r\n`) | 原始字节 | | 数据类型 | 字符/字符串 | 任意数据类型 | | 文件结束符 | 可能添加 `EOF` | 无特殊字符 | | 适用场景 | 文本文件 | 图像/音频/结构体数据 | #### 二、完整读写流程(高效方法) ```cpp #include <fstream> // 写入二进制文件 void writeBinaryFile(const std::string& filename) { std::ofstream outfile(filename, std::ios::binary); if (!outfile) return; // 错误处理 // 示例数据(结构体+原始字节) struct DataBlock { int id; double value; } block{42, 3.14}; char rawBytes[] = {0xAA, 0xBB, 0xCC}; // 写入结构体 outfile.write(reinterpret_cast<char*>(&block), sizeof(block)); // 写入原始字节 outfile.write(rawBytes, sizeof(rawBytes)); } // 读取二进制文件(高效单次读取) void readBinaryFile(const std::string& filename) { std::ifstream infile(filename, std::ios::binary | std::ios::ate); if (!infile) return; // 错误处理 // 获取文件大小 const size_t file_size = infile.tellg(); infile.seekg(0, std::ios::beg); // 重置指针[^3] // 一次性读取全部数据 char* buffer = new char[file_size]; infile.read(buffer, file_size); // 解析数据 DataBlock* block = reinterpret_cast<DataBlock*>(buffer); char* rawData = buffer + sizeof(DataBlock); // 使用数据... delete[] buffer; // 释放内存 } ``` #### 三、跨平台注意事项 1. **字节序问题** 不同系统可能有不同字节序(大端/小端),处理网络传输数据时需转换: ```cpp #include <arpa/inet.h> // Linux #include <winsock2.h> // Windows uint32_t normalized = ntohl(original); // 网络字节序转本地 ``` 2. **结构体对齐** 使用 `#pragma pack` 消除平台差异: ```cpp #pragma pack(push, 1) // 1字节对齐 struct CrossPlatformStruct { char flag; int id; }; #pragma pack(pop) ``` 3. **文件路径差异** Windows 用 `\\`,Linux 用 `/`,建议使用 C++17 的 `std::filesystem`: ```cpp #include <filesystem> std::string path = std::filesystem::path("data").append("binary.bin").string(); ``` #### 四、最佳实践 1. **错误处理** 每次操作后检查流状态: ```cpp if (!infile.good()) { // 处理读取错误 } ``` 2. **大文件分块处理** 避免单次读取超大文件(内存映射更高效): ```cpp constexpr size_t CHUNK_SIZE = 4096; char chunk[CHUNK_SIZE]; while (infile.read(chunk, CHUNK_SIZE)) { // 处理当前数据块 } ``` 3. **RAII 管理资源** 使用智能指针避免内存泄漏: ```cpp auto buffer = std::make_unique<char[]>(file_size); infile.read(buffer.get(), file_size); ```
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值