4.6 Write a utility like cp(1) that copies a file containing holes, without writing the bytes of 0 to the output file.
我自己写了一整程序来完成这个操作。
首先要使用fig3.2的程序生成一个带有hole的文件file.hole。
#include "apue.h" #include <fcntl.h> int main(int argc, char **argv) { if (argc != 3) err_quit("usage: mycp <sourcefile> <destfile>"); int fds, fdd; if ( (fds = open(argv[1], O_RDONLY, 0)) < 0) err_sys("can't open: %s", argv[1]); if ( (fdd = open(argv[2], O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) < 0) err_sys("can't open: %s", argv[2]); struct stat statbuf; off_t srcsize; if (fstat(fds, &statbuf) < 0) err_sys("stat error"); srcsize = statbuf.st_size; char buf; int n; off_t offset = 0; while (offset < srcsize) { if ( (n = read(fds, &buf, 1)) < 0) { err_sys("read error"); } else if (n > 0 && buf != 0) { write(fdd, &buf, n); offset += n; } else { offset++; continue; /* ignore the hole */ } } return 0; }
主要思想是这样的:先用stat()函数获得文件file.hole的大小。然后每次读取一个byte的数据,如果不是0,就把它写入到目标文件中。直至到达file.hole文件的末尾。
可能的改进:不适用fstat()函数,只使用read()函数,一直读到文件的末尾(EOF),read()函数自会返回0,此时结束程序即可。
#include "apue.h" #include <fcntl.h> int main(int argc, char **argv) { if (argc != 3) err_quit("usage: mycp <sourcefile> <destfile>"); int fds, fdd; if ( (fds = open(argv[1], O_RDONLY, 0)) < 0) err_sys("can't open: %s", argv[1]); if ( (fdd = open(argv[2], O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR)) < 0) err_sys("can't open: %s", argv[2]); char buf; int n; while ( (n = read(fds, &buf, 1)) > 0) { /* read() change the 'current file offset' value in file table entry */ if (buf != 0) write(fdd, &buf, n); } if (n < 0) err_sys("read error"); return 0; }
结果:
cat@Ubuntu:~/apue/apue.2e/wangshuo$ od -c file.hole |
cat@Ubuntu:~/apue/apue.2e/wangshuo$ od -c output |