【C语言】—— 文件操作(上)
9毫米的幻想 2024-10-08 17:35:01 阅读 96
【C语言】—— 文件操作(上)
一、 为什么使用文件二、 什么是文件2.1、 程序文件2.2、 数据文件2.3、 文件名2.4、二进制文件与文本文件
三、 文件的打开和关闭3.1、流和标准流(1)流(2)标准流
3.2、文件指针
四、文件的打开和关闭
一、 为什么使用文件
我们为什么要使用文件呢?回答这个问题之前,我们先来看一段代码:
<code>#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d\n", n);
return 0;
}
这段代码创建了一个变量
n
n
n,当程序运行时,我们输入一个值(比如说 10 )存在变量
n
n
n 中,当我们下一次运行程序时,这个10 不见了,它的值又恢复到 0,我们又得重新输入一个值。
原来,像
n
n
n 这样的变量是在内存里创建的,当程序结束时,刚刚申请的 4 个字节又还给了操作系统,当程序再次运行时,
n
n
n中的值依然是 0。
因此,如果将数据存在内存中,当程序结束,下次再运行时,这个值就不见了,它无法持久化地保存起来。
怎么办呢?
这时我们想,如果我们在电脑上创建了一个文件,文件中存这一个 10。这个文件是放在硬盘上的(比如C盘、E盘)。这即使把电脑关机,下次打开里面依然存的是 10。
这是因为,当我们把数据放在文件中,即硬盘上时,这些数据会持久化地保存下来。而相对的,放在内存中数据只要程序退出,数据就丢失了。
因此当我们想把数据持久化地保存下来时,就需要文件。
二、 什么是文件
硬盘(磁盘)上的文件就是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件
、数据文件
(从文件功能的角度分类)
2.1、 程序文件
所谓的程序文件就是我们写出来的代码,程序文件包括源程序文件(后缀文
.
c
.c
.c),目标文件(
w
i
n
d
o
w
s
windows
windows 环境后缀为
.
o
b
j
.obj
.obj),可执行程序(
w
i
n
d
o
w
s
windows
windows环境后缀为
.
e
x
e
.exe
.exe)
2.2、 数据文件
什么是数据文件呢?当我们写程序,<code>从某一个文件中读取数据;或者把一些数据写到文件中,这种文件就称为数据文件。
本章我们讨论的内容主要是数据文件。
在之前的学习中,我们所处理的输入输出都是以终端
为对象的,即:从终端的键盘输入数据,运行结果显示到显示器(屏幕)上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件
。
2.3、 文件名
一个文件要有唯一标识,以便用户识别和引用
文件名包含 3 部分:文件路径
+文件名主干
+文件后缀
如:c:\code\test.txt
c:\code\ 为文件路径
t
e
s
t
test
test 为文件名主干
t
x
t
txt
txt 为文件后缀
2.4、二进制文件与文本文件
根据文件的组织形式,数据文件一般被称为文本文件和二进制文件
数据在内存中以二进制的形式存储
,如果不加转换
的输出到外出文件中,就是二进制文件。
前面曾提到的
.
o
b
j
.obj
.obj文件就是一种 二进制文件,通过文本编辑器打开是一堆乱码,我们是看不懂的
如果要求在外存上以
A
S
C
I
I
ASCII
ASCII 码的形式存储,则需要再存储前转换。以
A
S
C
I
I
ASCII
ASCII 字符存储的文件就是文本文件。
那么一个数据在文件中是如何存储的呢?
<code>字符一律以
A
S
C
I
I
ASCII
ASCII 码形式存储,数值型数据
及可以用
A
S
C
I
I
ASCII
ASCII 码形式存储,也可以使用二进制形式存储。
什么意思呢?假设现在有一个整数 10000:
如果以
A
S
C
I
I
ASCII
ASCII 码的形式存储,则磁盘中占用 5 个字节(一个字符一个字节):一个字符 ‘1’,四个字符 ‘0’
如果以二进制的形式存储,磁盘上只占4个字节(一个整型)
而以
A
S
C
I
I
ASCII
ASCII 码形式存储则为<code>文本文件;以二进制形式存储则为二进制文件
。
测试代码:
#include<stdio.h>
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
fclose(pf);
pf = NULL;
return 0;
}
这段代码可能有些看不懂,但是没关系,我们只需知道其大致意思即可:这段代码就是将 10000 以二进制的形式写到文件中
执行程序后,我们直接打开文件:
我们再通过二进制的形式打开文件
VS上打开二进制文件的方法
10000 在二进制文件中
那 10 和 27 又是什么意思呢?其实就是 0001 0000 和 0010 0111 的<code>十六进制表示,同时,因为是小端字节序存储
,因此存储时反过来的。
三、 文件的打开和关闭
3.1、流和标准流
(1)流
我们程序的数据要输出
到各种外部设备(屏幕、硬盘、U盘、网络上),也需要从外部设备(键盘、文件、网络上、U盘)获取
数据,不同的外部设备的输入输出的操作各不相同,为了方便程序员对各种设备进行方便操作,我们抽象出 流 的概念,我们可以把流想象成流淌着数据的河
。
没有流,程序员就要学会如何从各种不同的设备上输入输出数据,而有了流,程序员只需知道如何将数据从流中取出和写入流即可,至于流如何与外部设备之间进行交流,我们并不关心,这是C语言底层和操作系统要关系的事情。这样大大简化了程序员学习编程的难度
C程序针对文件、画面、键盘等的数据输入输出操作都是通过流
操作的。
一般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流,然后操作
。
进行文件操作,打开文件其实就是打开流,然后再对流进行读写
(2)标准流
那为什么我们从键盘输入数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语言程序在启动的时候,默认打开了 3 个流
:
stdin(标准输入流):在大多数的环境中从键盘输入
,
s
c
a
n
f
scanf
scanf 函数就是从标准输入流中读取数据。stdout(标准输出流):大多数的环境中输出至显示器界面
,
p
r
i
n
t
f
printf
printf函数就是将信息输出到标准输出流中。stderr(标准错误流):大多数环境中输出到显示器界面
。
这是默认打开了的三个流,我们使用
s
c
a
n
f
scanf
scanf、
p
r
i
n
t
f
printf
printf 等函数就可以直接进行输入输出操作
的。
s
t
d
i
n
stdin
stdin、
s
t
d
o
u
t
stdout
stdout、
s
t
d
e
r
r
stderr
stderr 三个流的类型是:
F
I
L
E
FILE
FILE* ,通常称为文件指针。
C语言中,就是通过
F
I
L
E
FILE
FILE* 的文件指针来维护流的各种操作
的
3.2、文件指针
在缓冲文件系统中,关键的概念是“文件类型指针”,简称 “文件指针”。
每一个被使用的文件都在内存中开辟了一个相应的文件信息区
,用来存储文件的相关信息
(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量
中的。该结构体类型是有系统声明的,取名
F
I
L
E
FILE
FILE。
例如在VS2013编译器环境提供的
s
t
d
i
o
.
h
stdio.h
stdio.h 头文件中有以下的文件类型声明:
struct _iobuf {
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
};
typedef struct _iobuf FILE;
不同的编译器的
F
I
L
E
FILE
FILE 类型包含的内容不完全相同,但是大同小异。
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息
,使用者不必关系细节。
一般都是通过一个
F
I
L
E
FILE
FILE 指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个
F
I
L
E
FILE
FILE *的指针变量
FILE* pf;
定义
p
f
pf
pf 是一个指向
F
I
L
E
FILE
FILE 类型数据的指针变量。可以使
p
f
pf
pf指针指向某个文件信息区
(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够简洁找到与它关联的文件。
四、文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会<code>返回一个 FILE* 指针变量指向该文件,也相当于建立了指针和文件的关系。
A
N
S
I
ANSI
ANSI
C
C
C规定使用
f
o
p
e
n
fopen
fopen函数来打开文件,
f
c
l
o
s
e
fclose
fclose函数来关闭文件。
f
o
p
e
n
fopen
fopen 函数(打开文件)
如果文件打开<code>成功,返回一个FILE* 指针
,打开失败
则返回空指针
f
i
l
e
n
a
m
e
filename
filename 表示要打开的文件名
,其应符合文件的命名规范,可以包含文件路径
m
o
d
e
mode
mode 表示文件的打开模式
,下面都是文件的打开模式
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r” (只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w” (只写) | 为了输入输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 建立一个新的文件 |
“r+”(读写) | 为了读和写,打开一个新的文件 | 出错 |
“w+”(读写) | 为了读和写,创建一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新文件 |
“rb+”(读写) | 为了读和写,打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,创建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个未禁止文件,在文件尾进行读和写 | 建立一个新的文件 |
注:“
w
w
w”(只写)会将原文件的内容全部清空,再从第一位开始写入数据;“a”(追加) 是从文件末尾开始追加
f
c
l
o
s
e
fclose
fclose 函数(关闭文件)
使用
f
c
l
o
s
e
fclose
fclose 函数将文件关闭后,要将该文件指针置空(如
f
r
e
e
free
free 函数一样)
可能有些小伙伴对输入输出的关系还有些糊涂,我们可以来看下面一张图
其实,究竟是输入还是输出,应该站在程序的角度分析:<code>程序从外界获取数据,是输入;程序向外输出数据,是输出。
下面,我们先来尝试打开和关闭一个文件
#include<stdio.h>
int main()
{
FILE* pf = NULL;
//打开文件
pf = fopen("test.txt", "r");
//文件操作
if (NULL == pf)
{
perror("fopen fail");
return 1;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
}
前面曾提到,文件打开失败时,
f
o
p
e
n
fopen
fopen 函数会返回一个空指针,因此使用
f
o
p
e
n
fopen
fopen 函数打开一个文件,要对其返回值进行判断。
r
e
t
u
r
n
return
return 1 :表示的是程序异常,提前结束程序,正常结束时返回0
。使用
f
c
l
o
s
e
fclose
fclose 函数将文件关闭,别忘了将指针置空
,如同
f
r
e
e
free
free函数一样。
未完待续······
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。