1. C语言对文件的操作
1. 文件常见输入输出函数与屏幕、键盘输入输出函数的对比,如:fprintf、fscanf等。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main() { printf("-------------屏幕--------------\n"); printf("锄禾日当午!\n"); fprintf(stdout, "锄禾日当午!\n"); //显示器当做文件来操作 //printf就是fprintf的特例 puts("锄禾日当午,汗滴禾下土!"); //往屏幕上输出字符串,自带换行 fputs("锄禾日当午,汗滴禾下土!\n", stdout);//效果一样,但没有自带换行 putchar('A'); fputc('A', stdout); printf("\n-------------键盘--------------\n"); //int num; //scanf("%d", &num); //printf("num=%d\n", num); //int numA; //fscanf(stdin,"%d", &numA); //fscanf可以扫描任何文件,不仅是键盘 //fprintf(stdout,"numA=%d\n", numA); //char str[50]; ////gets(str); //fgets(str, sizeof(str) - 1, stdin); //第二个参数需要去掉'\0' //fputs(str,stdout); char ch = fgetc(stdin); fputc(ch, stdout); system("pause"); }
2. 标准错误输出函数stderr。
#include <stdio.h> #include <stdlib.h> //stderr,错误写入文件,输出错误信息 void main() { //遇到错误,就可以把错误信息写入stderr,会自动在显示器上输出 fprintf(stderr, "你遇到的错误是%s,重试次数是%d\n", "权限不够", 3);//你遇到的错误是权限不够,重试次数是 3 //stderr始终显示在显示器,stdout如果重定向会被写入磁盘 fprintf(stdout, "你遇到的错误是%s,重试次数是%d\n", "权限不够", 3);//你遇到的错误是权限不够,重试次数是 3 system("pause"); }
3. 宽字符处理函数 getw 和 putw。
#include <stdio.h> #include <stdlib.h> void main() { int W = _getw(stdin); //从键盘获取输入,获取4个字节,最新C++需要用_getw、_putw _putw(W, stdout); //显示器输出 //可以输出两个汉字,一个汉字两个字节 //int 用于装容两个汉字的二进制s //putw输出成功就返回输出的值,输出失败则返回-1 system("pause"); }
4. 文件读写。
读文件 ("r" 模式):
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //"r"模式文件必须存在,不存在就打开失败 //打开成功,就可以进行读的操作 //此时进行写操作,不会提示错误,但是会操作失败 void main() { char path[40] = "c:\\1.txt"; FILE *fp = fopen(path, "r"); //"r"按照读的方式打开文件,文件必须存在,不存在则打开失败 if (fp == NULL) printf("文件打开失败!\n"); else { printf("文件打开成功!\n"); //法一: while (!feof(fp)) //判断文件是否到末尾 { char ch = fgetc(fp); //从文件读取一个字符保存到ch putchar(ch); //输出这个字符 } //结果为:hello world! //上面while循环也可改为: //char ch = fgetc(fp); //while (ch != EOF) //End Of File文件结束 //{ // putchar(ch); //输出这个字符 // ch = fgetc(fp); //从文件读取一个字符保存到ch //} //还可改为do-while循环: //char ch; //do //{ // ch = fgetc(fp); // putchar(ch); //} while (ch != EOF); //法二:注意对比fscanf与fgetc //char str[100]; //int num; //while (!feof(fp)) //{ // fscanf(fp, "%s", str); //fscanf遇到空格和换行时结束 // printf("%s", str); //结果为:helloworld! //} fclose(fp); //关闭文件指针 } system("pause"); }
写文件("w" 模式):
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //"w"模式:若文件不存在则建立该文件 //若文件存在则文件长度清0,即该文件内容会消失 //"w"模式只能写不能读 void main() { char path[40] = "c:\\2.txt"; FILE *fp = fopen(path, "w"); //"w"按照写的方式打开文件 if (fp == NULL) printf("文件打开失败!\n"); else { printf("文件打开成功!\n"); fputs("hello world!\n",fp); //向文件写入字符串 fprintf(fp, "%s\n", "Hello World!"); //向文件写入字符串 fclose(fp); //关闭文件指针 } system("pause"); }
读写文件("r+"模式):
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //"r+"模式文件必须存在,不存在就打开失败,存在就可以读和写 void main() { char path[40] = "c:\\3.txt"; FILE *fp = fopen(path, "r+"); //"r+"读写方式打开文件 if (fp == NULL) printf("文件打开失败!\n"); else { printf("文件打开成功!\n"); while (!feof(fp)) //判断文件是否到末尾 { char ch = fgetc(fp); //从文件读取一个字符保存到ch putchar(ch); //输出这个字符 } int res = fputc('A', fp); //写入一个字符‘A’ if (res == -1) printf("\n写入失败"); else printf("\n写入成功\n"); fclose(fp); //关闭文件指针 } system("pause"); }
写读文件("w+" 模式):
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //"w+"模式:若文件不存在则建立该文件 //若文件存在则文件长度清0,即该文件内容会消失 //"w+"模式既能写也能读 void main() { char path[40] = "c:\\4.txt"; FILE *fp = fopen(path, "w+"); //写的方式打开文件 if (fp == NULL) printf("文件打开失败!\n"); else { printf("文件打开成功!\n"); fputs("A hello world!", fp); //向文件写入字符串 rewind(fp); //文件指针移动到开头 char ch = fgetc(fp); //从文件读取一个字符保存到ch //fgetc如果执行成功就会返回读取的字符;若执行失败则返回-1 printf("%d\n", ch); putchar(ch); //输出这个字符 fclose(fp); //关闭文件指针 } system("pause"); } // w 只写模式打开,文件存在则长度清0,不存在则建立文件。 // w+ , wb, wb+ , wt, wt+ 模式打开文件,文件不存在则建立文件 // a 以附加的方式打开只写文件,若文件不存在,则建立文件,存在则在文件尾部添加数据 // a+ 以附加的方式打开可读写文件,不存在则建立文件,存在则写入数据到文件尾 // at 二进制数据的追加,不存在则创建,只能写。 // at+ 读写打开一个文本文件,允许读或在文本末追加数据 // ab 二进制数据的追加,不存在则创建,只能写。
5. access 函数:
确定文件或文件夹的访问权限。即,检查某个文件的存取方式,比如说是只读方式、只写方式等。
如果指定的存取方式有效,则函数返回0,否则函数返回-1。
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
R_OK 只判断是否有读权限
W_OK 只判断是否有写权限
X_OK 判断是否有执行权限
F_OK 只判断是否存在
#include <stdio.h> #include <stdlib.h> #include <io.h> //windows在头文件<io.h>中,linux在头文件<unistd.h>中 void main() { //windows下所有文件夹都是可读可写的 //printf("%d\n", _access("c:\\1", 0)); //0 判断是否存在c:\\1这个文件夹 //printf("%d\n", _access("c:\\1.txt", 0)); //0 判断是否存在c:\\1.txt这个文件 //if (_access("c:\\1", 0)) //存在返回0;不存在返回-1 // printf("文件夹不存在\n"); //else // printf("文件夹存在\n"); //printf("%d\n", _access("c:\\1.txt", 2)); //2 判断c:\\1.txt这个文件是否可写 //if (_access("c:\\1", 0)) //可写返回0;不可写返回-1 // printf("文件不可写\n"); //else // printf("文件可写\n"); //printf("%d\n", _access("c:\\1.txt", 4)); //4 判断c:\\1.txt这个文件是否可读 //if (_access("c:\\1", 0)) //可读返回0;不可读返回-1 // printf("文件不可读\n"); //else // printf("文件可读\n"); printf("%d\n", _access("c:\\1.txt", 6)); //6 判断c:\\1.txt这个文件是否可读可写 if (_access("c:\\1", 0)) //可读可写返回0;不可读可写返回-1 printf("文件不可读可写\n"); else printf("文件可读可写\n"); system("pause"); }
6. 按照内存块的方式读写文件(数组、结构体),fread 、 fwrite 函数:
函数原型:
size_t fread(void *buffer,size_t size, size_t count,FILE *fp)
size_t fwrite(void *buffer,size_t size, size_t count,FILE *fp)
功能:读/写数据块
返值:成功,返回读/写的块数;出错或文件尾,返回0
说明:
typedef unsigned size_t;
buffer: 指向要输入/输出数据块的首地址的指针
size: 每个要读/写的数据块的大小(字节数)
count: 要读/写的数据块的个数
fp: 要读/写的文件指针
fread与fwrite 一般用于二进制文件的输入/输出
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //按内存块写入文件fwrite: void main() { int num[100]; //数组是连续排列的,是一段连续的内存 for (int i = 0; i < 100; i++) num[i] = i; //初始化数组 FILE *fp; fp = fopen("c:\\数组.txt", "wb"); //二进制写入的模式打开文件 if (fp == NULL) printf("文件打开失败\n"); else { int res = 0; res = fwrite(num, sizeof(int), 100, fp); //将内存写入文件 //写成功多少个,会返回数量 //第1个参数:写入内存的首地址 //第2个参数:一个元素有多大 //第3个参数:写多少个元素 //第4个参数:写到哪个文件 if (res == 100) printf("写入成功\n"); else printf("写入失败\n"); } fclose(fp); system("pause"); }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //按内存块读文件fread: void main() { int num[100]; //数组是连续排列的,是一段连续的内存 FILE *fp; fp = fopen("c:\\数组.txt", "rb"); //二进制写入的模式打开文件 if (fp == NULL) printf("文件打开失败\n"); else { int res = 0; res = fread(num, sizeof(int), 100, fp); //读取文件到内存 //读成功多少个,会返回数量 //第1个参数:读入内存的首地址 //第2个参数:一个元素有多大 //第3个参数:读多少个元素 //第4个参数:读到哪个文件 if (res == 100) printf("读入成功\n"); else printf("读入失败\n"); for (int i = 0; i < 100; i++) printf("num[%d]=%d\n", i, num[i]); //打印数据 } fclose(fp); system("pause"); }
7. 测试文件是否出现错误, ferror 、 perror 函数:
ferror 函数:
在调用各种输入输出函数(如 putc.getc.fread.fwrite等)时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。
函数原型: int ferror(FILE *fp)
功能:测试文件是否出现错误
返值:未出错,0;出错,非0
说明
每次调用文件输入输出函数,均产生一个新的ferror函数值,所以应及时测试
fopen打开文件时,ferror函数初值自动置为0
perror 函数:
在调用各种输入输出函数时,如果出现错误,除了函数返回值有所反映外,还可以用ferror函数检查。 它的一般调用形式为 ferror(fp);如果ferror返回值为0(假),表示未出错。如果返回一个非零值,表示出错。在执行fopen函数时,ferror函数的初始值自动置为0。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main() { char path[40] = "c:\\1.txt"; FILE *fp = fopen(path, "r"); if (fp == NULL) printf("文件打开失败!\n"); else { printf("文件打开成功!\n"); //文件打开成功! //文件打开成功时,判断一次 if (ferror(fp) == 0) printf("文件正常\n"); //文件正常 else printf("文件出错\n"); fputs("C语言", fp); //执行fputs写文件后再次判断 if (ferror(fp) == 0) printf("文件正常\n"); else { printf("文件出错\n"); //文件出错 perror("错误原因是:"); //错误原因是:Bad file descriptor } } fclose(fp); system("pause"); }
8. 处理文件错误,clearerr复位错误标志:
clearerr的作用是使文件错误标志和文件结束标志置为0.假设在调用一个输入输出函数时出现了错误,ferror函数值为一个非零值。在调用clearerr(fp)后,ferror(fp)的值变为0。
用 法:void clearerr(FILE *stream);
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <stdio.h> //按照写的模式打开一个文件,读取会出错 void main() { FILE *fp = fopen("c:\\1.txt", "w"); if (fp == NULL) { printf("文件打开失败!\n"); perror("错误信息是:"); } else { fputs("hello world", fp); //向文件输出一个字符串 rewind(fp); //将文件指针移到开头 char ch = fgetc(fp); //从文件读取一个字符 if (ch == EOF) //-1,EOF,end of file,读取文件失败返回-1,读取到最后也返回-1 { if (feof(fp)) //feof(fp)返回值为非0,到了文件末尾 { printf("读到了文件末尾\n"); clearerr(fp); //重置文件流的状态 } if (ferror(fp)) //ferror(fp)返回值为非0,意味着文件出错 { printf("文件读取出错\n"); clearerr(fp); //重置文件流的状态,清除错误信号,表明恢复正常,如果不清除下次正确的状态还会出错 } } } fclose(fp); system("pause"); }
9. 文件定位函数,rewind、ftell、fseek 函数:
文件的读写方式有两种,一是顺序读写,位置指针按字节顺序从头到尾移动,另一种是随机读写,位置指针按需要移动到任意位置,随机形式多用于二进制文件的读写。
如果要对文件进行随机读写,就需要控制文件位置指针的值,这就是文件定位,与文件定位有关的函数是rewind函数,fseek函数和ftell函数。
(1)rewind 函数:
rewind函数没有返回值,其调用形式为:rewind(FILE* fp);
该函数使得文件位置指针返回文件开头。
(2)ftell 函数:
原型为:long ftell(FILE *);
执行成功时,返回当前文件指针到文件头有多少个字节,否则,返回-1。
当文件指针到达文件末尾时,也可使用ftell获取文件大小。
在windows上ftell获取文本文件的大小,换行符会解析成两个字符/r/n,linux上为一个字符,并且linux有结束符。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main() { FILE *fp = fopen("c:\\1.txt", "r"); if (fp == NULL) { printf("文件打开失败!\n"); } else { while (!feof(fp)) //没有到文件结尾就继续 { char ch = getc(fp); //从文件读取一个字符 if (ch == 'o') { int len = ftell(fp); //获取距离文件开头的字节数 printf("\n\n找到o,距离文件开头%d字节\n\n",len); } putchar(ch); } int size = ftell(fp); //到了文件末尾可以获取大小 printf("\n文件大小有%d字节\n",size); //上面读取文件,文件指针已经到了末尾,下面再次读取需使用rewind rewind(fp); //文件指针回到开头 char str[100] = { 0 }; while (fgets(str, 100, fp) != NULL) { printf("%s", str); //打印字符串 } } fclose(fp); //关闭文件 system("pause"); }
(3)fseek 函数:
文件定位中最重要的一个函数是fseek,用以控制、调整文件指针的值,从而改变下一次读写操作的位置,其函数原型为:int fseek(FILE * fp, long offset, int startPos);
其中,fp是文件指针,startPos是起始点,offset是目标位置相对起始点的偏移量,可以为负数,如果函数操作执行成功,文件位置指针将被设定为“起始点+offset”,起始点并不是任意设定的,C语言给出了3种起始点方式,如下所示:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //fseek可以移动到指定位置进行读写 void main() { FILE *fp = fopen("c:\\1.txt", "r+"); if (fp == NULL) printf("文件打开失败!\n"); else { printf("文件打开成功!\n"); //一开始文件指针再开头 //移动到尾部进行写入,移动到尾部前面几个字节进行写入 //输出结果为:先是在文件末尾输入“锄禾日当午”,然后刷新缓冲区往前移动10个字符覆盖输入“汗滴禾下土”。 //fseek(fp, 0, SEEK_END); //移动文件指针到末尾 //fputs("锄禾日当午", fp); //输出字符串 //fflush(fp); //将缓冲区数据立即写入文件 //fseek(fp, -10, SEEK_END); //往前移动10个字节(5个汉字占10字节) //fputs("汗滴禾下土", fp); //输出字符串 //读取文件后10个字节的内容 //fseek(fp, -10, SEEK_END); //移动指针到末尾前10个字节处 //while (!feof(fp)) //{ // char ch = fgetc(fp); //获取一个字符 // putchar(ch); //输出字符 //} //修改前面8个字节 //先显示一次: //while (!feof(fp)) //{ // char ch = fgetc(fp); //获取一个字符 // putchar(ch); //输出字符 //} //printf("\n-----------------------------------------------\n"); //分割行 //fseek(fp, 0, SEEK_SET); //移动到开头 //for (int i = 0; i < 8; i++) //写入8个字符'1' // fputc('1', fp); ////再显示一次: //fseek(fp, 0, SEEK_SET); //移动到开头 //while (!feof(fp)) //{ // char ch = fgetc(fp); //获取一个字符 // putchar(ch); //输出字符 //} //文件中查找某个字符u,并修改前面4个字符 while (!feof(fp)) { char ch = fgetc(fp); //获取一个字符 putchar(ch); //输出字符 } printf("\n-----------------------------------------------\n"); //分割行 rewind(fp); //文件指针回到开头 fseek(fp, 0, SEEK_SET); //移动到开头 while (!feof(fp)) { char ch = fgetc(fp); //获取一个字符 if (ch == 'u') { fseek(fp, -4, SEEK_CUR);//当前位置向前移动4个字符 fputc('1', fp); fputc('2', fp); fputc('3', fp); fputc('4', fp); break; //跳出循环 } } //再次显示 fseek(fp, 0, SEEK_SET); //移动到开头 while (!feof(fp)) { char ch = fgetc(fp); //获取一个字符 putchar(ch); //输出字符 } fclose(fp); } system("pause"); }
10. 删除文件,remove 函数:
用 法: int remove(const char *filename);
返回值:如果删除成功,remove返回0,否则返回EOF(-1)。
如果要删除的文件已经打开,则删除失败返回 -1。
#include <stdio.h> #include <stdlib.h> void main() { //char *Filepath = "c:\\2.txt"; //remove(Filepath); //删除文件,传入路径 char *Filepath = "c:\\2.txt"; int res = remove(Filepath); //删除文件,传入路径 printf("%d\n", res); if (res == 0) printf("删除成功!\n"); else printf("删除失败!\n"); system("pause"); }
11. 产生唯一的临时文件名,mktemp 函数:
功能: mktemp()用来产生唯一的临时文件名。参数template所指的文件名称字符串中最后六个字符必须是XXXXXX。产生后的文件名会借字符串指针返回。
返回值: 文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
头文件是io.h。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <io.h> //windows下mktemp()函数所在头文件;而linux下在头文件<stdlib.h>中 void main() { char Filepath[100] = "c:\\XXXXXX"; //mktemp修改的目标,后面6个必须是X char *newName = _mktemp(Filepath); //传入路径,根据模板生成唯一的目录名 printf("%s,%s\n", newName, Filepath); char cmd[100]; sprintf(cmd, "md %s", Filepath); //初始化字符串,用于指令创建目录 system(cmd); system("pause"); }