【STL】iostream 编程:二进制输出文件


本文介绍一下二进制输出文件的规则及其作用。


目录

  • [1 概述](#1 概述)
  • [2 二进制输出](#2 二进制输出)
  • [3 示例](#3 示例)
  • [4 说明](#4 说明)

1 概述

流最初是为文本处理设计的,因此文件输出默认采用文本模式在文本模式下,写入时单个换行符 \n 会自动扩展为 Windows 系统的回车 + 换行双字符 \r\n。这种自动转换会破坏二进制数据,示例如下:

cpp 复制代码
// binary_output_files.cpp
// compile with: /EHsc
#include <fstream>
using namespace std;
int iarray[2] = { 99, 10 };
int main( )
{
    ofstream os( "test.dat" );
    os.write( (char *) iarray, sizeof( iarray ) );
}

开发者预期输出字节序列:{99,0,10,0};

但文本模式下实际写入:{99,0,13,10,0},多插入了回车符 \r,后续读取二进制数据的程序会解析出错。

2 二进制输出

如果需要纯粹的二进制输出、字节原样写入不做任何字符转换,构造 ofstream 时传入 ios_base::binary 打开模式标志:

cpp 复制代码
// binary_output_files2.cpp
// 编译参数:/EHsc
#include <fstream>
using namespace std;
int iarray[2] = { 99, 10 };

int main()
{
   ofstream ofs ( "test.dat", ios_base::binary );
   // 精确写入8个字节,无任何字符转译
   ofs.write( (char*)&iarray[0], sizeof(int)*2 );
}

3 示例

下述示例分别通过文本模式和二进制模式写入,然后二进制模式读取查看区别,文本模式读取查看区别:

cpp 复制代码
// binary_output_files.cpp
// 编译参数:/EHsc
#include <fstream>
#include <iostream>
using namespace std;

int iarray[2] = { 99, 10 };

int main()
{
    //文本模式写入(无ios::binary)
    {
        ofstream os("test.dat");
        os.write((char*)iarray, sizeof(iarray));
        os.close();

        //二进制读取
        ifstream is("test.dat", ios::binary);
        char buf[16] = { 0 };
        is.read(buf, sizeof(buf));
        is.close();

        //逐字节打印十六进制,观察多出0x0D(13)
        cout << "文件内字节(十六进制):" << endl;
        for (int i = 0; i < sizeof(iarray) + 2; i++)
        {
            printf("%02X ", (unsigned char)buf[i]);
        }
        cout << endl;

        //文本模式读取
        int readArr[2] = { 0 };
        ifstream textIn("test.dat");
        textIn.read((char*)readArr, sizeof(readArr));
        textIn.close();

        cout << "预期数组:[99, 10]" << endl;
        cout << "文本模式读回:[" << readArr[0] << ", " << readArr[1] << "]" << endl;
    }

    //二进制模式写入(ios::binary)
    {
        ofstream os("test2.dat", ios::binary);
        os.write((char*)iarray, sizeof(iarray));
        os.close();

        //二进制读取
        ifstream is("test2.dat", ios::binary);
        char buf[16] = { 0 };
        is.read(buf, sizeof(buf));
        is.close();

        //逐字节打印十六进制,观察多出0x0D(13)
        cout << "文件内字节(十六进制):" << endl;
        for (int i = 0; i < sizeof(iarray) + 2; i++)
        {
            printf("%02X ", (unsigned char)buf[i]);
        }
        cout << endl;

        //文本模式读取
        int readArr[2] = { 0 };
        ifstream textIn("test2.dat");
        textIn.read((char*)readArr, sizeof(readArr));
        textIn.close();

        cout << "预期数组:[99, 10]" << endl;
        cout << "文本模式读回:[" << readArr[0] << ", " << readArr[1] << "]" << endl;
    }

    return 0;
}

运行结果:

很明显,二进制读取的时候是有问题的,但是文本模式写入二进制模式读取本身逻辑上就不通畅,所以什么方式写入什么方式读取不就好了。

4 说明

  1. 文本模式转换规则(仅 Windows 平台生效)
    • 写入:内存中的 \n (0x0A)自动变成 \r\n (0x0D 0x0A)存入文件;
    • 读取:文件里连续的 \r\n 自动还原为单个 \n;
      • Linux / macOS 无此转换,文本、二进制模式行为一致;
  2. 二进制模式核心作用
    • 添加 ios_base::binary 后,所有字节原样落地,不会插入、替换任何换行相关字符,适合结构体、数组、图片、程序等二进制数据持久化。
  3. 风险场景
    • 使用 write() 序列化数字、结构体时,必须加 binary,否则数值中出现 0x0A 就会多出 0x0D,字节长度错乱,读取数据完全失真。
相关推荐
_Twink1e19 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
dong_junshuai20 小时前
每天一个开源项目#87 fmt:24.5K Stars 的 C++ 格式化核心
c++·开源·github
雪的季节21 小时前
Multisim14.0的详细中文安装步骤【附安装包】
c++
Persistent的粽子!1 天前
C++:类与对象(二)
开发语言·c++
蒸蒸yyyyzwd1 天前
cpp 选手备战秋招学习笔记 day23
c++·求职招聘
.YM.Z1 天前
C++ STL 容器深度剖析:vector 与 list 的模拟实现及对比
开发语言·c++·vector·list
mengzhi啊1 天前
QEventLoop loop配合loop.exec();替代while(1)。电脑cpu占用为0,使用while(1)cpu占用率100%
c++·qt
HugoStudio_SWAN1 天前
洛谷 P1319 / P1320 压缩技术——同一枚硬币的正反面
c++·学习·程序人生·算法
小小晓.1 天前
C++单例模式万字详解:6种实现演进+线程安全彻底解决+CRTP终极模板
c++·单例模式
j7~1 天前
【C++11】C++11 新特性全套详解(列表初始化、右值引用、lambda 表达式、function 与 bind 包装器等)
c++·右值引用·lambda表达式·可变参数模板·移动语义·包装器·c++11发展史