在现今与计算机密切交流中,文件作为计算机中不可或缺的一部分。而文件可用于存储程序、文档、数据、书信、表格、图形、照片、视频等等诸多信息。
在这里对于文件的相关内容做一个结合,可能存在遗留或偏差,恳请提出建议修改
一、文件函数内容
函数有以下21种功能
函数 | 原型 | 功能 |
fopen() | FILE *fopen(const char *filename, const char *mode) | 给定的模式 mode 打开 filename 所指向的文件 |
---|---|---|
putc() | int putc(int char, FILE *stream) | 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。 |
getc() | int getc(FILE *stream) | 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动 |
exit() | void exit(int status) | 立即终止调用进程 |
fclose() | int fclose(FILE *stream) | 关闭流 stream。刷新所有的缓冲区。 |
fprintf() | int fprintf(FILE *stream, const char *format, ...) | 发送格式化输出到流 stream 中。 |
fscanf() | int fscanf(FILE *stream, const char *format, ...) | 从流 stream 读取格式化输入。 |
fgets() | char *fgets(char *str, int n, FILE *stream) | 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内 |
fputs() | int fputs(const char *str, FILE *stream) | 把字符串写入到指定的流 stream 中,但不包括空字符。 |
rewind() | void rewind(FILE *stream) | 设置文件位置为给定流 stream 的文件的开头。 |
fseek() | int fseek(FILE *stream, long int offset, int whence) | 设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。 |
ftell() | long int ftell(FILE *stream) | 返回给定流 stream 的当前文件位置。 |
fflush() | int fflush(FILE *stream) | 刷新流 stream 的输出缓冲区。 |
fgetpos() | int fgetpos(FILE *stream, fpos_t *pos) | 获取流 stream 的当前文件位置,并把它写入到 pos。 |
fsetpos() | int fsetpos(FILE *stream, const fpos_t *pos) | 设置给定流 stream 的文件位置为给定的位置。参数 pos 是由函数 fgetpos 给定的位置。 |
feof() | int feof(FILE *stream) | 测试给定流 stream 的文件结束标识符 |
ferror() | int ferror(FILE *stream) | 测试给定流 stream 的错误标识符。 |
ungetc() | int ungetc(int char, FILE *stream) | 把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符 |
setvbuf() | int setvbuf(FILE *stream, char *buffer, int mode, size_t size) | 定义流 stream 应如何缓冲 |
fread() | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) | 从给定流 stream 读取数据到 ptr 所指向的数组中 |
fwrite() | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) | 把 ptr 所指向的数组中的数据写入到给定流 stream 中 |
二、什么是文件
文件(file)一般指的是磁盘或者固态硬盘上一段已近命名的存储区。对于C而言,stdio.h的头文件就是一个文件的名称,该文件包含着些许有用的信息。对于操作系统而言,文件可能更加复杂。
例如:大型文件会被分开存储,或者包含额外的一些信息/数据,方便操作系统确定的文件。
不过,在这而言,我们更加关注的是C程序如何处理好文件。
在C中,文件是一系列连续的字节,每个字节都被单独读取。着与UNIX环境里结构相对应。
在C中会提供两种文件格式:文本模式、二进制模式。
三、文本模式/二进制模式
- Windows系统,文本模式下,文件以"“代表换行。若以文本模式打开文件,并用fputs等函数写入换行符”\n"时,函数会自动在"\n"前面加上"\r",实际写入文件的是""
- Unix/Linux系统,文本模式下,文件以"\n"代表换行,即Linux系统中在文本模式与二进制模式无区别。
四、标准文件
在C程序中将会自动打开3个文件,标准输入(standard input)、标准输出(standard output)与标准错误输出(standard error output)。
默认情况:标准的输入基于普通的输入设备,通常为键盘。标准输出和标准错误输出指的是系统的普通输出设备,通常为显示屏。
五、标准I/O
与标准环境的底层I/O相比,标准的I/O除了具有可移植外还有两大好处
- 标准I/O简化了许多专门的函数问题
- 输入和输出都有缓冲。
1.fopen()简述
任何程序/文件如需要使用则需要打开,在C中打开文件需要通过函数fopen()函数打开,该函数声明在stdio.h文件中。其语法如上所示。
其中:mode各自作用如下表所示
模式字符串 | 含义 |
---|---|
"r" | 以只读的模式打开文件 |
"w" | 以写的方式打开文件,把现有的文件长度截为0,如果文件不存在,则新建一个文件 |
"a" | 以写的模式打开,在现有文件末尾添加内容,如果文件不存在,则新建一个文件 |
"r+" | 以更新的模式打开文件(即可以读写文件) |
"a+" | 以更新模式打开文件(读写文件),在现有文件末尾添加内容,如果文件不存在则新建一个文件;可以读取整个文件,但是只能在末尾添加内容 |
"rb"、"wb"、"ab"、"rb+"、"r+b"、"wb+"、"w+b"、"ab+"、"a+b" | 与上一模式类似,但是是以二进制的方式打开文件 |
"wx"、"wbx"、"w+x"、"wb+x"或"w+bx" | C11,如果文件已存在或者以独占的形式打开文件,则打开文件夹失败 |
警告:
如果使用任何一种“w”(不带x字母)模式打开现有的文件,均会将原有文件删除!!!
如带x字母的任何一种模式,则无法打开一个现有文件!
代码演示:
#include<stdio.h>
int main(int argc,char* argv[]){
FILE *fp;
fp = fopen("新建文件名.txt","w");//以新建文件的形式打开文件!
fclose(fp);//关闭文件
return 0;
}
2.getc()和putc()函数
getc()和putc()函数与getchar()和putchar()函数类似。但是不同的是,我们需要告诉getc()和putc()使用哪一个文件。
其中:
ch = getchar();//从标准输入中获取一个字符
ch = getc(fp);//从fp指定文件里读取一个字符
类似的:
putc(ch,fpout);//吧字符ch放入FILE指针fpout指定的文件里
代码演示:
#include <stdio.h>
int main (){
FILE *fp;
int ch;
fp = fopen("file.txt", "w");
for( ch = 65 ; ch <= 90; ch++ ) //写入大写字母到文件里,以新建的格式
{
putc(ch, fp);
}
fclose(fp);
return(0);
}
3.文件结尾
我们在读取数据的程序在读到文件结尾时需要停止,这里我们就需要告诉程序已经读取完毕需要停止,但是我们如何停止呢?
如果getc()函数在读取一个字符时,发现是文件结尾,它将返回一个特殊值EOF。这里我们通过添加条件语句判断是否截止,当然,我们需要判断的是是否为空文件。
4.fclose()函数
上面两个代码演示中,我们看到了fclose()函数,但是具体是什么意思呢?
fclose(fp)函数关闭fp指定的文件,必要时刷新缓冲区。而对于比较正式的程序,我们应该检测时候成功关闭文件,如成功关闭返0,失败EOF;
if(fclose(fp) != 0){
printf("Error in closing file %s\n",argv[1]);
}
如出现磁盘已满,移动硬盘移除或I/0错误,则调用fclose()函数失败。
5.文件I/0:fprintf()、fscanf()、fgets()、fputs()
文件I/O流处理函数中,FILE指针指向特定文件与getc()、putc()类似。
5.1fprintf()和fscanf()函数
文件I/O函数fprintf()和fscanf()函数的工作方式与printf()和scanf()类似。
代码演示:
- fprintf()函数:
#include<stdio.h>
#include <stdlib.h>
int main(){
FILE *fp;
fp = fopen("file.txt","w+");
fprintf(fp,"%s %s %d","Hello","World!",2022);//向文件写入三个值,分别为Hello World! 2022
fclose(fp);
return 0;
}
- fscanf()函数:
#include <stdio.h>
#include <stdlib.h>
int main(){
char str1[10], str2[10], str3[10];
int year;
FILE * fp;
fp = fopen ("file.txt", "w+");
fputs("We are in 2014", fp);
rewind(fp);
fscanf(fp, "%s %s %s %d", str1, str2, str3, &year);
printf("Read String1 |%s|\n", str1 );
printf("Read String2 |%s|\n", str2 );
printf("Read String3 |%s|\n", str3 );
printf("Read Integer |%d|\n", year );
fclose(fp);
return(0);
}
5.2fgets()和fputs()函数
fgets()函数与gets()函数一样,表示存储输入位值的地址(char *类型),第二个参数表示字符串大小,最后一个参数表示文件指针,指定带读取的文件。
fgets(buf,stlen,fp);
fputs()函数接受两个参数,第一个是字符串地址;第二个是文件指针。
fputs(buf,fp);
这里buf是字符串地址,fp为目标文件
代码演示:
fputs()函数
#include <stdio.h>
int main (){
FILE *fp;
fp = fopen("file.txt", "w+");
fputs("你好,", fp);
fputs("世界!", fp);
fclose(fp);
return(0);
}
fgets()函数
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char str[60];
/* 打开用于读取的文件 */
fp = fopen("file.txt" , "r");
if(fp == NULL) {
perror("打开文件时发生错误");
exit(0);
}
if( fgets (str, 60, fp)!=NULL ) {
/* 向标准输出 stdout 写入内容 */
puts(str);
}
fclose(fp);
return(0);
}
5.3 随机访问:fseek()和ftell()
有了fseek()函数,便可吧文件看做是数组,在fopen()打开的文件直接移动到任意节点处。
fseek()函数声明:
int fseek(FILE *stream, long int offset, int whence)
参数
stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
offset – 这是相对 whence 的偏移量,以字节为单位。
whence – 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
常量 | 描述 |
---|---|
SEEK_SET | 文件的开头 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件的末尾 |
ftell()函数声明:
long int ftell(FILE *stream)
参数
stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
代码演示:
fseek()
#include <stdio.h>
int main (){
FILE *fp;
fp = fopen("file.txt","w+");
fputs("Hello World!", fp);
fseek( fp, 6, SEEK_SET );
fputs("C primer plus!", fp);
fclose(fp);
return(0);
}
ftell()
#include <stdio.h>
int main ()
{
FILE *fp;
int len;
fp = fopen("file.txt", "r");
if( fp == NULL )
{
perror ("打开文件错误");
return(-1);
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fclose(fp);
printf("file.txt 的总大小 = %d 字节\n", len);
return(0);
}
5.4 fread()和fwrite()
介绍着两者之前,首先了解相关背景知识!之前所用到的I/O函数都是面向文本的,用于处理字符和字符串。如何在文本中保存数值数据?这里就需要这两者函数实现!
fwrite()函数
关乎size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数
ptr -- 这是指向要被写入的元素数组的指针。
size -- 这是要被写入的每个元素的大小,以字节为单位。
nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
例如:
char buffer[256];
fwrite(buffer,256,1,fp);
上面调用一块256字节的数据从buffer写入文件。
特别的,要保存一块10个double类型值得数组,我们可以
double str[10];
fwritr(str,sizeof(double),10,fp);
size_t fread()函数
关乎size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数
ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
size -- 这是要读取的每个元素的大小,以字节为单位。
nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
例如:我们要恢复保存的内含10个double类型的数组,可以这样
double str[10];
fread(str,sizeof(double),10,fp);
该调用吧10个double大小的值拷贝到str数组中
fread()函数放回成功读取项的数量。正常放回的是nmemb,如出现错误,则放回比nmemb小。
以上是部分文件知识总结,可能存在这部分的知识漏缺,望请私信进行修正。