【C++】标准库 - 文件的读写 ifstream, ofstream, fstream

news/2024/10/22 4:02:14/

【C++】标准库 - 文件的读写 ifstream, ofstream, fstream

文章目录

  • 【C++】标准库 - 文件的读写 ifstream, ofstream, fstream
    • 一、概述
    • 二、打开文件
      • 2.1 - ifstream 打开文件
      • 2.2 - ofstream 打开文件
      • 2.3 - fstream 以读取和写入的方式打开
    • 三、读取和写入文本文件
      • 3.1 - 读取文件内容
        • 3.1.1 - getline
        • 3.1.2 - get
        • 3.1.3 - >>
      • 3.2 - 写入文件
        • 3.2.1 - <<
        • 3.2.2 - put
    • 四、文件中的位置
      • 4.1 - 知悉指针当前的位置
      • 4.2 - 移动指针位置
    • 五、一些实用的方法
      • 5.1 - eof
      • 5.2 - ignore
      • 5.3 - clear
      • 5.4 - fail
    • 六、参考链接

一、概述


网上关于使用 C++ 读写文件的内容不是所期待的,所以来写一下。

无论是读文件还是写文件,首先需要打开文件,需要使用两个类

  • ifstream (Input File stream) 用于读取
  • ofstream (Output File stream) 用于写入

这两个类继承自 std::io_base 用于处理 io 流。

需要包含头文件

#include <fstream>

二、打开文件

2.1 - ifstream 打开文件


两种打开文件的方式,

  • 使用成员函数 open,有两个参数:
    1. 待打开的文件名
    2. 文件打开的模式
ifs.open("file.extension", openMode);
  • 不使用成员函数 open ,在构造时直接指定文件名与打开模式
ifstream ifs("file.extension", openMode);

指定文件路径有多种方式

  • 绝对路径 (完整路径,从硬盘的根目录出发),大概为以下格式:
// Windows 下
"C:/Documents and Settings/User/Desktop/file.txt"
// Linux 下
"/home/user/file.txt"
  • 相对路径 (从可执行文件 / exe 文件开始的路径),如果文件位于可执行文件下子目录 subdirectory 下则为
"subdirectory/file.txt"
  • 如文件位于可执行文件所在的目录,则需要直接指定文件名即可

打开模式也来自 ios_base 类,需要指定命名空间 ios_base::ios:: ,由于我们需要使用读取的模式所以为 ios::in 表示 input,输入。

打开后,需要确定是否打开,if (ifs)

操作结束后,需要关闭,使用成员函数 close,ifs.close()

代码示例

#include <iostream>
#include <fstream>using namespace std;int main(int argc, char* argv[])
{// 以读取方式打开ifstream ifs("test.txt", ios::in);if (ifs) // 确保文件是否打开成功{// 语句ifs.close(); // 关闭文件}else // 否则cerr << "Unable to open the file !" << endl;return 0;
}

当我们使用 ifstream 打开文件时,打开模式 ios::in 为可选内容,此选项为默认选项。

2.2 - ofstream 打开文件


使用 ofstream 以写入的方式打开文件,同样有两种方式,一种直接声明,一种使用函数 open ,与 ifstream 相同。

对于写入,文件的打开方式有很多。

文件打开方式速记说明
ios::outoutput (输出)指定文件的打开方式为写入,一般为必要参数,但在使用 ofstream 对象时,为默认参数
ios::appappend (添加)当打开文件用于写入时,会在已有数据之后写入,不覆盖原有内容。使用此种打开方式,每次写入都会置于文件末尾,即便之前更改了位置。
ios::trunctruncate (截断)当打开文件时,如果文件存在内容则清空文件内容
ios::ateat end (在结束处)以写入方式打开文件,并将文件指针置于末尾。与 ios::app 不同之处为,如果改变了指针位置,写入不一定会在文件末尾

对于这些写入文件的打开方式,如果文件不存在则会创建。

用于指定多个打开模式,使用操作符或 | 。英文发音为 pipe 。

代码示例:

#include <iostream>
#include <fstream>using namespace std;int main(int argc, char* argv[])
{ofstream ofs("test.txt", ios::out | ios::trunc); // 声明流与打开方式if (ofs) // 文件是否打开 {// 操作语句ofs.close(); // 关闭文件}else // 否则cerr << "Error to open file !" << endl;return 0;
}

2.3 - fstream 以读取和写入的方式打开

使用 fstream 可以以读写一起的方式打开文件,工作原理与 ifstream 和 ofstream 相同。

原型为

fstream flux("file.extension", ios::in|ios::out | [ios::trunc|ios::ate]);

中括号表示,需要使用两者中之一的打开方式

  • 这是唯一的办法用以读取和写入的方式打开文件
  • 中括号在实际代码中是不需要写的
  • ios::app 是不可以选择的打开方式,此种文件打开方式,只允许在写入时使用,而此处 fstream 用于读取和写入

使用此种打开方式,文件必须存在!ios::in|ios::out 必须指定,由于文件已经存在,打开时需要指定 ios::ate 用于保留原始内容,或指定 ios::trunc 用于清空内容。

ifsteam, ofstream, fstream 都支持多种字符串格式

// const char *
explicit basic_fstream(const char* _Filename, ios_base::openmode _Mode = ios_base::in | ios_base::out, int _Prot = (int) ios_base::_Openprot);// const string &
explicit basic_fstream(const string& _Filename, ios_base::openmode _Mode = ios_base::in | ios_base::out, int _Prot = (int) ios_base::_Openprot);// const wchar_t *
explicit basic_fstream(const wchar_t* _Filename, ios_base::openmode _Mode = ios_base::in | ios_base::out, int _Prot = (int) ios_base::_Openprot);// const wstring &
explicit basic_fstream(const wstring& _Filename, ios_base::openmode _Mode = ios_base::in | ios_base::out, int _Prot = (int) ios_base::_Openprot);//....

ios_base::_Openprot 为打开保护

#include <fstream>
#include <string>
using namespace std;int main(int argc, char* argv[])
{string my_file = "text.txt";fstream fs(my_file.c_str(), ios::in);if (fs) // 如果打开文件成功{// 操作语句fs.close(); // 关闭文件}else // 否则cerr << "Error to open file !" << endl;return 0;
}

三、读取和写入文本文件

3.1 - 读取文件内容


对于文件的读取,有多种不同的方法,如下

  • getline(stream, 字符串) :用于读取完整一行内容
  • stream.get(字符) :用于读取一个字符
  • stream >> 变量 :用于从文件中获取内容知道遇到分隔符 (空格,换行,…)

3.1.1 - getline


getline 需要两个参数,使用 ifstream 或 fstream 创建的流,和 用于存储内容的“目标”,通常为一个字符串,需要包含头文件 <string>

示例:

#include <iostream>
#include <string>
#include <fstream>using namespace std;
int main(int argc, char* argv[])
{ifstream ifs("test.txt", ios::in); // 以读取模式打开if (ifs){string context;getline(ifs, context); cout << context; // 显示行ifs.close();}elsecerr << "Unable to open the file !" << endl;return 0;
}

为了读取完整的文件,需要一行一行的读取,需要一个重复的循环,getline 会读取到文件结束

if (ifs)
{string line;while (getline(ifs, line)){cout << line << endl;}
}

getline 有一个重载方法,第三个参数为结束字符,这个结束字符的默认值为换行符 \n ,因此,我们可以一行一行的读取内容。

getline 只有在使用 ifstream 和 fstream 时有效,在 ofstream 时不再可用。

3.1.2 - get


get 函数用于读取一个字符,当然在使用循环的情况下,也可以读取完整的文件。

语法为

stream.get(character);

这个方法读取文件中的一个字符,然后将其存储在 char 类型的 character 变量中。

示例

#include <iostream>
#include <fstream>using namespace std;int main(int argc, char* argv[])
{ifstream ifs("test.txt", ios::in);if (ifs){char character; // 字符型变量用于存储读取的字符ifs.get(character);cout << character;ifs.close();}elsecerr << "Unbale to open the file !" << endl;return 0;
}

为了读取完整的文件,循环与 getline 相同。

3.1.3 - >>


这个符号应该不陌生,应该见到过与 cin 一起使用的情况,对于文件的运行原理也一样。这个操作符从文件中读取内容,直到遇到分隔符如空格或者换行符等。

比如一个文件中有以下内容

12 345
testSDZ

可见,文件中存在两个整数和两个字符串,若我们需要全部获取到,需要声明两个 int 和 两个 string

示例:

#include <iostream>
#include <string>
#include <fstream>using namespace std;
int main(int argc, char* argv[])
{ifstream ifs("test.txt", ios::in);if (ifs){int integer1, integer2;string string1, string2;ifs >> integer1 >> integer2 >> string1 >> string2;ifs.close();}elsecerr << "Unable to open the file !" << endl;return 0;
}

3.2 - 写入文件


写入文件也有多种方式

  • stream << 需要写入的内容; 向文件中写入一个任意的元素 (string, int …)
  • stream.put(字符); 向文件中写入单个字符

3.2.1 - <<


这个符号对于了解 C++ 的人来说不应算陌生,它被用于 cout ,对于文件功能与显示到标准输出基本一致。
此操作符允许向文件中写入字符,或字符串,或整数…

操作符的使用语法为

stream << element1 << element2 << ...;

如代码所示与 cout 的使用并无太多区别。代码示例:

#include <iostream>
#include <string>
#include <fstream>using namespace std;int main(int argc, char* argv[])
{ofstream ofs("test.txt", ios::out | ios::trunc);if (ofs){string name = "Zhangsan";int age = 23;ofs << "Birthday: " << 25 << '/' << 6 << '/' << 1998 << endl;ofs << "Hello, " << name << ", you are " << age << " years old.";ofs.close();}elsecerr << "Unable to open the file !" << endl;return 0;
}

我们向文件中写入 一些字符串,字符,一些整数和换行符。不需要显式声明类型,在使用时不用刻意区分,文本文件中内容如下:

Birthday: 25/6/1998
Hello, Zhangsan, you are 23 years old

3.2.2 - put


put 被较少使用,由于不像 << 一样,只接受一个字符
使用时,只需要替换上述写入部分的代码

if (ofs)
{char chr = 'X';ofs.put(chr);// 等价于 ofs.put('X');ofs.close();
}

四、文件中的位置


与 C 语言相似,也存在文件读写指针的概念,用于处理文件中的写入位置。

4.1 - 知悉指针当前的位置


为了知道我们当前在文件中所处的位置,需要知道打开的方式

如果使用 ifstream 打开,存在方法 tellg()

如果使用 ofstream 打开, 存在方法 tellp()

这两种方法,返回当前文件指针所在的位置,从文件开始的字节编号。

stream.tell[g | p];

4.2 - 移动指针位置


为了移动文件读写指针的位置,同样依赖文件的打开方式

如果使用 ifstream 打开

存在方法 seekg ,这个方法包含两个参数,第一个为字节的编号,第二个为从哪里开始计算这个编号,第二个参数可以为以下数值

  • ios::beg ,从文件开始处
  • ios::cur , 从当前文件读写指针处
  • ios::end , 从文件结尾处

默认值为 ios::beg

如果使用 ofstream 打开

方法几乎为同样的名称 seekp ,它的工作方式与 seekg 一致

stream.seek[g | p](10, ios::beg);

五、一些实用的方法


  • stream.eof() ,为了得知文件读写指针是否到达了文件尾;
  • stream.ignore(num, characterEnd) ,用于忽略 num 个字符,或忽略所有直到遇到指定的 characterEnd 字符;
  • stream.clear() ,用于将所有的标志位状态置为初始状态;
  • stream.fail() ,用于测试文件流的打开是否正常,可用于检测一个文件是否存在

标志位

英语为 flag ,即一个位,可以有两种值,0 或 1,对于 fstream 来讲,存在四个标志位,

  • goodbit
  • eofbit
  • failbit
  • badbit

5.1 - eof


这个方法返回一个布尔值,它会检查标志位 eofbit 是否为 true,即是否到达文件尾,否则为 false

eofbit 变为 true 的情况,要么是没有更多数据可以读取,要么是因为不能继续写入。

5.2 - ignore


这个方法需要两个参数,需要忽略的字符数量以及一个终止的字符。它将忽略掉第一个参数数量个字符,直到遇到第二个参数指定的字符。此种方法可以用作计算文件的行数。

但需要注意两点

  1. 用于计算行数,需要知道一行的字符数量
  2. 文件必须使用读取的模式打开

如果不提前知道文件的行数,也可以使用一种简便的方法,需要包含:

#inlcude <limits>
using namespace std;

在第一个参数处可以设置

numeric_limits<int>::max()

这个方法返回一个 int 最大能存储达的数值。一般为 2147483647

使用举例

stream.ignore(numeric_limits<int>::max(), '\n');

5.3 - clear


此方法用于重新置位 fstream 的四个标志位。

在文件读写指针到达文件尾时,eofbit 变为 true,如果此时需要回到文件首,如果不重新置位,则 eofbit 会一直处于 true 的状态,这时就会出问题

5.4 - fail


fail 方法用于实现 faibit 和 badbit 的检测,如果结果为 false,则表示文件流被正确创建,且打开成功。也保证了文件的存在

六、参考链接


  • https://openclassrooms.com/

http://www.ppmy.cn/news/729431.html

相关文章

测试面试题总结

测试面试题总结 一、对手机拍照测试用例的设计 快捷键能否拍照(比如苹果的音量键)&#xff1b;拍照时是否自动对焦&#xff1b;按下快门照片是否自动保存&#xff1b;能否连拍&#xff1b;能否识别单张/多张人脸&#xff1b;非静音模式下按下快门是否有快门声&#xff1b;是否…

测试—分类【修改版】

目录 测试分类按开发阶段划分单元测试集成测试系统测试验收测试 按实施组织划分α测试β测试第三方测试 按照是否运行划分静态测试动态测试 按是否手工划分手工测试自动化测试 按是否查看代码划分黑盒测试白盒测试灰盒测试 按地域划分国际化测试本地化测试 按测试对象划分界面测…

汽车操作系统的前世今生

随着阿里巴巴Alios和百度Apollo计划的轮番登台&#xff0c;“操作系统OperatingSystem” 似乎在一夜间成为了智能网联汽车的标配。事实真是如此吗&#xff1f;本文将简单的介绍下汽车操作系统的前世今生。 1、车载系统和电控系统 要谈汽车操作系统&#xff0c;首先得了解汽车…

85、 基于STM32单片机RFID刷卡签到考勤门禁系统无线蓝牙APP控制(程序+原理图+PCB源文件+参考论文+硬件设计资料+元器件清单等)

单片机主芯片选择方案 方案一&#xff1a;AT89C51是美国ATMEL公司生产的低电压&#xff0c;高性能CMOS型8位单片机&#xff0c;器件采用ATMEL公司的高密度、非易失性存储技术生产&#xff0c;兼容标准MCS-51指令系统&#xff0c;片内置通用8位中央处理器(CPU)和Flash存储单元&a…

iPhone 丢失后应该怎么办?我做了这5件事!

你每天会跟你的 iPhone 亲密相处多长时间&#xff1f; 雷锋网的编辑掐指一算&#xff0c;发现竟然超过了18个小时&#xff0c;属于重度手机依赖症患者~~~ 虽然我的 iphone 不是卖完肾才买的&#xff0c;但它俨然已经成为长在我身上的一个非常重要的器官&#xff0c;日常生活中&…

python安卓手机编程入门自学_编程入门学习路线(附教程推荐)

本文送给励志成为优秀程序员却无从下手的朋友们。 编程从来不是一件无趣的事情,相反,它会带给你无穷无尽的快乐。这是一种创造事物的快乐,就像上帝创造世间万物一样,在代码世界里,你就是无所不能的造物主。 可是如何以最快的速度入门,这才是广大新手最关心的问题。本文就…

Spring Boot 中的 Zookeeper 分布式锁

Spring Boot 中的 Zookeeper 分布式锁 分布式锁是分布式系统中常用的一个同步工具&#xff0c;它可以在多个进程之间协调访问共享资源&#xff0c;避免数据不一致或重复处理。在分布式环境中&#xff0c;由于网络通信的延迟和节点故障等原因&#xff0c;传统的锁机制无法满足需…

word转化为ftl格式文件模板,导出后office提示文件错误

需求如下: 使用模板,导出word文件,最近在做这个需求,本地环境用的是wps,结合本地的环境快速完成了开发需求之后,有一天客户发现office打开报错,本人深感不接,wps都能打开,各个在线文档也都支持,为何office就不支持,环境不同。 分析: wps是按照office版本迭代开发…