绪言
文件操作是C++实用程序设计的重要手段,它通常出现在需要保存日志时,一些信奥选手可能也会接触到文件操作。
本文将尽可能介绍与文件操作相关的所有常见函数,带你一文了解文件操作。
前置知识
与文件操作的相关函数分为两种,一种定义在头文件<stdio.h>
(C++<cstdio>
)中,包含文件格式化输入输出和基本输入输出函数;另一种定义在头文件<iostream>
和<fstream>
中,称为文件流输入输出函数。
以下是几个在头文件中定义的基本类型:
size_t
类型:无符号整数类型,用于反映一个对象的长度、大小等。fpos_t
类型:文件位置类型,用于反映对当前存储文件进行操作的位置(可以理解为当前光标的位置)FILE
类型:文件流类型,存储一个文件。这个类型虽然不常用,但我们常用FILE*
类型来存储一个指向文件的指针。
以下是几个定义在头文件<stdio.h>
中的宏:
NULL
和nullptr
:在C++中NULL
的声明:#define NULL 0
,即NULL
就代表0
,而并不是单纯的空指针。而nullptr
这个在C++11中新加入的关键字是一个纯粹的空指针。EOF
:在C++中EOF
的声明:#define EOF (-1)
,即EOF就代表-1
,一般用于描述当前光标已经到达文件结尾。SEEK_SET
、SEEK_CUR
和SEEK_END
:这是三个int
类型的常量,用于fseek()
函数,分别代表文件开头位置、光标位置、文件结尾位置。
文件流输入输出:<iostream>
头文件和<fstream>
头文件
头文件定义的类型
在<fstream>
头文件中定义了三个新的文件流类类型:
类型名 | 描述 |
---|---|
ofstream | 表示输出文件流,用于创建文件、向文件写入数据 |
ifstream | 表示输入文件流,用于从文件读取数据 |
fstream | 通用文件流,即既可以写入数据,也可以读取数据 |
请注意:上面的三个类型都是类!
打开和关闭文件:open()
和close()
打开文件open()
open()
函数是上述三个类的成员函数。它的声明如下:
void open(const char* _Filename, std::ios_base::open_mode _Mode);
其中,_Filename
是文件名,_Mode
是下列几种文件打开方式参数之一:
名称 | 描述 |
---|---|
ios::app | 追加模式。只能在文件末尾写入数据。 |
ios::ate | 默认设置。将光标默认到文件末尾。 |
ios::in | 读入模式。只能从文件中读取数据。 |
ios::out | 输出模式。只能向文件写入数据。 |
ios::trunc | 清空模式。在打开文件前清空文件。 |
上述的几种模式可以组合使用,例如:
ofstream a;
a.open("test.cpp", ios::in | ios::out);
即用读写模式打开文件。
同时也可以不指定打开模式,则打开模式会被设置为默认值。
关闭文件close()
类似地,close()
也是上述三个类的成员函数。它的声明如下:
void close();
它的使用也很简单:
int main()
{
ofstream a;
// main function body
a.close();
}
文件读写
使用文件流输入输出也可以使用<<
和>>
运算符。唯一不同的是,这里cin
和cout
要替换成ofstream
和ifstream
对象,向文件进行流输入输出。以下是一个实例:
#include <cstdio>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream outfile;
ifstream infile;
infile.open("test.in");
outfile.open("test.out");
string t;
infile >> t;
outfile << t << endl;
infile.close();
outfile.close();
return 0;
}
我们事先在文件test.in
中写入了以下内容:
This is a testing text.
则运行上面的代码,文件test.out
将会被创建并包含以下内容:
This is a testing text.
判断打开成功与否:is_open()
is_open()
函数返回描述当前文件是否打开成功的布尔值。如果打开成功,则返回true
;否则返回false
。
重新定位文件光标位置:seekp()
和seekg()
seekg()
函数是类ifstream
的成员函数,seekp()
函数是类ofstream
的成员函数,fstream
,fstream
类则兼有两个函数。这两个函数负责重新定位文件操作位置,即移动光标。假设有一个类型为ifstream
的对象f
,以下以seekg()
为例:
f.seekg(n)
:把光标从文件开头向后移n
个字节。f.seekg(n, ios::cur)
:把光标从当前位置向后移n
个字节。f.seekg(n, ios::end)
:把光标从文件结尾向前移n
个字节。
文件格式化、基本输入输出:<stdio.h>
头文件和<cstdio>
头文件
打开和关闭文件:fopen()
和fclose()
fopen()
函数
fopen()
函数返回一个指向文件的指针。它的声明如下:
FILE* fopen(const char* _Filename, const char* _Mode);
其中,_Filename
是文件名,_Mode
是一个字符串,表示文件打开模式,属于下面几种类型之一:
- r 只读。该文件必须存在。
- r+ 读写。该文件必须存在。
- rb+ 读写二进制文件。
- rt+ 读写。
- w 只写。若文件存在则覆盖,若文件不存在则建立文件。
- w+ 读写。若文件存在则覆盖,若文件不存在则建立文件。
- a 追加只写。若文件不存在则会建立文件。写入的数据会被加到文件尾。(EOF符保留)
- a+ 追加读写。若文件不存在则会建立文件。写入的数据会被加到文件尾。(原来的EOF符不保留)
- wb 只写二进制文件。
- wb+ 读写二进制文件。若文件存在则覆盖,若文件不存在则建立文件。
- wt+ 读写。若文件存在则覆盖,若文件不存在则建立文件。
- at+ 读+追加。写入的数据会被加到文件尾。
- ab+ 读+追加二进制文件。写入的数据会被加到文件尾。
fclose()
函数
关闭文件。它的声明如下:
void fclose(FILE* _Stream);
其中,_Stream
是一个指向文件的指针。
读写:fscanf()
和fprintf()
这两个函数用法与scanf()
、printf()
相同,只需要在所有参数前加上一个指向文件的指针即可。
读写:fgetc()
和fputc()
这两个函数用法与getchar()
、putchar()
相同,只需要在所有参数之后加上一个指向文件的指针即可。
读写:fgets()
和fputs()
fgets()
函数
用于从文件中读取一行。它的声明如下:
char* fgets(char* _Buffer, int _MaxCount, FILE* _Stream);
其中,_Buffer
是存储读取内容的字符串,_MaxCount
是最大读取数(一般是字符串长度,切记要大于等于文件一行的长度),_Stream
是指向目标文件的指针。
fputs()
函数
用于向目标文件输出一行。它的声明如下:
int fputs(const char* _Buffer, FILE* _Stream);
其中,_Buffer
是要输出的字符串,_Stream
是指向目标文件的指针。
读写:fread()
和fwrite()
它们的声明如下:
size_t fread(void* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE* _Stream);
size_t fwrite(const void* _Buffer, size_t _ElementSize, size_t _ElementCount, FILE* _Stream);
其中,_Buffer
是目标数据的地址;_ElementSize
是单个数据块字节长度,_ElementCount
是数据块数量,二者相乘应该等于数据的大小;_Stream
是指向目标文件的指针。
ftell()
函数
返回当前文件的光标位置。它的声明如下:
long ftell(FILE* _Stream)
fseek()
函数
移动当前文件的光标位置。它的声明如下:
int fseek(FILE* _Stream, long _Offset, int _Origin);
假设fp
是一个FILE*
类型的指针。
fseek(fp,n,SEEK_SET)
:把光标从文件开头向后移n
个字节。fseek(fp,n,SEEK_CUR)
:把光标从当前位置向后移n
个字节。fseek(fp,n,SEEK_END)
:把光标从文件结尾向前移n
个字节。
重置光标:rewind()
把目标文件的光标移到文件的开头。它的声明如下:
void rewind(FILE* _Stream);
其中,_Stream
是一个指向目标文件的指针。
总结/小注
限于篇幅,这里不再给出多余的实例,感兴趣的读者可以自行尝试。希望大家多多点赞关注支持!