c++读取写入数据



前言

对学习C/C++感兴趣的小伙伴可以看看这篇文章哦:C/C++教程

本章主要详解C/C++对文件的所有常见方法汇总

先要明白一个概念,即几乎在所有编程语言中,文件处理都是一个非常重要的模块

因为文件可以实现对数据大量且长久的存储

一、文件处理过程

无论什么编程语言,处理文件的过程都可以分为以下三步:

  1. 打开文件
  2. 操作文件
  3. 关闭文件

所以当我们操作文件的时候,请务必牢记这三点,因为该逻辑几乎是所有语言通用的,只不过具体实现细节略有差异

二、C处理文件

首先来看C中处理文件的方式,因为C是面向过程的语言,所以使用起来较为繁琐,你需要记住很多函数

而这些函数所在的头文件为:

1
#include<cstdio> //或者#include<stdio.h>均可

同时需要注意的是:

C语言库中的函数,很多都存在安全隐患,就会存在一个相应的安全函数,一般对应的安全函数名称都是在原函数后添加_s后缀

例如:fopen的安全函数为fopen_s

相比较而言,安全函数会比标准函数使用更繁琐,所以很多情况下我们会习惯于使用标准函数,

但在VS环境下直接使用不安全的函数,会直接报错,编译无法通过,此时就必须要定义对应的宏才能正常使用

而安全函数则无需定义任何宏,可直接使用

具体使用哪一种看个人习惯,官方推荐使用安全函数

1.打开文件

首先是打开文件的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//标准函数:
FILE* fopen(
const char * _FileName,//要打开的文件名,不指定路径,则在当前文件夹找
const char * _Mode //打开的模式 读r 写w 或追加a
);
//返回值:打开失败返回NULL,打开成功则返回指向文件的标识符

//安全函数
errno_t fopen_s(
FILE** _Stream, //保存打开文件后的标识符
const char * _FileName, //要打开的文件名,不指定路径,则在当前文件夹找
const char * _Mode //打开的模式 读r 写w 或追加a
);
//返回值:打开成功返回0,打开失败则返回对应错误代码

两种函数的使用区别:

1
2
3
4
5
6
7
8
9
#define _CRT_SECURE_NO_WARNINGS //vs环境下,必须定义该宏,否则报错
#include<cstdio>
using namespace std;
int main() {
FILE* file = fopen("1.txt","r"); //以读的方式打开文件
if (file == NULL) { //file为NULL,则打开文件失败,退出程序
return -1;
}
}
1
2
3
4
5
6
7
8
9
#include<cstdio>
using namespace std;
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","r"); //以读的方式打开文件
if (err != 0) { //err不为0,则打开文件失败,退出程序
return -1;
}
}

对于mode参数,有如下选择:
在这里插入图片描述

2.读文件

然后就是文件操作中的读:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//标准函数:
size_t fread(
void* _Buffer, //读取到的内容存放空间
size_t _ElementSize, //每次读多少个字节
size_t _ElementCount, //读多少次
FILE* _Stream //文件标识符
);
//返回值:实际读取的次数,注意,实际的取得字节数应该是该返回值和_ElementSize参数相乘,所以一般_ElementSize参数填1

//安全函数:
size_t fread_s(
void* _Buffer,//读取到的内容存放空间
size_t _BufferSize, //第一个参数指示的缓存区大小
size_t _ElementSize,//每次读多少个字节
size_t _ElementCount,//读多少次
FILE* _Stream //文件标识符
);
//返回值:实际读取的次数,注意,实际的取得字节数应该是该返回值和_ElementSize参数相乘,所以一般_ElementSize参数填1

两者使用区别:

1
2
3
4
5
6
7
8
9
10
11
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
using namespace std;
int main() {
FILE* file = fopen("1.txt","r"); //以读的方式打开文件
if (file == NULL) { //file为NULL,则打开文件失败,退出程序
return -1;
}
char buf[0xFF]; //定义存放读取内容的缓存区
size_t size=fread(buf,1,100, file); //每次读一个字节,读100次
}
1
2
3
4
5
6
7
8
9
10
11
#include<cstdio>
using namespace std;
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","r"); //以读的方式打开文件
if (err != 0) { //err不为0,则打开文件失败,退出程序
return -1;
}
char buf[0xFF]; //定义存放读取内容的缓存区
size_t size=fread_s(buf,sizeof(buf),1,100,file);//每次读一个字节,读100次
}

除了上面最基本的读文件数据函数,还有一些其它读操作的函数:

  1. fgetc:从文件中读取一个字符
1
2
3
4
int fgetc(
FILE* _Stream //文件标识符
);
//返回值:返回读取到的一个字符
1
2
3
4
5
6
7
8
9
10
#define _CRT_SECURE_NO_WARNINGS //vs环境下必须定义该宏,否则报错
#include<cstdio>
using namespace std;
int main() {
FILE* file = fopen("1.txt","r"); //已只读方式打开
if (file == NULL) { //打开失败直接返回
return -1;
}
char c=fgetc(file); //读取一个字符
}
  1. fgets:从文件中读取一个字符串
1
2
3
4
5
6
char* __cdecl fgets(
char* _Buffer, //存放读到的字符缓冲区
int _MaxCount, //该缓存区的大小
FILE* _Stream //文件标识符
);
//返回值:成功为_Buffer指针,失败为NULL

使用:

1
2
3
4
5
6
7
8
9
10
11
#define _CRT_SECURE_NO_WARNINGS //vs环境下必须定义该宏,否则报错
#include<cstdio>
using namespace std;
int main() {
FILE* file = fopen("1.txt","r"); //已只读方式打开
if (file == NULL) { //打开失败直接返回
return -1;
}
char buf[0xFF];
fgets(buf,0xFF,file); //读取一行字符串
}
  1. fscanf:按格式从文件中读取指定内容,与scanf函数类似
1
2
3
4
5
int fscanf(
FILE* const _Stream,//文件标识符
char const* const _Format, //指定读取格式,与printf格式相同
... //存放读取内容的缓存区
)

使用:

1
2
3
4
5
6
7
8
9
10
11
12
#define _CRT_SECURE_NO_WARNINGS //vs环境下必须定义该宏,否则报错
#include<cstdio>
using namespace std;
int main() {
FILE* file = fopen("1.txt","r"); //已只读方式打开
if (file == NULL) { //打开失败直接返回
return -1;
}
int d; //存放数字
char buf[0xFF]; //存放字符串的缓存区
fscanf(file,"%d %s",&d,buf); //按格式读取文件内容
}
  1. fscanf_sfscanf的安全函数,作用相同
1
2
3
4
5
int fscanf_s(
FILE* const _Stream,//文件标识符
char const* const _Format, //指定读取格式,与printf格式相同
... //存放读取内容的缓存区,注意在每个缓存区大小后一个参数为该缓存区的大小
)

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<cstdio>
using namespace std;
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","r");
if (err != 0) {
return -1;
}
int b;
char buf[0xFF];
fscanf_s(file,"%d %s",&b,buf,sizeof(buf));
fclose(file);
}

4.写文件

文件操作主要就两个,上面说了读,下面就是写了:

标准函数:

1
2
3
4
5
6
size_t fwrite(
void const* _Buffer, //要写入的内容
size_t _ElementSize, //元素大小
size_t _ElementCount, //元素个数
FILE* _Stream //文件标识
);

使用:

1
2
3
4
5
6
7
8
9
10
11
#define _CRT_SECURE_NO_WARNINGS //vs环境下必须定义该宏,否则报错
#include<cstdio>
using namespace std;
int main() {
FILE* file = fopen("1.txt","w"); //已只读方式打开
if (file == NULL) { //打开失败直接返回
return -1;
}
char buf[] = "test"; //要写入的内容
fwrite(buf,1,sizeof(buf),file); //写入操作
}

该函数无安全函数

除了最基本的写入函数,还有一些其它的常用写操作函数:

  1. fputc:向文件中写入一个字符
1
2
3
4
int  fputc(
int _Character,//要写入的字符
FILE* _Stream //文件标识符
);

使用:

1
2
3
4
5
6
7
8
9
10
#include<cstdio>
using namespace std;
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","w");
if (err != 0) {
return -1;
}
int ret=fputc('c',file);//向file标识的文件写入一个c字符
}
  1. fputs:向文件中写入一个字符串
1
2
3
4
int fputs(
char const* _Buffer,//要写入的内容
FILE* _Stream //文件标识符
);

使用:

1
2
3
4
5
6
7
8
9
10
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","w");
if (err != 0) {
return -1;
}
char buf[] = "test";
int ret = fputs(buf,file); //将buf内的内容写入到file标识的文件
}

  1. fprintf:向文件中写入指定格式字符串,与pritnf函数类似
1
2
3
4
5
int fprintf(
FILE* _Stream, //文件标识符
char const* const _Format, //写入格式 与printf使用方式相同
...
)

使用:

1
2
3
4
5
6
7
8
9
10
#include<cstdio>
using namespace std;
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","w");
if (err != 0) {
return -1;
}
fprintf(file,"%d %s",4,"test"); //向fille标识的文件写入数字4和字符串test
}
  1. fprintf_sfprintf的安全函数

fprintf没什么区别,不再讲解

5.关闭文件

最后是关闭文件

1
2
3
int fclose(
FILE* _Stream //文件标识符
);

使用:

1
2
3
4
5
6
7
8
9
10
#include<cstdio>
using namespace std;
int main() {
FILE* file;
errno_t err=fopen_s(&file,"1.txt","w");
if (err != 0) {
return -1;
}
fclose(file);//关闭文件
}

三、C++处理文件

C++使用了面向对象对文件处理进行了封装,所以处理文件会比C方便很多

为了方便使用,C++封装了三个文件操作类

头文件:

1
2
#include<fstream> //处理文件的头文件
using namespace std; //引用该命名空间,不引用将必须使用std::fstring 的方式使用该类

代码:

首先是最通用的类fstream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<fstream>
using namespace std;
int main() {
fstream file;
file.open("1.txt",ios::out); //以只写模式打开文件
char buf[] = "test";
file.write(buf,sizeof(buf));//写入文件
file<<"666"<<endl;
file.close(); //关闭文件

file.open("1.txt", ios::app); //以追加模式打开文件
char buf1[] = "test1";
file.write(buf1, sizeof(buf));//写入文件末尾
file.close(); //关闭文件

file.open("1.txt",ios::in); //以只读方式打开文件
char buf2[0xFF]; //存储读取的内容
file.read(buf2,0xFF); //读文件
file.close(); //关闭文件
}

模式选择:
在这里插入图片描述
但既然已经封装成为了类,那么在特定需求下,打开文件这个操作也是可以省略的

c++中读取文件中数据的三种方式以及数据类型转换_


1.逐词读取,用 空格 区分每个词

创建输入流对象infile打开相应的文件,创建一个字符串data来存储文件中的数据:

1
2
3
4
5
6
ifstream infile("data.txt");
string data;
while (infile) {
infile >> data;
cout << "read from file:" << data<<" ";
}

2.逐行读取,将每行数据读入字符数组中,用 回车换行 区分每行数据

创建输入流对象infile打开相应的文件,创建一个字符数组data来存储文件中的数据,此时需要使用getline()函数来逐行读取文件的数据:

1
2
3
4
5
ifstream infile("data.txt");
char data[1000];
while (infile.getline(data, 1000) ) {
cout << "read from file:" << data << endl;
}

3.逐行读取,将每行数据读入字符串内,用 回车换行 区分每行数据

创建输入流对象infile打开相应的文件,创建一个字符串data来存储文件中的数据,此时需要使用getline()函数来逐行读取文件的数据:

1
2
3
4
5
ifstream infile("data.txt");
string data;
while (getline(infile, s)) {
cout << "read from file:" << data << endl;
}

这种方式结合C++中数据转换类istringstream类很容易实现按行读取数据后再按照 空格 分割单个数据。

C++中的数据类型转换类

C++中引入了 istringstreamostringstreamstringstream这三个类来进行不同类型数据的转换,要使用它们创建对象就必须包含 <sstream> 这个头文件。

  1. istringstream类用于执行C++风格的串流的输入操作。

istringstream对象可以绑定一行字符串,然后以空格为分隔符把该行分隔开来。在读取数据文件时可以按行读取数据并存储到字符串中,然后通过istringstream字符串分割开,并存储到相应类型的变量中。语法格式如下:

1
istringstream::istringstream(string str);

将一个字符串中数字分割开并赋值给double类型的变量:

1
2
3
4
5
string str = "92 20 120.7";
double num1 = 0, num2 = 0, num3 = 0;
istringstream string_to_num(str);
string_to_num >> num1 >> num2 >> num3 ;
cout << num1 << endl << num2 << endl << num3 ;
  1. ostringstream类用于执行C++风格的串流的输出操作。

ostringstream对象可以将多种数值转换成字符串,可以用于字符串的合并;

1
2
3
4
5
6
7
ostringstream os;
string str = "qwerdf";
int i = 6666;

os<<str<<i;
cout<<os.str();//输出:qwer6666
os.str("");//清空,clear()只清除流的状态标志,不能清除流的内容;
  1. strstream类同时可以支持C++风格的串流的输入输出操作。

首先是读文件的类ifstream

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
#include<fstream>
using namespace std;
int main() {
ifstream f("1.txt");
char buf[0xFF];
f.read(buf,0xFF); //普通读取
char c=f.get(); //读取一个字符

char bufLine[0xFF];
f.getline(bufLine,0xFF); //读取一行
}

然后是写文件的类ofstream

1
2
3
4
5
6
7
8
9
#include<iostream>
#include<fstream>
using namespace std;
int main() {
ofstream f("1.txt");
char buf[0xFF];
f.write("hello world",12); //普通写
f.put('c'); //写入一个字符
}