【STL】iostream 编程:文件输出流的成员函数


本文介绍文件输出流相关的成员函数,包括用法和示例。


目录

  • [1 概述](#1 概述)
  • [2 输出流的 open 成员函数](#2 输出流的 open 成员函数)
    • [2.1 新建文件](#2.1 新建文件)
    • [2.2 末尾追加](#2.2 末尾追加)
    • [2.3 复用流对象](#2.3 复用流对象)
    • [2.4 说明](#2.4 说明)
  • [3 put 函数](#3 put 函数)
  • [4 write 函数](#4 write 函数)
  • [5 seekp 与 tellp 函数](#5 seekp 与 tellp 函数)
  • [6 输出流的 close 成员函数](#6 输出流的 close 成员函数)
  • [7 错误处理函数](#7 错误处理函数)

1 概述

文件输出流的成员函数分为三类:

  1. 功能等同于流操纵符的成员函数;
  2. 执行无格式原始写入操作的成员函数;
  3. 用于修改流状态、不存在对应操纵符与插入运算符的成员函数;
    处理顺序式、带格式的文本输出时,仅使用插入运算符 << 和各类操纵符就足够。

若要对磁盘二进制文件执行随机读写,就需要使用其他专用成员函数,这类函数可以搭配插入运算符使用,也可以单独调用。

2 输出流的 open 成员函数

想要使用文件输出流 ofstream,必须在构造函数或者 open 函数中将流与某个磁盘文件绑定

如果使用 open 函数,同一个流对象可以先后绑定多个不同文件。两种绑定方式所传入的文件相关参数完全一致。

打开输出流关联的文件时,通常需要指定打开模式标志。这些标志是定义在 ios 类中的枚举常量,可通过按位或运算符 | 组合使用。
下面介绍输出流中三个最常用的场景,对应不同打开模式:

2.1 新建文件

新建文件,若文件已存在则直接删除原有内容:

cpp 复制代码
ofstream ofile("FILENAME");
// Default is ios::out

ofstream ofile("FILENAME", ios::out);
// Equivalent to above

2.2 末尾追加

向已有文件末尾追加内容,文件不存在则自动创建:

cpp 复制代码
ofstream ofile("FILENAME", ios::app);

2.3 复用流对象

同一个流先后打开多个文件:

cpp 复制代码
ofstream ofile();
ofile.open("FILE1", ios::in);
// Do some output
ofile.close();    // FILE1 closed
ofile.open("FILE2", ios::in);
// Do some more output
ofile.close();    // FILE2 closed
// When ofile goes out of scope it is destroyed.

2.4 说明

  1. 默认模式 ios::out
    • 只写模式,打开文件时直接清空原有内容,适合覆盖重写;
  2. ios::app 追加模式
    • 所有写入操作强制在文件尾部执行,不会覆盖原有数据;
  3. 复用流对象流程
    • open() 绑定文件→文件IO→ close() 释放文件句柄→再次 open() 绑定新文件;
  4. RALL 自动关闭
    • 对象离开作用域析构时,会自动调用 close(),无需手动关闭;
  5. 模式组合示例
    • ios::out | ios::binary:二进制覆盖写入;
    • ios::app | ios::binary:二进制追加写入;

3 put 函数

put 函数将一个字符写入到输出流

默认情况下,以下两个语句相同,但第二个受流的格式化参数的影响:

cpp 复制代码
cout.put('A');

// Exactly one character written
cout <<'A'; // Format arguments 'width' and 'fill' apply

说明

  1. cout.put(ch)
    • 属于无格式原始输出函数,完全无视 setw、对齐、填充字符这类格式化配置,只原样输出这一个字符,不会补充任何填充空位。
  2. cout << ch
    • 格式化插入运算符,会先检查当前流的宽度、填充规则;
    • 如果设置了输出宽度,会自动在字符前后补填充符;

4 write 函数

write 函数将一块内存数据写入文件输出流,长度参数用于指定要写入的字节总数

下面示例创建文件输出流,并把 Date 结构体的二进制原始数据写入文件:

cpp 复制代码
// write_function.cpp
// compile with: /EHsc
#include <fstream>
using namespace std;

struct Date
{
	int mo, da, yr;
};

int main()
{
	Date dt = { 6, 10, 92 };
	ofstream tfile("date.txt", ios::binary);
	tfile.write((char*)&dt, sizeof dt);
}

说明

  1. 核心特性:
    • write 遇到空字符 \0 不会停止写入,能完整写出整个结构体内存块
    • write 属于无格式二进制写入,完全不触发任何格式化逻辑,不会截断于 \0,适合结构体、数组等整块内存持久化。
  2. 参数解析:
    • 第一个参数:内存起始地址,必须转为 char*;
    • 第二个参数:总字节数,通常用 sizeof(结构体/变量) 获取;
  3. 强制要求二进制模式 ios::binary:
    • 如果不开启二进制标志,文本模式会自动转换换行符,破坏结构体二进制数据,读取时会解析出错。
  4. 和 put(ch) 区别
    • put(ch):单次只写 1 个字节;
    • write(buf, len):一次性写入任意长度连续内存块;

5 seekp 与 tellp 函数

文件输出流内部维护一个写入指针,该指针标记下一段数据将要写入的文件位置

  • 成员函数 seekp 用于修改这个写入指针,以此实现磁盘文件的随机写入功能;

  • 成员函数 tellp 用来获取当前写入指针所处的文件偏移位置;

  • 输入流中存在功能对应的 seekg、tellg 函数;
    命名含义:

  • p = put,代表写入,仅用于 ofstream / fstream;

  • g = get,代表读取,仅用于 ifstream / fstream;
    作用:

  • tellp():返回当前写入位置的字节偏移量(文件流位置类型 streampos);

  • seekp(偏移量, 基准位置):跳转写入指针,支持三种基准:

    • ios::beg:文件开头
    • ios::cur:当前指针位置
    • ios::end:文件末尾
      使用场景 :二进制文件局部覆盖写入,跳过指定长度、修改文件中间某段数据。必须搭配 ios::binary 打开,文本模式下换行符转换会导致偏移计算错乱。

示例代码如下所示

cpp 复制代码
// write_function.cpp
// compile with: /EHsc
#include <fstream>
using namespace std;

int main()
{
	ofstream file("data.bin", ios::out | ios::binary);
	int num = 123;
	// 写入4字节整数
	file.write((char*)&num, sizeof(int));

	// 获取当前写入位置
	streampos pos = file.tellp();

	// 跳回文件开头,覆盖重写
	file.seekp(0, ios::beg);
	int newNum = 456;
	file.write((char*)&newNum, sizeof(int));
}

6 输出流的 close 成员函数

close 成员函数关闭与文件输出流绑定的磁盘文件。必须关闭文件,缓冲区所有待写入的数据才会完整落地到磁盘。

  • 必要时 ofstream 的析构函数会自动帮你关闭文件;但如果你需要用同一个流对象打开另一个文件,就必须手动调用 close。
  • 仅当文件是通过流的构造函数或 open 成员函数打开时,输出流析构函数才会自动关闭文件。
  • 如果你在构造函数传入一个已经打开的文件描述符,或是使用 attach 成员函数绑定外部文件,此时必须显式调用 close 关闭文件,析构不会自动处理。
    调用 close() 会强制刷新缓冲区,把内存中缓存的写入数据全部写入磁盘,再释放文件句柄。

7 错误处理函数

写入流时,可使用以下成员函数检测错误状态:

函数 返回值说明
bad 发生不可恢复的严重错误时返回 true
fail 出现不可恢复错误,或是常规预期故障(类型转换失败,文件不存在等)时返回 true;调用 clear(0) 清除状态后通常可继续执行 IO
good 无任何错误标记、且未设置文件结束标记时返回 true
eof 读到文件末尾时返回 true
clear 修改流内部错误状态;无参默认调用会清空所有错误标记
rdstate 返回当前完整的错误状态掩码
  • 流重载了 ! 运算符,功能等价于 fail():
cpp 复制代码
if(!cout)
// 等价于
if(cout.fail())
  • 同时重载了 void* 转换运算符,逻辑与 ! 相反:
    • void* 转换判断不等同于 good(),因为它不会校验文件结束标记 eof。
cpp 复制代码
if(cout)
// 等价于
if(!cout.fail())

说明

  1. 错误标记层级关系
    • badbit:硬件/底层致命错误,bad() 单独检测该位;
    • failbit:转换、打开文件等常规失败,fail() 同时检测 badbit+failbit;
    • eofbit:仅文件末尾标记,good() 要求 badbit、failbit、eofbit 全部置0;
  2. 三种判断方式区别
    • if(stream):仅判断 !fail(),忽略 eof 状态;
    • if(!stream):等同于 stream.fail();
    • if(stream.good()):最严格,无错误且未到文件末尾。
  3. 错误恢复流程
    1. 流一旦触发 fail / bad。后续所有读写操作都会静默失效;
    2. 调用 stream.clear() 清空错误标记后,才能恢复正常 IO;
相关推荐
Huangjin007_1 小时前
【C++11篇(四)】新的类功能、lambda 与包装器详解
开发语言·c++
哥不想学算法10 小时前
【C++】字符串字面量拼接
开发语言·c++
cookies_s_s15 小时前
C++ 字符串动态创建对象 -- 工厂模式、自动注册、模板递归动态调用
服务器·开发语言·c++
王老师青少年编程15 小时前
2026年6月GESP真题及题解(C++七级):消消乐
数据结构·c++·算法·真题·gesp·2026年6月
海清河晏11116 小时前
数据结构 | 二叉搜索树
数据结构·c++·visual studio
盐焗鹌鹑蛋16 小时前
【C++】继承
开发语言·c++
会周易的程序员17 小时前
使用 pybind11 封装 C++ 日志库 microLog 为 Python 模块
java·c++·python·物联网·架构·日志·aiot
WZF-Sang17 小时前
网络基础——2
服务器·网络·c++·学习·网络编程·php
-西门吹雪19 小时前
现代C++ 并发编程-学习指南
java·jvm·c++