每种编程语言处理文件数据的方式不尽相同，Python 是这么干的。有些数据是临时的，它们在应用程序运行时存储在内存中，然后丢弃。但是有些数据是持久的。它们存储在硬盘驱动器上供以后使用，而且它们通常是用户最关心的东西。对于程序员来说，编写代码读写文件是很常见的，但每种语言处理该任务的方式都不同。本文演示了如何使用 Python 处理文件数据。安装 Python在 Linux 上，你可能已经安装了 Python。如果没有，你可以通过发行版软件仓库安装它。例如，在 CentOS 或 RHEL 上：$ sudo dnf install python3 在 macOS 上，你可以使用 MacPorts 或 Homebrew 安装。在 Windows 上，你可以使用 Chocolatey 安装。一旦安装了 Python，打开你最喜欢的文本编辑器，准备好写代码吧。使用 Python 向文件中写入数据如果你需要向一个文件中写入数据，记住有三个步骤：打开写入关闭这与你在计算机上编码、编辑照片或执行其他操作时使用的步骤完全相同。首先，打开要编辑的文档，然后进行编辑，最后关闭文档。在 Python 中，过程是这样的：f = open('example.txt', 'w') f.write('hello world') f.close() 这个例子中，第一行以写模式打开了一个文件，然后用变量 f 表示，我使用了 f 是因为它在 Python 代码中很常见，使用其他任意有效变量名也能正常工作。在打开文件时，有不同的模式：w 代表写入r+ 代表可读可写a 表示追加第二行表示向文件中写入数据，本例写入的是纯文本，但你可以写入任意类型的数据。最后一行关闭了文件。使用 with 语法写入数据对于快速的文件交互，常用有一种简短的方法可以写入数据。它不会使文件保持打开状态，所以你不必记得调用 close() 函数。相反，它使用 with 语法：with open('example.txt', 'a') as f: f.write('hello open source') 使用 Python 读取数据如果你或你的用户需要通过应用程序需要向文件中写入一些数据，然后你需要使用它们，那么你就需要读取文件了。与写入类似，逻辑一样：打开读取关闭同样的，这个逻辑反映了你一开始使用计算机就已知的内容。阅读文档，你可以打开、阅读，然后关闭。在计算机术语中，“打开”文件意味着将其加载到内存中。实际上，一个文本文件内容肯定不止一行。例如，你需要读取一个配置文件、游戏存档或乐队下一首歌曲的歌词，正如你打开一本实体书时，你不可能立刻读完整本书，代码也只能解析已经加载到内存中的文件。因此，你可能需要遍历文件的内容。f = open('example.tmp', 'r') for line in f: print(line) f.close() 示例的第一行指明使用 读 模式打开一个文件，然后文件交由变量 f 表示，但就像你写数据一样，变量名是任意的。f 并没有什么特殊的，它只是单词 “file” 的最简表示，所以 Python 程序员会经常使用它。在第二行，我们使用了 line，另一个任意变量名，用来表示 f 的每一行。这告诉 Python 逐行迭代文件的内容，并将每一行的内容打印到输出中（在本例中为终端或 IDLE）。使用 with 语法读取数据就像写入一样，使用 with 语法是一种更简短的方法读取数据。即不需要调用 close() 方法，方便地快速交互。with open('example.txt', 'r') as f: for line in f: print(line) 文件和 Python使用 Python 有很多方法向文件写入数据，包括用 JSON、YAML、TOML 等不同的格式写入。还有一个非常好的内置方法用于创建和维护 SQLite 数据库，以及许多库来处理不同的文件格式，包括 图像、音频和视频等。via: https://opensource.com/article/21/7/read-write-files-python作者：Seth Kenlon 选题：lujun9972 译者：MjSeven 校对：turbokernel本文由 LCTT 原创编译，Linux中国 荣誉推出
不同的编程语言是如何读写数据的
每种编程语言都有其独特的完成任务的方式，这也说明了为什么有这么多语言可供选择。在 Jim Hall 的《不同的编程语言如何完成相同的事情》文章中，他演示了 13 种不同的语言如何使用不同的语法来完成同一个任务。经验是，编程语言往往有很多相似之处。一旦你了解了一种编程语言，你就可以通过理解它的语法和结构来学习另一种。本着同样的精神，Jim 的文章比较了不同编程语言如何读写数据。无论数据来自配置文件还是用户创建的文件，在存储设备上处理数据都是程序员的常见任务。以这种方式涵盖所有编程语言是不切实际的，但最近的 Opensource.com 系列文章提供了对这些编程语言采用的不同方法的深入了解：CC++JavaGroovyLuaBashPython读写数据用计算机读写数据的过程和你在现实生活中读写数据的过程类似。要访问书中的数据，你首先要打开它，然后阅读单词或将生词写入书中，然后合上书。当程序需要从文件中读取数据时，你向程序传入一个文件位置，然后计算机将该数据读入内存中并解析它。同样，当程序需要将数据写入文件时，计算机会将新数据放入系统的内存写入缓冲区，然后将其同步到存储设备上的文件中。下面是这些操作的一些伪代码：在内存中加载文件。读取文件内容，或将数据写入文件。关闭文件。从文件中读取数据从 Opensource.com 系列文章的语言中，你可以看到读取文件的三种趋势。C在 C 语言中，打开文件可能涉及检索单个字符（直到 EOF 指示符，表示文件结束）或一个数据块，具体取决于你的需求和方法。根据你的目标，它可能感觉像一个主要是手工的过程，但这正是其他语言所模仿的。FILE *infile; int ch; infile = fopen(argv[1], "r"); do { ch = fgetc(infile); if (ch != EOF) { printf("%c", ch); } } while (ch != EOF); fclose(infile); 你还可以选择将文件的某些部分加载到系统缓冲区中，然后在缓冲区外工作。FILE *infile; char buffer[300]; infile = fopen(argv[1], "r"); while (!feof(infile)) { size_t buffer_length; buffer_length = fread(buffer, sizeof(char), 300, infile); } printf("%s", buffer); fclose(infile); C++C++ 简化了一些步骤，允许你将数据解析为字符串。std::string sFilename = "example.txt"; std::ifstream fileSource(sFilename); std::string buffer; while (fileSource >> buffer) { std::cout << buffer << std::endl; } JavaJava 和 Groovy 类似于 C++。它们使用名为 Scanner 的类来设置数据流或对象，这样就会包含你选择的文件内容。你可以通过标记（字节、行、整数等）扫描文件。File myFile = new File("example.txt"); Scanner myScanner = new Scanner(myFile); while (myScanner.hasNextLine()) { String line = myScanner.nextLine(); System.out.println(line); } myScanner.close(); Groovydef myFile = new File('example.txt') def myScanner = new Scanner(myFile) while (myScanner.hasNextLine()) { def line = myScanner.nextLine() println(line) } myScanner.close() LuaLua 和 Python 进一步抽象了整个过程。你不必有意识地创建数据流，你只需给一个变量赋值为 open 函数的返回值，然后解析该变量的内容。这种方式快速，最简且容易。myFile = io.open('example.txt', 'r') lines = myFile:read("*all") print(lines) myFile:close() Pythonf = open('example.tmp', 'r') for line in f: print(line) f.close() 向文件中写入数据就写代码来说，写入是读取的逆过程。因此，将数据写入文件的过程与从文件中读取数据基本相同，只是使用了不同的函数。C在 C 语言中，你可以使用 fputc 函数将字符写入文件：fputc(ch, outfile); 或者，你可以使用 fwrite 将数据写入缓冲区。fwrite(buffer, sizeof(char), buffer_length, outfile); C++因为 C++ 使用 ifstream 库为数据打开缓冲区，所以你可以像 C 语言那样将数据写入缓冲区（C++ 库除外）。std::cout << buffer << std::endl; Java在 Java 中，你可以使用 FileWriter 类来创建一个可以写入数据的对象。它的工作方式与 Scanner 类非常相似，只是方向相反。FileWriter myFileWriter = new FileWriter("example.txt", true); myFileWriter.write("Hello world\n"); myFileWriter.close(); Groovy类似地，Groovy 使用 FileWriter，但使用了稍微 “groovy” 的语法。new FileWriter("example.txt", true).with { write("Hello world\n") flush() } LuaLua 和 Python 很相似，都使用名为 open 的函数来加载文件，writer 函数来写入数据，close 函数用于关闭文件。myFile = io.open('example.txt', 'a') io.output(myFile) io.write("hello world\n") io.close(myFile) PythonmyFile = open('example.txt', 'w') myFile.write('hello world') myFile.close() File 模式许多语言在打开文件时会指定一个“模式”。模式有很多，但这是常见的定义：w 表示写入r 表示读取r+ 表示可读可写a 表示追加某些语言，例如 Java 和 Groovy，允许你根据用于加载文件的类来确定模式。无论编程语言以何种方式来确定文件模式，你都需要确保你是在 追加 数据，除非你打算用新数据覆盖文件。编程语言不像文件选择器那样，没有内置的提示来警告你防止数据丢失。新语言和旧把戏每种编程语言都有其独特完成任务的方式，这就是为什么有这么多语言可供选择。你可以而且应该选择最合适你的语言。但是，你一旦了解了编程的基本结构，你可以随意尝试其他语言，而不必担心不知道如何完成基本任务。通常情况下，实现目标的途径是相似的，所以只要你牢记基本概念，它们就很容易学习。via: https://opensource.com/article/21/7/programming-read-write作者：Alan Smithee 选题：lujun9972 译者：MjSeven 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
了解 Lua 如何处理数据的读写。有些数据是临时的，存储在 RAM 中，只有在应用运行时才有意义。但有些数据是要持久的，存储在硬盘上供以后使用。当你编程时，无论是简单的脚本还是复杂的工具套件，通常都需要读取和写入文件。有时文件可能包含配置选项，而另一些时候这个文件是你的用户用你的应用创建的数据。每种语言都会以不同的方式处理这项任务，本文将演示如何使用 Lua 处理文件数据。安装 Lua如果你使用的是 Linux，你可以从你的发行版软件库中安装 Lua。在 macOS 上，你可以从 MacPorts 或 Homebrew 安装 Lua。在 Windows 上，你可以从 Chocolatey 安装 Lua。安装 Lua 后，打开你最喜欢的文本编辑器并准备开始。用 Lua 读取文件Lua 使用 io 库进行数据输入和输出。下面的例子创建了一个名为 ingest 的函数来从文件中读取数据，然后用 :read 函数进行解析。在 Lua 中打开一个文件时，有几种模式可以启用。因为我只需要从这个文件中读取数据，所以我使用 r（代表“读”）模式：function ingest(file) local f = io.open(file, "r") local lines = f:read("*all") f:close() return(lines) end myfile=ingest("example.txt") print(myfile) 在这段代码中，注意到变量 myfile 是为了触发 ingest 函数而创建的，因此，它接收该函数返回的任何内容。ingest 函数返回文件的行数（从一个称为 lines 的变量中0。当最后一步打印 myfile 变量的内容时，文件的行数就会出现在终端中。如果文件 example.txt 中包含了配置选项，那么我会写一些额外的代码来解析这些数据，可能会使用另一个 Lua 库，这取决于配置是以 INI 文件还是 YAML 文件或其他格式存储。如果数据是 SVG 图形，我会写额外的代码来解析 XML，可能会使用 Lua 的 SVG 库。换句话说，你的代码读取的数据一旦加载到内存中，就可以进行操作，但是它们都需要加载 io 库。用 Lua 将数据写入文件无论你是要存储用户用你的应用创建的数据，还是仅仅是关于用户在应用中做了什么的元数据（例如，游戏保存或最近播放的歌曲），都有很多很好的理由来存储数据供以后使用。在 Lua 中，这是通过 io 库实现的，打开一个文件，将数据写入其中，然后关闭文件：function exgest(file) local f = io.open(file, "a") io.output(f) io.write("hello world\n") io.close(f) end exgest("example.txt") 为了从文件中读取数据，我以 r 模式打开文件，但这次我使用 a （用于”追加“）将数据写到文件的末尾。因为我是将纯文本写入文件，所以我添加了自己的换行符（/n）。通常情况下，你并不是将原始文本写入文件，你可能会使用一个额外的库来代替写入一个特定的格式。例如，你可能会使用 INI 或 YAML 库来帮助编写配置文件，使用 XML 库来编写 XML，等等。文件模式在 Lua 中打开文件时，有一些保护措施和参数来定义如何处理文件。默认值是 r，允许你只读数据：r 只读w 如果文件不存在，覆盖或创建一个新文件。r+ 读取和覆盖。a 追加数据到文件中，或在文件不存在的情况下创建一个新文件。a+ 读取数据，将数据追加到文件中，或文件不存在的话，创建一个新文件。还有一些其他的(例如，b 代表二进制格式)，但这些是最常见的。关于完整的文档，请参考 Lua.org/manual 上的优秀 Lua 文档。Lua 和文件和其他编程语言一样，Lua 有大量的库支持来访问文件系统来读写数据。因为 Lua 有一个一致且简单语法，所以很容易对任何格式的文件数据进行复杂的处理。试着在你的下一个软件项目中使用 Lua，或者作为 C 或 C++ 项目的 API。via: https://opensource.com/article/21/3/lua-files作者：Seth Kenlon 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
学习 Bash 读取和写入数据的不同方式，以及何时使用每种方法。当你使用 Bash 编写脚本时，有时你需要从一个文件中读取数据或向一个文件写入数据。有时文件可能包含配置选项，而另一些时候这个文件是你的用户用你的应用创建的数据。每种语言处理这个任务的方式都有些不同，本文将演示如何使用 Bash 和其他 POSIX shell 处理数据文件。安装 Bash如果你在使用 Linux，你可能已经有了 Bash。如果没有，你可以在你的软件仓库里找到它。在 macOS 上，你可以使用默认终端，Bash 或 Zsh，这取决于你运行的 macOS 版本。在 Windows 上，有几种方法可以体验 Bash，包括微软官方支持的 Windows Subsystem for Linux（WSL）。安装 Bash 后，打开你最喜欢的文本编辑器并准备开始。使用 Bash 读取文件除了是 shell 之外，Bash 还是一种脚本语言。有几种方法可以从 Bash 中读取数据。你可以创建一种数据流并解析输出, 或者你可以将数据加载到内存中。这两种方法都是有效的获取信息的方法，但每种方法都有相当具体的用例。在 Bash 中援引文件当你在 Bash 中 “ 援引 source ” 一个文件时，你会让 Bash 读取文件的内容，期望它包含有效的数据，Bash 可以将这些数据放入它建立的数据模型中。你不会想要从旧文件中援引数据，但你可以使用这种方法来读取配置文件和函数。（LCTT 译注：在 Bash 中，可以通过 source 或 . 命令来将一个文件读入，这个行为称为 “sourcing”，英文原意为“一次性（试）采购”、“寻找供应商”、“获得”等，考虑到 Bash 的语境和发音，我建议可以翻译为“援引”，或有不当，供大家讨论参考 —— wxy）例如，创建一个名为 example.sh 的文件，并输入以下内容：#!/bin/sh greet opensource.com echo "The meaning of life is $var" 运行这段代码，看见失败了：$ bash ./example.sh ./example.sh: line 3: greet: command not found The meaning of life is Bash 没有一个叫 greet 的命令，所以无法执行那一行，也没有一个叫 var 的变量记录，所以文件没有意义。为了解决这个问题，建立一个名为 include.sh 的文件：greet() { echo "Hello ${1}" } var=42 修改你的 example.sh 脚本，加入一个 source 命令：#!/bin/sh source include.sh greet opensource.com echo "The meaning of life is $var" 运行脚本，可以看到工作了：$ bash ./example.sh Hello opensource.com The meaning of life is 42 greet 命令被带入你的 shell 环境，因为它被定义在 include.sh 文件中，它甚至可以识别参数（本例中的 opensource.com）。变量 var 也被设置和导入。在 Bash 中解析文件另一种让数据“进入” Bash 的方法是将其解析为数据流。有很多方法可以做到这一点. 你可以使用 grep 或 cat 或任何可以获取数据并管道输出到标准输出的命令。另外，你可以使用 Bash 内置的东西：重定向。重定向本身并不是很有用，所以在这个例子中，我也使用内置的 echo 命令来打印重定向的结果：#!/bin/sh echo $( < include.sh ) 将其保存为 stream.sh 并运行它来查看结果：$ bash ./stream.sh greet() { echo "Hello ${1}" } var=42 $ 对于 include.sh 文件中的每一行，Bash 都会将该行打印（或 echo）到你的终端。先用管道把它传送到一个合适的解析器是用 Bash 读取数据的常用方法。例如, 假设 include.sh 是一个配置文件, 它的键和值对用一个等号（=）分开. 你可以用 awk 甚至 cut 来获取值：#!/bin/sh myVar=`grep var include.sh | cut -d'=' -f2` echo $myVar 试着运行这个脚本：$ bash ./stream.sh 42 用 Bash 将数据写入文件无论你是要存储用户用你的应用创建的数据，还是仅仅是关于用户在应用中做了什么的元数据（例如，游戏保存或最近播放的歌曲），都有很多很好的理由来存储数据供以后使用。在 Bash 中，你可以使用常见的 shell 重定向将数据保存到文件中。例如, 要创建一个包含输出的新文件, 使用一个重定向符号：#!/bin/sh TZ=UTC date > date.txt 运行脚本几次：$ bash ./date.sh $ cat date.txt Tue Feb 23 22:25:06 UTC 2021 $ bash ./date.sh $ cat date.txt Tue Feb 23 22:25:12 UTC 2021 要追加数据，使用两个重定向符号：#!/bin/sh TZ=UTC date >> date.txt 运行脚本几次：$ bash ./date.sh $ bash ./date.sh $ bash ./date.sh $ cat date.txt Tue Feb 23 22:25:12 UTC 2021 Tue Feb 23 22:25:17 UTC 2021 Tue Feb 23 22:25:19 UTC 2021 Tue Feb 23 22:25:22 UTC 2021 Bash 轻松编程Bash 的优势在于简单易学，因为只需要一些基本的概念，你就可以构建复杂的程序。完整的文档请参考 GNU.org 上的 优秀的 Bash 文档。via: https://opensource.com/article/21/3/input-output-bash作者：Seth Kenlon 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
学习如何用 C 语言来进行文件输入输出操作
理解 I/O 有助于提升你的效率。如果你打算学习 C 语言的输入、输出，可以从 stdio.h 包含文件开始。正如你从其名字中猜到的，该文件定义了所有的标准（“std”）的输入和输出（“io”）函数。大多数人学习的第一个 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 <stdio.h> 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 <stdio.h> 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 个字符的缓冲区，你也已经看到了性能上的巨大差异。via: https://opensource.com/article/21/3/file-io-c作者：Jim Hall 选题：lujun9972 译者：wyxplus 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出