14-一个简单的文件压缩程序
13.3 一个简单的文件压缩程序
下面的程序示例把一个文件中选定的数据拷贝到另一个文件中。该程序同时打开了两个文件,以 "r" 模式打开一个,以 "w" 模式打开另一个。该程序(程序清单13.2)以保留每3个字符中的第1个字符的方式压缩第1个文件的内容。最后,把压缩后的文本存入第2个文件。第2个文件的名称是第1个文件名加上 .red 后缀(此处的 red 代表 reduced )。使用命令行参数,同时打开多个文件,以及在原文件名后面加上后缀,都是相当有用的技巧。这种压缩方式有限,但是也有它的用途(很容易把该程序改成用标准I/O而不是命令行参数提供文件名)。
程序清单13.2 reducto.c 程序
// reducto.c –把文件压缩成原来的1/3!
#include <stdio.h>
#include <stdlib.h> // 提供 exit()的原型
#include <string.h> // 提供 strcpy()、strcat()的原型
#define LEN 40
int main(int argc, char *argv [])
{
FILE *in, *out; // 声明两个指向 FILE 的指针
int ch;
char name[LEN]; // 存储输出文件名
int count = 0;
// 检查命令行参数
if (argc < 2)
{
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
// 设置输入
if ((in = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "I couldn't open the file \"%s\"\n",
argv[1]);
exit(EXIT_FAILURE);
}
// 设置输出
strncpy(name, argv[1], LEN - 5); // 拷贝文件名
name[LEN - 5] = '\0';
strcat(name, ".red"); // 在文件名后添加.red
if ((out = fopen(name, "w")) == NULL)
{ // 以写模式打开文件
fprintf(stderr, "Can't create output file.\n");
exit(3);
}
// 拷贝数据
while ((ch = getc(in)) != EOF)
if (count++ % 3 == 0)
putc(ch, out); // 打印3个字符中的第1个字符
// 收尾工作
if (fclose(in) != 0 || fclose(out) != 0)
fprintf(stderr, "Error in closing files\n");
return 0;
}
假设可执行文件名是 reducto ,待读取的文件名为 eddy ,该文件中包含下面一行内容:
So even Eddy came oven ready.
命令如下:
reducto eddy
待写入的文件名为 eddy.red 。该程序把输出显示在 eddy.red 中,而不是屏幕上。打开 eddy.red ,内容如下:
Send money
该程序示例演示了几个编程技巧。我们来仔细研究一下。
fprintf() 和 printf() 类似,但是 fprintf() 的第1个参数必须是一个文件指针。程序中使用 stderr 指针把错误消息发送至标准错误,C标准通常都这么做。
为了构造新的输出文件名,该程序使用 strncpy() 把名称 eddy 拷贝到数组 name 中。参数 LEN-5 为 .red 后缀和末尾的空字符预留了空间。如果 argv[2] 字符串比 LEN-5 长,就拷贝不了空字符。出现这种情况时,程序会添加空字符。调用 strncpy() 后, name 中的第1个空字符在调用 strcat() 函数时,被 .red 的 . 覆盖,生成了 eddy.red 。程序中还检查了是否成功打开名为 eddy.red 的文件。这个步骤在一些环境中相当重要,因为像 strange.c.red 这样的文件名可能是无效的。例如,在传统的DOS环境中,不能在后缀名后面添加后缀名(MS-DOS使用的方法是用 .red 替换现有后缀名,所以 strange.c 将变成 strange.red 。例如,可以用 strchr() 函数定位(如果有的话),然后只拷贝点前面的部分即可)。
该程序同时打开了两个文件,所以我们要声明两个 FILE 指针。注意,程序都是单独打开和关闭每个文件。同时打开的文件数量是有限的,这个限制取决于系统和实现,范围一般是10~20。相同的文件指针可以处理不同的文件,前提是这些文件不需要同时打开。