#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() 函数是唯一一个接受任意字节流并将它们全部写入给定流的函数。