当前位置:   article > 正文

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

ifstream读取文件

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

一、概述


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

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

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

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

需要包含头文件

#include <fstream>
  • 1

二、打开文件

2.1 - ifstream 打开文件


两种打开文件的方式,

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

指定文件路径有多种方式

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

打开模式也来自 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

当我们使用 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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

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

原型为

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

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

  • 这是唯一的办法用以读取和写入的方式打开文件
  • 中括号在实际代码中是不需要写的
  • 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);

//....
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

三、读取和写入文本文件

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();
	}
	else
		cerr << "Unable to open the file !" << endl;
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

if (ifs)
{
	string line;
	while (getline(ifs, line))
	{
		cout << line << endl;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

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

3.1.2 - get

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

语法为

stream.get(character);
  • 1

这个方法读取文件中的一个字符,然后将其存储在 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();
	}
	else
		cerr << "Unable to open the file !" << endl;
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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

3.1.3 - >>

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

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

12 345
test

SDZ
  • 1
  • 2
  • 3
  • 4

可见,文件中存在两个整数和两个字符串,若我们需要全部获取到,需要声明两个 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();
	}
	else
		cerr << "Unable to open the file !" << endl;

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3.2 - 写入文件


写入文件也有多种方式

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

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

操作符的使用语法为

stream << element1 << element2 << ...;
  • 1

如代码所示与 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();
	}
	else
		cerr << "Unable to open the file !" << endl;
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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

Birthday: 25/6/1998
Hello, Zhangsan, you are 23 years old
  • 1
  • 2
3.2.2 - put

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

if (ofs)
{
	char chr = 'X';
	ofs.put(chr);
	// 等价于 ofs.put('X');
	
	ofs.close();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

四、文件中的位置


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

4.1 - 知悉指针当前的位置


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

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

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

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

stream.tell[g | p];
  • 1

4.2 - 移动指针位置


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

如果使用 ifstream 打开

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

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

默认值为 ios::beg

如果使用 ofstream 打开

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

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

五、一些实用的方法


  • 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;
  • 1
  • 2

在第一个参数处可以设置

numeric_limits<int>::max()
  • 1

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

使用举例

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

5.3 - clear


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

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

5.4 - fail


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

六、参考链接


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/300517
推荐阅读
相关标签
  

闽ICP备14008679号