了解I/O有助于提高你的效率。如果打算学习C语言的输入输出,可以从stdio.h包含文件入手。正如您可能从其名称中猜到的那样,该文件定义了所有标准(“std”)输入和输出(“io”)函数。大多数人学习的第一个stdio.h函数是打印格式化输出的printf函数。或者用于打印字符串的puts函数。这些函数对于向用户打印信息非常有用,但是如果你想做更多的事情,你还需要了解其他函数。您可以通过编写一份常用Linux命令的副本来了解其中一些功能和方法。cp命令主要用于复制文件。如果查看cp手册页,您会发现cp命令支持很多参数和选项。但最简单的功能就是复制文件:cpinfileoutfile只需要使用一些读写文件的基本功能,就可以用C语言自己实现cp命令。一次读取和写入一个字符您可以使用fgetc和fputc函数轻松地进行输入和输出。这些函数一次读写一个字符。用法定义在stdio.h中,也很直接:fgetc从文件中读取一个字符,fputc将一个字符保存到文件中。intfgetc(文件*流);intfputc(intc,FILE*stream);编写cp命令需要访问该文件。在C中,您可以使用fopen函数打开一个文件,该函数有两个参数:文件名和打开文件的模式。该模式通常是从文件(r)读取或写入文件(w)。关于文件的打开方式还有其他选项,但出于本教程的目的,我们将只关注读取和写入。因此,将一个文件复制到另一个文件就变成了打开源文件和目标文件,然后不断地从第一个文件读取字符并将这些字符写入第二个文件。fgetc函数返回从输入文件读取的单个字符,或者在文件完成时返回文件结束标记(EOF)。读取EOF后,您就完成了复制,您可以关闭这两个文件。代码如下所示:do{ch=fgetc(infile);if(ch!=EOF){fputc(ch,输出文件);}}while(ch!=EOF);你可以使用这个循环来编写你自己的cp程序,使用fgetc和fputc函数一次读写一个字符。cp.c的源码如下:#includeintmain(intargc,char**argv){FILE*infile;文件*输出文件;内部通道;/*解析命令行*//*usage:cpinfileoutfile*/if(argc!=3){fprintf(stderr,"Incorrectusage\n");fprintf(stderr,"用法:cpinfileoutfile\n");返回1;}/*打开输入文件*/infile=fopen(argv[1],"r");if(infile==NULL){fprintf(stderr,"无法打开文件进行读取:%s\n",argv[1]);返回2;}/*打开输出文件*/outfile=fopen(argv[2],"w");if(outfile==NULL){fprintf(stderr,"无法打开文件进行写入:%s\n",argv[2]);fclose(infile);返回3;}/*将一个文件复制到另一个文件*//*使用fgetc和fputc*/do{ch=fgetc(infile);if(ch!=EOF){fputc(ch,输出文件);}}while(ch!=EOF);/*完成*/fclose(infile);fclose(输出文件);return0;}你可以使用gcc将cp.c文件编译成可执行文件:$gcc-Wall-ocpcp.c-ocp选项告诉编译器将编译好的程序保存到cp文件中——Wall选项告诉编译器提示所有可能的警告,如果没有看到任何警告,则一切正常。读取和写入数据块通过一次读取和写入一个字符来实现您自己的cp命令可以完成这项工作,但速度不是很快。在复制文档和文本文件等“日常”文件时,您可能不会注意到它,但在复制大文件或通过网络复制文件时,您会注意到差异。一次处理一个字符需要大量开销。实现此cp命令的更好方法是将输入数据块读入内存(称为缓存),然后将该数据集合写入第二个文件。这要快得多,因为程序可以一次读取更多数据,从而减少了从文件中“读取”的次数。您可以使用fread函数将文件读入变量。这个函数有几个参数:指向要将数据读入的数组或内存缓冲区的指针(ptr)、要读取的最小对象的大小(size)、要读取的对象数(nmemb)和文件(stream):size_tfread(void*ptr,size_tsize,size_tnmemb,FILE*stream);不同的选项为更高级的文件输入和输出(例如,读取和写入具有特定数据结构的文件)提供了极大的灵活性。但是,在从一个文件读取数据并将数据写入另一个文件的简单情况下,可以使用字符数组缓冲区。您可以使用fwrite函数将缓冲区中的数据写入另一个文件。这采用与fread函数类似的一组选项:指向要读取的数组或内存缓冲区的指针、要读取的最小对象的大小、要读取的对象的数量以及要写入的文件。size_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);如果程序将文件读??入缓冲区,然后将该缓冲区写入另一个文件,则array(ptr)可以是固定大小的数组。例如,您可以使用长度为200个字符的字符数组作为缓冲区。在这种假设下,您需要更改cp程序中的循环以将数据从文件读取到缓冲区,然后将该缓冲区写入另一个文件:while(!feof(infile)){buffer_length=fread(buffer,sizeof(char),200,文件);fwrite(缓冲区,sizeof(char),buffer_length,输出文件);这是更新后的cp程序的完整源代码,该程序现在使用缓冲区进行读写输入数据:#includeintmain(intargc,char**argv){FILE*infile;文件*输出文件;字符缓冲区[200];size_t缓冲区长度;/*解析命令行*//*usage:cpinfileoutfile*/if(argc!=3){fprintf(stderr,"Incorrectusage\n");fprintf(stderr,"用法:cpinfileoutfile\n");返回1;}/*打开输入文件*/infile=fopen(argv[1],"r");if(infile==NULL){fprintf(stderr,"无法打开文件进行读取:%s\n",argv[1]);返回2;}/*打开输出文件*/outfile=fopen(argv[2],"w");if(outfile==NULL){fprintf(stderr,"无法打开文件进行写入:%s\n",argv[2]);fclose(infile);返回3;}/*将一个文件复制到另一个文件*//*使用fread和fwrite*/while(!feof(infile)){buffer_length=fread(buffer,sizeof(char),200,infile);fwrite(缓冲区,sizeof(char),buffer_length,输出文件);}/*完成*/fclose(infile);fclose(输出文件);return0;}因为你想把这个程序和其他程序比较,请把这个源代码保存为cp2.c程序可以用gcc编译:$gcc-Wall-ocp2cp2.c和以前一样,-ocp2选项告诉编译器将编译后的程序保存到cp2程序文件中。-Wall选项告诉编译器打开所有警告。如果您没有看到任何警告,则一切正常。是的,使用缓冲区读写数据确实更快是实现此版本cp程序的更好方法。由于它可以一次从一个文件中读取多个数据到内存中,所以程序不需要频繁地读取数据。对于小文件,您可能不会注意到使用这两种方案之间的区别,但是如果您需要复制大文件,或者在较慢的介质(例如通过网络连接)上复制数据时,您会注意到一个明显的差距。我使用Linuxtime命令进行比较。此命令运行另一个程序并告诉您该程序花费了多长时间。对于我的测试,我想看看所用时间的差异,所以我在系统上复制了一个628MB的CD-ROM映像文件。我首先使用标准的Linuxcp命令复制图像文件,看看需要多长时间。我从运行Linux的cp命令开始,我也避免使用Linux的内置文件缓存系统,这样它就不会给程序带来误导性的性能提升。使用Linuxcp进行测试,总共花费了不到一秒的时间:$timecpFD13LIVE.isotmpfilereal0m0.040suser0m0.001ssys0m0.003s运行我自己实现的cp命令版本,复制同一个文件花费了更长的时间。一次复制文件一个字符花费了将近五秒钟:$time./cpFD13LIVE.isotmpfilereal0m4.823suser0m4.100ssys0m0.571s从输入读取数据到缓冲区,然后写入该缓冲区它要快得多导入和导出文件。使用此方法复制文件只需不到一秒:$time./cp2FD13LIVE.isotmpfilereal0m0.944suser0m0.224ssys0m0.608s我演示的cp程序使用200个字符的缓冲区大小。我敢肯定,如果一次将更多文件数据读入内存,程序会运行得更快。然而,通过这种比较,您已经看到了性能上的巨大差异,即使缓冲区只有200个字符也是如此。