大多数人学习的第一个 stdio.h 的函数是打印格式化输出的 printf 函数。或者是用来打印一个字符串的 puts 函数。这些函数非常有用,可以将信息打印给用户,但是如果你想做更多的事情,则需要了解其他函数。

你可以通过编写一个常见 Linux 命令的副本来了解其中一些功能和方法。cp 命令主要用于复制文件。如果你查看 cp 的帮助手册,可以看到 cp 命令支持非常多的参数和选项。但最简单的功能,就是复制文件:

cp infile outfile

你只需使用一些读写文件的基本函数,就可以用 C 语言来自己实现 cp 命令。

一次读写一个字符

你可以使用 fgetc 和 fputc 函数轻松地进行输入输出。这些函数一次只读写一个字符。该用法被定义在 stdio.h,并且这也很浅显易懂:fgetc 是从文件中读取一个字符,fputc 是将一个字符保存到文件中。

int fgetc(FILE *stream);

int fputc(int c, FILE *stream);

编写 cp 命令需要访问文件。在 C 语言中,你使用 fopen 函数打开一个文件,该函数需要两个参数:文件名和打开文件的模式。模式通常是从文件读取(r)或向文件写入(w)。打开文件的方式也有其他选项,但是对于本教程而言,仅关注于读写操作。

因此,将一个文件复制到另一个文件就变成了打开源文件和目标文件,接着,不断从第一个文件读取字符,然后将该字符写入第二个文件。fgetc 函数返回从输入文件中读取的单个字符,或者当文件完成后返回文件结束标记(EOF)。一旦读取到 EOF,你就完成了复制操作,就可以关闭两个文件。该代码如下所示:

do {

ch = fgetc(infile);

if (ch != EOF) {

fputc(ch, outfile);

}

} while (ch != EOF);

你可以使用此循环编写自己的 cp 程序,以使用 fgetc 和 fputc 函数一次读写一个字符。cp.c 源代码如下所示:

#include

int

main(int argc, char **argv)

{

FILE *infile;

FILE *outfile;

int ch;

/* parse the command line */

/* usage: cp infile outfile */

if (argc != 3) {

fprintf(stderr, "Incorrect usage\n");

fprintf(stderr, "Usage: cp infile outfile\n");

return 1;

}

/* open the input file */

infile = fopen(argv[1], "r");

if (infile == NULL) {

fprintf(stderr, "Cannot open file for reading: %s\n", argv[1]);

return 2;

}

/* open the output file */

outfile = fopen(argv[2], "w");

if (outfile == NULL) {

fprintf(stderr, "Cannot open file for writing: %s\n", argv[2]);

fclose(infile);

return 3;

}

/* copy one file to the other */

/* use fgetc and fputc */

do {

ch = fgetc(infile);

if (ch != EOF) {

fputc(ch, outfile);

}

} while (ch != EOF);

/* done */

fclose(infile);

fclose(outfile);

return 0;

}

你可以使用 gcc 来将 cp.c 文件编译成一个可执行文件:

$ gcc -Wall -o cp cp.c

-o cp 选项告诉编译器将编译后的程序保存到 cp 文件中。-Wall 选项告诉编译器提示所有可能的警告,如果你没有看到任何警告,则表示一切正常。

读写数据块

通过每次读写一个字符来实现自己的 cp 命令可以完成这项工作,但这并不是很快。在复制“日常”文件(例如文档和文本文件)时,你可能不会注意到,但是在复制大型文件或通过网络复制文件时,你才会注意到差异。每次处理一个字符需要大量的开销。

实现此 cp 命令的一种更好的方法是,读取一块的输入数据到内存中(称为缓存),然后将该数据集合写入到第二个文件。这样做的速度要快得多,因为程序可以一次读取更多的数据,这就就减少了从文件中“读取”的次数。

你可以使用 fread 函数将文件读入一个变量中。这个函数有几个参数:将数据读入的数组或内存缓冲区的指针(ptr),要读取的最小对象的大小(size),要读取对象的个数(nmemb),以及要读取的文件(stream):

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

不同的选项为更高级的文件输入和输出(例如,读取和写入具有特定数据结构的文件)提供了很大的灵活性。但是,在从一个文件读取数据并将数据写入另一个文件的简单情况下,可以使用一个由字符数组组成的缓冲区。

你可以使用 fwrite 函数将缓冲区中的数据写入到另一个文件。这使用了与 fread 函数有相似的一组选项:要从中读取数据的数组或内存缓冲区的指针,要读取的最小对象的大小,要读取对象的个数以及要写入的文件。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

如果程序将文件读入缓冲区,然后将该缓冲区写入另一个文件,则数组(ptr)可以是固定大小的数组。例如,你可以使用长度为 200 个字符的字符数组作为缓冲区。

在该假设下,你需要更改 cp 程序中的循环,以将数据从文件读取到缓冲区中,然后将该缓冲区写入另一个文件中:

while (!feof(infile)) {

buffer_length = fread(buffer, sizeof(char), 200, infile);

fwrite(buffer, sizeof(char), buffer_length, outfile);

}

这是更新后的 cp 程序的完整源代码,该程序现在使用缓冲区读取和写入数据:

#include

int

main(int argc, char **argv)

{

FILE *infile;

FILE *outfile;

char buffer[200];

size_t buffer_length;

/* parse the command line */

/* usage: cp infile outfile */

if (argc != 3) {

fprintf(stderr, "Incorrect usage\n");

fprintf(stderr, "Usage: cp infile outfile\n");

return 1;

}

/* open the input file */

infile = fopen(argv[1], "r");

if (infile == NULL) {

fprintf(stderr, "Cannot open file for reading: %s\n", argv[1]);

return 2;

}

/* open the output file */

outfile = fopen(argv[2], "w");

if (outfile == NULL) {

fprintf(stderr, "Cannot open file for writing: %s\n", argv[2]);

fclose(infile);

return 3;

}

/* copy one file to the other */

/* use fread and fwrite */

while (!feof(infile)) {

buffer_length = fread(buffer, sizeof(char), 200, infile);

fwrite(buffer, sizeof(char), buffer_length, outfile);

}

/* done */

fclose(infile);

fclose(outfile);

return 0;

}

由于你想将此程序与其他程序进行比较,因此请将此源代码另存为 cp2.c。你可以使用 gcc 编译程序:

$ gcc -Wall -o cp2 cp2.c

和之前一样,-o cp2 选项告诉编译器将编译后的程序保存到 cp2 程序文件中。-Wall 选项告诉编译器打开所有警告。如果你没有看到任何警告,则表示一切正常。

是的,这真的更快了

使用缓冲区读取和写入数据是实现此版本 cp 程序更好的方法。由于它可以一次将文件的多个数据读取到内存中,因此该程序不需要频繁读取数据。在小文件中,你可能没有注意到使用这两种方案的区别,但是如果你需要复制大文件,或者在较慢的介质(例如通过网络连接)上复制数据时,会发现明显的差距。

我使用 Linux time 命令进行了比较。此命令可以运行另一个程序,然后告诉你该程序花费了多长时间。对于我的测试,我希望了解所花费时间的差距,因此我复制了系统上的 628 MB CD-ROM 镜像文件。

我首先使用标准的 Linux 的 cp 命令复制了映像文件,以查看所需多长时间。一开始通过运行 Linux 的 cp 命令,同时我还避免使用 Linux 内置的文件缓存系统,使其不会给程序带来误导性能提升的可能性。使用 Linux cp 进行的测试,总计花费不到一秒钟的时间:

$ time cp FD13LIVE.iso tmpfile

real 0m0.040s

user 0m0.001s

sys 0m0.003s

运行我自己实现的 cp 命令版本,复制同一文件要花费更长的时间。每次读写一个字符则花了将近五秒钟来复制文件:

$ time ./cp FD13LIVE.iso tmpfile

real 0m4.823s

user 0m4.100s

sys 0m0.571s

从输入读取数据到缓冲区,然后将该缓冲区写入输出文件则要快得多。使用此方法复制文件花不到一秒钟:

$ time ./cp2 FD13LIVE.iso tmpfile

real 0m0.944s

user 0m0.224s

sys 0m0.608s

我演示的 cp 程序使用了 200 个字符大小的缓冲区。我确信如果一次将更多文件数据读入内存,该程序将运行得更快。但是,通过这种比较,即使只有 200 个字符的缓冲区,你也已经看到了性能上的巨大差异。

html输入输出文件,学习如何用 C 语言来进行文件输入输出操作相关推荐

  1. c语言创建excel文件6,怎么利用c语言创建excel文件

    怎么利用c语言创建excel文件 想要利用c语言创建excel文件再把它导入excel其实很简单,如果数据简单的话,可以使用CSV(逗号分隔值)格式的文件.CSV格式的文件可以用OfficeExcel ...

  2. c语言怎样用格式化文件存储,如何用格式化的方式读写文件

    对格式会来说,C语言的格式读写文件是很有要求的,在前面我们已经讲解了如何去进行字符的输入输出,但事实真相,数据的类型是很丰富的,而且大家已经熟悉了用printf和scanf函数进行格式化的输入输出,他 ...

  3. c语言ATM机文件储存账号密码,C语言ATM(有文件输入输出).doc

    C语言ATM(有文件输入输出) #include "stdio.h" #include "stdlib.h" #include "conio.h&qu ...

  4. 如何用c语言从txt文件中读取数据

    用C语言从txt文件中读取数据,可以使用C标准库文件自带的文件接口函数进行操作. 一.打开文件: FILE *fopen(const char *filename, const char *mode) ...

  5. 如何用C语言简单加密文件+

    上一篇文章写完以后,收到了很多朋友的私信,希望我能写出一个较为完善的利用C语言简单加密文件的代码,今天花了点时间终于调试完了,相比于上一篇文章的代码的话这里做了一些改进: 1.加密文件的数据改为原文件 ...

  6. 如何用C语言清空特定文件夹中的所有文件

    最近笔者在做一个有关计算机视觉的项目,需要对提前的视频帧进行实验,当数据量很大且文件夹中的子文件夹和文件很多时,手工删除这些文件不现实,笔者今天写了一个程序,通过机器自动删除所有相关文件,十分快速,删 ...

  7. linux怎么创建新的c语言文件夹,如何用c语言创建文件夹

    参考: ########################################################## 判断文件夹是否存在: 在windows环境下头文件为: #include ...

  8. C语言实现文件的局部修改,C语言:在文件的指定位置实现局部修改,而无需重写文件的其他部分...

    前言(可跳过) 在进行大型文件的读写操作时,若采用读打开文件a,再将"a中修改删除位置之前的内容+修改删除的内容+a中修改删除位置之后的内容"保存到文件b,关闭并删除文件a,将文件 ...

  9. c语言中把文件看成什么流,C语言中的文件流

    所谓文件(file)一般指存储在外部介质上数据的集合,比如我们经常使用的mp3.mp4.txt.bmp.jpg.exe.rmvb等等.这些文件各有各的用途,我们通常将它们存放在磁盘或者可移动盘等介质中 ...

  10. c语言中文件类型只有6,C语言中的文件类型只有哪两种

    C语言中的文件类型只有ASCII文件和二进制文件两种.ASCII码文件通常用于存放输入数据及程序的最终结果:二进制文件用于暂存程序的中间结果,供另一段程序读取. C语言中的文件类型只有ASCII文件和 ...

最新文章

  1. HD 1003 Max Sum (最大字段和问题)
  2. 采购订单模板_采购必备:如何搭建合规的采购流程
  3. java 实现 tcp_java实现TCP通信
  4. 初学ActionScript 3.0(一):Hello World
  5. mysql limti_mysql优化
  6. opengl学习笔记(四)
  7. 学习C# 3.0语法笔记(1)
  8. 解决Windows 2003终端服务许可证过期的办法
  9. L1-026 I Love GPLT
  10. 倾囊传授DELL主板BIOS设置
  11. 如何使用键盘操控苹果Mac?
  12. 心电自动分析技术综述-Phililps DXL / GE Marquette / Glasgow / HES Hannover / Mortara
  13. 在VirtualBox的虚拟机上安装和使用NCS2(intel movidius stick 2)
  14. python10的负n次方_python的次方
  15. gbk、gb2312、big5、unicode、utf-8
  16. 测试开发面试题(一)-----appium相关
  17. win10下装黑苹果双系统_win10下安装双系统:黑苹果10.13.5(17F77)教程!
  18. 网上图书订阅系统的WBS图,和WBS字典
  19. google thumbnailator简介
  20. 一般人看不透!沉默的大多数用户才是产品发展的关键!

热门文章

  1. 论文笔记_S2D.38_2018-CVPR_DORN_用于单目深度估计的深度有序回归网络
  2. Ubuntu 16.04下安装 PCL简单方法
  3. 数值分析(6)-函数逼近的基本概念
  4. C++读写txt文件方式以及基于opencv的Mat数据类型读写txt文件类型
  5. 图像/视频超分之降质过程
  6. 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则
  7. opencv图像连通区域分析
  8. orcale物化视图刷新
  9. 企业架构-发布在线文档【企业架构框架-TOGAF v0.2.pdf】
  10. Python网络爬虫第一弹《Python网络爬虫相关基础概念》