在 C 中读取和打印 .txt 文件行的最清晰方法
Posted
技术标签:
【中文标题】在 C 中读取和打印 .txt 文件行的最清晰方法【英文标题】:Clearest way to read and print .txt file lines in C 【发布时间】:2012-12-13 07:54:09 【问题描述】:有很多方法描述了如何使用各种方法来打印本网站上的文本文件的行:
Posix-style, reading IP addresses, Fixed line length。它们似乎都是针对特定示例量身定制的。
如果有最清晰、最简洁和最简单的方法来简单:打印每一行,那就太好了任何文本文件到屏幕上。最好详细说明每一行的作用。
简洁明了的要点。
【问题讨论】:
你想做什么?你想转储整个文件吗? 在 UNIX 上,它被称为cat
。
@benjarobin 我想将文本文件的每一行打印到屏幕上。如果文件有 5 行,我想要最清晰的方法来打开它并打印这 5 行。就我的实际代码而言;我没有具体的用途。如果能够很好地掌握执行这个简单概念的最佳方法,那就太好了。
【参考方案1】:
#include <stdio.h>
static void cat(FILE *fp)
char buffer[4096];
size_t nbytes;
while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), fp)) != 0)
fwrite(buffer, sizeof(char), nbytes, stdout);
int main(int argc, char **argv)
FILE *fp;
const char *file;
while ((file = *++argv) != 0)
if ((fp = fopen(file, "r")) != 0)
cat(fp);
fclose(fp);
return(0);
cat()
函数不是绝对必要的,但我宁愿使用它。主程序逐步执行每个命令行参数并打开命名文件。如果成功,它会调用cat()
函数来打印其内容。由于对fopen()
的调用未指定"rb"
,因此它作为文本文件打开。如果文件未打开,此代码会静默忽略该问题。如果没有指定文件,则根本不打印任何内容。
cat()
函数一次只读取最多 4096 字节的文本块,并将它们写入标准输出(“屏幕”)。当没有更多内容可阅读时,它就会停止。
如果你想在没有指定文件的情况下扩展代码来读取标准输入,那么你可以使用:
if (argc == 1)
cat(stdin);
else
...while loop as now...
这是将cat()
函数写成如图所示的原因之一。
此代码不直接关注换行符——或任何类型的行。如果你想一次一行地正式处理它,那么你可以做几件事:
static void cat(FILE *fp)
char buffer[4096];
while (fgets(buffer, sizeof(buffer), fp) != 0)
fputs(buffer, stdout);
这将一次读取和写入一行。如果任何一行超过 4095 字节,它将在两次或更多操作中读取该行,并在相同数量的操作中写入。请注意,这假定使用 fread()
和 fwrite()
的版本不采用文本文件。在 POSIX 系统上,带有 fread()
和 fwrite()
的版本将处理数据中带有空字节 ('\0'
) 的任意二进制文件,但使用 fgets()
和 fputs()
的版本不会。到目前为止,这两个版本都是严格的标准 C(标准的任何版本),因为它们不使用任何特定于平台的扩展;它们与代码一样可移植。
另外,如果你有 POSIX 2008 getline()
函数,你可以使用它,但你也需要 #include <stdlib.h>
(因为你最终不得不释放它分配的内存):
static void cat(FILE *fp)
char *buffer = 0;
size_t buflen = 0;
while (getline(&buffer, &buflen, fp) != -1)
fputs(buffer, stdout);
free(buffer);
此版本也不会处理二进制数据(即其中包含空字节的数据)。当然,它可以升级为:
static void cat(FILE *fp)
char *buffer = 0;
size_t buflen = 0;
ssize_t nbytes;
while ((nbytes = getline(&buffer, &buflen, fp)) != -1)
fwrite(buffer, sizeof(char), nbytes, stdout);
free(buffer);
getline()
函数报告它读取了多少字节(之后有一个空字节),但 fwrite()
函数是唯一一个接受任意字节流并将它们全部写入给定流的函数。
【讨论】:
为什么是固定大小的缓冲区?使用 stat 调用 malloc 并不难,而且更安全、更便携,更不用说更好了。 更安全?更便携?为什么 ?慢一点是的,记住堆栈上的所有内容很可能都在 CPU 缓存中...为什么使用 HEAP(malloc 不慢,但也不快)? malloc() 会导致额外的条件。另外:程序无论如何都是 I/O 绑定的,read_bunch + write_bunch 对磁盘 LRU 来说是灾难性的。 @Jonathan Leffler 在 python 中,将文件中的行打印到屏幕是 4 行。我知道 c 要复杂得多,但我希望有一个解决方案不到六倍的时间...... @Dlinet,这是非常出色的 C 代码。 Python 可以用更少的行数解决这个问题,但那是因为 Python 是一种比 C 更高级的语言。对于像这样的简单问题,Python 的优势在于;但是 C 让经验丰富的开发人员完全控制完成的工作和完成的方式。 Python 可以用更少的代码来解决这个问题……但是 Python 是用 C 编写的! (好吧,无论如何,CPython 是。还有其他风格的 Python。但 CPython 是第一位的,并且仍然是王者。)【参考方案2】:嗯,这是我最终提出的一个非常简短的解决方案。我想它有一些根本性的错误,否则它会被建议,但我想我会把它贴在这里并希望有人把它拆开:
#include <stdio.h>
main()
FILE *MyFile;
int c;
MyFile=fopen("C:\YourFile.txt","r");
c = fgetc(MyFile);
while (c!=EOF)
printf("%c",c);
c = fgetc(MyFile);
【讨论】:
有问题的是:(1)这是打印字符,而不是问题所要求的行; (2)在使用fopen()
的返回值之前没有检查文件是否打开成功; (3) 你对main()
的声明在C99 或C2011 中无效——它应该是int main(void)
或int main(int argc, char **argv)
(或者,在紧要关头,int main()
); (4) 使用putchar()
或fputc()
可能比使用printf()
输出单个字符更好; (5) 使用while ((c = fgetc(MyFile)) != EOF) putchar(c);
会更符合C 语言习惯; (6) 缺少fclose(MyFile)
。
+1 用于使用int c;
——这既正确又重要。严格来说,由于您为main()
编写了C89 定义,因此您应该在main()
的末尾使用return(0);
(给或带括号)。如果您的代码符合 C99 标准,您可以不这样做,但在我看来,最好将其包含在 C99 或 C2011 代码中。
@JonathanLeffler 谢谢乔纳森,这很有见地。我将更多地了解 C 的不同类型/年份及其 main() 声明!【参考方案3】:
@Dlinet,您正在尝试学习一些关于如何组织程序的有用课程。我不会发布代码,因为已经有一个非常好的答案;我不可能改进它。但我想向你推荐一本书。
这本书名为Pascal 中的软件工具。语言是 Pascal,而不是 C,但是对于阅读这本书来说,这不会造成严重的困难。他们开始实施像本例中的简单工具(在 UNIX 上称为 cat
),然后转向更高级的东西。他们不仅教授了有关如何组织此类程序的重要课程,还涵盖了语言设计问题。 (Pascal 中确实存在让他们烦恼的问题,如果您了解 C,您会意识到 C 没有这些问题。)
这本书现已绝版,但我在学习编写代码时发现它非常有价值。直到今天,所谓的“左角设计”方法对我都很有用。
我鼓励您在 Amazon 或其他任何地方找到使用过的副本。亚马逊使用的副本起价为 0.02 美元,外加 4 美元的运费。
http://www.amazon.com/Software-Tools-Pascal-Brian-Kernighan/dp/0201103427
学习本书中的程序并在 C 中实现它们将是一个教育练习。任何 Linux 系统都已经拥有这些程序的更强大和完全调试的版本,但它不会浪费您的时间通读这本书并学习如何编写这些东西。
或者,您可以在您的计算机上安装 FreePascal 并使用它来运行书中的程序。
祝你好运,愿你永远喜欢软件开发!
【讨论】:
+1:我从最初的 Software Tools 中学到了很多东西(使用 Ratfor — Rational Fortran 编写)。那本书,连同The Elements of Programming Style,对我来说都是非常有影响力的书,所有这些都是多年前的事了(其中 30 本书,也许还有一些备用)。但这与直接问题有些相切。【参考方案4】:如果您想要预烘焙的东西,POSIX 系统上有cat
。
如果你想自己写,这里是基本布局:
-
检查以确保文件名、权限和路径有效
在循环中读取直到换行符分隔符(在 Unix 上为 \n,在 Windows/DOS 上为 \r\n)
检查错误。如果是这样,打印错误并中止。
将行打印到屏幕。
重复
关键是,实际上并没有具体的方法来做到这一点。只需阅读,然后写,然后重复。通过一些错误检查,你又得到了 cat。
【讨论】:
谢谢,但我正在寻找的是在 c 编程语言中执行此操作的最佳方法。您提供的概念框架是合理的,但不是特定于语言的。示例:我是一名 python 程序员,在 python 中这个过程非常简单: f=open(filepath,"r") for line in f: print line f.close() @Dlinet:我想说的是,没有特别好的或漂亮的方法可以做到这一点。只是在 C 中,有很多文件代码。一个简单的任务很多。在 Ruby 中,我可以在一行中做到这一点,但 C 需要更多。查看代码的其他答案。很多。 我查看了其他一些答案。例如:我发布的第三个链接是11行,但仅适用于固定行。以上是关于在 C 中读取和打印 .txt 文件行的最清晰方法的主要内容,如果未能解决你的问题,请参考以下文章
求助大神,R语言怎样读取txt文件中第三列1000-2000行的数据