最近学习了在c语言中对文件的处理(此为win10操作系统),由根据《c标准库》一书针对文件处理相关函数进行了一些总结
在这里只总结了<stdio.h>头文件内的函数,头文件<stdio.h>声明了很多执行输入输出的函数,在阅读各个函数的定义即作用之前,章节前对于stdio.h的历史追朔让我很感兴趣,甚至感觉 了解语言是如何进化统一的比了解函数语句是如何操作的更加重要,现将一部分内容节选出来分享一下:
在20世纪60年代早期,FORTRAN IV被认为是独立于机器的语言。但是如果不作任何改动,根本不可能在各种计算机体系结构中移动FORTRAN IV程序。可移植性的主要障碍是输入输出领域。在FORTRAN IV中,可以对FORTRAN IV代码中间的I/O语句中对正在通信的设备进行命名。CARD 和 INPUT TAPE就不一样。
之后,逐渐发展到使用逻辑单元号(LUN)来代替具体的设备名,从而在可执行的二进制卡片之前加入控制卡片,从而指定某个特殊的运行过程那些设备与特定的LUN相对应。这时候,独立于设备的I/O时代来临了。
设备独立的进一步改善得益于标准外围交换程序(peripheral interchange program,PIP)的进步。该程序允许指定源设备与目标设备的任意成,然后尽力执行两个设备之间的拷贝操作。
进入UNIX。UNIX对所有文本流采用了标准内部形式,文本的每一行以换行符终止。这正是程序读入文本时所期望的,也是程序输出所产生的。假如这样的约定不能满足和UNIX机器相连的处理文本的外围设备的需求,可以在系统的对外接口有些修改,不必修改任何内部代码。UNIX提供了两种机制来修正“对外接口”的文本流。首先的是一个通用的映射函数,它可以用任意的文本处理设备工作。可以用系统调用ioctl来设置或者测试一个具体设备的的各种参数。另一个修正文本流的机制是修改直接控制该设备的专门软件。对于每一个UNIX可能需要控制的设备来说,用户必须添加一个常驻UNIX的设备管理器。
当第一个C编译器在UNIX平台上运行时,C语言就自然地继承了它的宿主操作系统简单的I/O模型。除了文本流的统一表示,还有其他一些优点。很久以前使用的LUNs在最近几十年也慢慢地演变为称为文件描述符或句柄的非常小的正整数。操作系统负责分发文件描述符。并且把所有的文件控制信息存储在自己的专用内存中,而不是让用户去分配和维持文件和记录控制块以加重负担。
为了简化多数程序的运行管理,UNIX shell分配给每个运行的程序3个标准文件描述符,这些就是现在普通使用的标准输入、标准输出和标准错误流。(文本流)
UNIX不会阻止向任意打开的文件写入任意的二进制编码,或者从一个足够大的地方把它们丝毫不变地读取出来。(二进制流)
所以,UNIX消除了文本流(与人通信)和二进制流(与机器通信)之间的区别。
在相同的实现下,从一个二进制流读入的数据应该和之前写入到这个liu的数据相同,而文本流则不是。
PS:流是一个操作系统层面的高度抽象的概念,它隐藏了I/O设备具体的实质,而将所有的I/O带来的数据变化看做输入的流入和流出,这样,在操作系统层面为程序将各种I/O设备模拟成流的样式,已经使这时的I/O模块独立而抽象了。可以看到,I/O模型发展的过程,就是其逐渐抽象统一的过程,这一点与语言的发展的历程是相似的。
X3J11委员会在1983年开始召开会议为C起草ANSI标准。非UNIX系统的C厂商和那些UNIX用户之间争论了很长时间,因为UNIX用户不能理解I/O为什么要这么麻烦(显然,UNIX的文件结构和设备的管理机制保证了I/O模块的简洁性,这是相对于其他操作系统的优点)。这是一个很有教育意义的过程,这些争论的一个重要的副产品就是更清楚地阐明了C支持的I/O模块。
最终,委员会经过讨论整洁的重要性和向下兼容的重要性之后,决定抛弃UNIX风格的原语。(主要平衡代码效率和代码简洁性)
接下来就看一下相关的实现
FILE 它是一个对象类型,可以记录控制流需要的所有信息,包括它的文件定位符、指向相关缓冲(如果有的话)的指针、记录是否发生了读/写错误的错误提示符和记录文件手否结束的文件结束符(用来控制流的FILE对象的地址可能很重要,不必使用FILE对象的副本来代替原始的对象进行服务。)
库中的函数分两类:
1.针对任意流的操作;
2.指定特定问文件流的操作;
两者分别又有读写、文件定位、缓冲区控制等操作,可以完成对流的全方位操作。
文件只为两种形式,字符型文件和二进制型文件
所以不管是何种形式的文件,c语言统一把它当作连续的字节流进行处理,该字节流的信息以及文件对应的文件描述符等都是需要存储在FILE类型中的内容。
源码的定义
1 #ifndef _FILE_DEFINED 2 struct _iobuf { 3 char *_ptr; 4 int _cnt; 5 char *_base; 6 int _flag; 7 int _file; 8 int _charbuf; 9 int _bufsiz; 10 char *_tmpfname; 11 }; 12 typedef struct _iobuf FILE;
不需要对内部进行太多的理解,就是各种描述文件的信息,可以当作类似于int类型 一样的类型去使用,只不过是描述文件类型
1.remove(导致一个文件再也不能通过它的文件名进行访问)
1 #include<stdio.h> 2 int main() 3 { 4 FILE *pFile; 5 char *FileName = "D:\\test1.txt"; 6 int n; 7 int b; 8 char buff[1024] = {0}; 9 b = remove(FileName); 10 fopen_s(&pFile,"D:\\test1.txt","r+"); 11 //printf("%s n = %d\n",buff,n); 12 13 14 return 0; 15 }
2.rename(类似于重命名)
1 #include<stdio.h> 2 int main() 3 { 4 char *pOld = "D:\\love.txt"; 5 char *pNew = "D:\\666.txt"; 6 FILE *pFile; 7 rename(pOld,pNew); //类似于重命名 8 fopen_s(&pFile,"D:\\love.txt","r"); 9 return 0; 10 }
3.tmpfile(创建一个二进制的临时文件)
4.fclose(清空流)
5.fopen(打开文件)
6.freopen(关联文件,在编程比赛过程中,如果太过于繁杂的输入数据,可以通过创建txt文件然后关联的方式进行输入,例 a + b)
1 #include <stdio.h> 2 int main() 3 { 4 int a,b; 5 freopen("D:\\in.txt","r",stdin); //输入数据将从in.txt文件中读取 6 freopen("D:\\out.txt","w",stdout); //输出数据将保存在out.txt文件中 7 while(scanf("%d %d",&a,&b)!=EOF) 8 printf("%d\n",a+b); 9 fclose(stdin);//关闭文件 10 fclose(stdout);//关闭文件 11 return 0; 12 13 }
还有一些没有涉及到的函数,在以后使用中继续加入,接下来根据这些函数写两个简单的应用
1.复制字符型文件
#include<stdio.h> int main() { FILE *pFile1; FILE *pFile2; char c; fopen_s(&pFile1,"D:\\test2.txt","r"); fopen_s(&pFile2,"D:\\love.txt","w"); while((c = getc(pFile1)) != EOF) { putc(c,pFile2); } return 0; }
2.复制二进制型文件(也是文件传输的雏形)
#include<stdio.h> int main() { FILE *pFile1; FILE *pFile2; int n; char buff[1024]; fopen_s(&pFile1,"C:\\Users\\cyc\\Desktop\\通讯录-2.png","rb"); fopen_s(&pFile2,"D:\\你猜是啥呀.png","wb"); while((n = fread(buff,1,1024,pFile1))> 0) { fwrite(buff,1,n,pFile2); } return 0; }
当然这个复制和快捷键 ctrl + c ctrl + v不同,快捷键是利用剪切板进行复制粘贴的
2019-05-09 11:34:21 编程小菜鸟自我反省,大佬勿喷,谢谢!!!