C++文件读写与操作

本文最后更新于:2021年1月28日 下午

概览:C语言与C++读写文件,简单操作事例。


代码全部运行于VS2017

文件分为两种:文本文件与二进制文件。

  • 文本文件:文件以ASCII码的形式存储在计算机中
  • 二进制文件:文件以二进制的形式存储在计算机中,一般不能直接读懂。

C语言读写文件

打开文件 - fopen

C语言使用fopen函数打开文件

fopen位于stdio.h中,

1
FILE *fopen( const char *filename, const char *mode );
  • filename是文件名
  • mode指文件访问模式

写文件 - fwrite

1
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

写入文件使用fwrite

  • buffer是指向写入对象的指针

  • size是要写入对象的大小

  • count 是要写入对象的数量

  • stream是文件流。

  • 返回值是成功写入的对象数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct Student {
int id;
int age;
char name[32];
bool gender;
unsigned int height;
};

Student stu[] = {

{
1,17,"lisa",true,179
},

{
2,18,"kaly",true,159
},

{
3,20,"luccy",true,109
},

};

FILE* fp = fopen("test.bin", "wb");//以二进制文件写

for (int i = 0; i < 3; i++)
{
fwrite(stu + i, sizeof(Student), 1, fp);
}

fclose(fp);//关闭流

读文件 - fread

1
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
  • buffer指存储对象的缓冲区。
  • 返回数据是成功读取的对象的数目。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FILE* fp = fopen("test.bin", "rb");

Student stus;

while (!feof(fp))
{
//fread 返回值是读到的对象数目,而不是字节
int bytes = fread(&stus, sizeof(stus), 1, fp);
if (bytes <= 0)
{
break;
}
printf("id=%d,age=%d,name=%s,sex=%s,height=%d\n", stus.id, stus.age, stus.name,
(stus.gender ? "male" : "famale"), stus.height);
}

fclose(fp);

其他函数

  • int feof(FILE *stream);:检查文件流是否达到末尾,到末尾为非零值,未到末尾为0.
  • int ferror(FILE *stream);:检查文件流是否发生错误。非零值表示发生错误,0表示未发生错误。

C++ 文件输入输出

fstream头文件中定义了三个类型来支持文件IO:

  • ifstream:从一个给定文件读取数据。

  • ofstream:向一个给定文件写入数据

  • fstream:可读写给定文件。

    这些类型提供的操作与cin以及cout操作一样,可以使用IO运算符(<<以及>>)来读写文件,使用getline来从一个ifstream中读取数据。

C++文件I/O基本流程

  1. 包含头文件fstream
  2. 创建流对象
  3. 打开文件,以各种方式打开文件
  4. 写/读数据
  5. 关闭流对象。

使用文件流对象

读写文件时,定义一个文件流对象,然后将对象与文件关联起来。

同时,每个文件流类都定义类一个名为open的成员函数,它会完成一些系统相关操作。

创建文件流对象时,文件名是可选的,如果提供文件名,那么open就会被自动调用。

1
2
ifstream in(ifile);	//构建一个ifstream并且打开给定文件
ofstream out; //输出文件流并未写入任何数据

文件流对象关联文件

对于定义的空文件流对象,可以使用open来将其与文件关联起来。

但是使用open有可能失败,所以加上检测是一个良好的习惯。

1
2
3
4
5
6
7
8
ofstream out;		//输出文件流并未写入任何数据
out.open(ifile + ".copy");

if(out) //检测是否open成功
{
//成功执行代码
如果open成功,open会设置流的状态,使good()为true
}

一旦一个文件流与一个文件关联,就会持续保持与对应文件的关联。

对一个已经打开的文件流调用open会失败,随后使用文件流操作都会失败。

要让文件流关联其他文件就要先close()。

当一个fstream对象离开其作用域的时候,与之关联的文件会自动关闭。当fstream对象被销毁时,close会自动被调用。

文件模式

  • ios::in:读
  • ios::out:写
  • ios::app:每次写操作前定位到文件末尾
  • ios::ate:打开文件后立即定位到文件末尾
  • ios::trunc:截断文件
  • ios::binary:以二进制方式进行IO

打开文件时,可以指定文件模式

  • 只有ofstream以及fstream可以设定out
  • 只有ifstream以及fstream可以设定in
  • 只有当out被设定时才能设定trunc
  • 只要trunc没被设定,就可以设定app
  • app模式下,即使没有显式指定out,文件也是用输出方式打开的
  • 默认情况下,以out模式打开,文件也会被截断。而为了保留out模式打开文件下的内容,必须同时指定app模式,这样会将数据追加写入道文件末尾,或者同时指定In,打开文件同时进行读写操作
  • ate与binary可用于任何类型的文件流对象下,且可以与其他任何文件模式组合使用。

以out模式打开文件,文件的内容会被丢弃。(截断指丢弃文件内容)

ofstream out("file")就是默认以out模式打开,直接会截断文件。

https://www.cnblogs.com/jianyungsun/archive/2011/02/19/1958587.html

普通方式读写文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void writeFile() {
//写文件
ofstream ofs; //创建流对象
ofs.open("person.txt",ios::out); //设置打开文件的方式

ofs << "你好,我来自火星" << endl; //给文件输出内容
ofs << "我来侵略地球了,需要宿主" << endl;

ofs.close(); //关闭文件流对象,释放资源
}

void readFile() {

ifstream ifs;
ifs.open("person.txt", ios::in);

if (!ifs.is_open()) {//若文件没有打开
cout << "文件打开失败" << endl;
return;
}

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

ifs.close();

}

读取文件的一些方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void readFile() {

ifstream ifs;
ifs.open("person.txt", ios::in);


//方式一:使用全局函数getline(std::istream,std::string)来读取
string buf;
while (getline(ifs, buf)) {
cout << buf << endl;
}

ifs.close();

}
//方法二:使用char数组接收
char buf[1024] = { 0 };
while (ifs >> buf) {
cout << buf << endl;
}

//方法三:使用流对象的getline(char* buf,std::streamsize count)来读取
char buf[1024] = { 0 };
while (ifs.getline(buf, sizeof(buf))) {
cout << buf << endl;
}


二进制方式读写文件

二进制方式写文件主要利用流对象调用成员函数write

函数原型 :ostream& write(const char * buffer,int len);

  • 字符指针buffer指向内存中一段存储空间。len是读写的字节数。

二进制方式读文件主要利用流对象调用成员函数read

函数原型:istream& read(char *buffer,int len);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Person {
public:
char m_name[64];
int m_age;
};

void bwrite()
{
ofstream out;
out.open("person.bin", ios::out | ios::binary); //没有文件就自动建立文件

Person p = { "Colourso", 20 };
Person p1 = { "www",19 };
Person p2 = { "IEEE",21 };

//将p的指针强转为char*
out.write((char*)&p,sizeof(p));
out.write((char*)&p1,sizeof(p1));
out.write((char*)&p2,sizeof(p2));

out.close();
}

void bread()
{
ifstream in;
in.open("person.bin", ios::in | ios::binary); //没有文件就打开失败

if (!in.is_open())
{
cout << "打开失败" << endl;
return;
}

Person p;

//指针类型强转
while (in.read((char*)&p, sizeof(p))) {
cout << p.m_name << " " << p.m_age << endl;
}


in.close();
}
  • 若Person类中m_name类型为string时,读取文件会发生一些错误……,暂时不知。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!