每个人都要有一个骨灰级的爱好,不为金钱,而纯粹是为了在这个领域享受追寻真理的快乐。
分类: LINUX
2013-02-08 01:23:30
利用fread/fwrite函数分批读取文本内容,对目标文件大小适应性好.
#include#include #include #include #include #define BUFSIZE 8192 #define SWPFILE "./.swp" static struct option opts[] = { {.name = "number", .has_arg = 1, .val = 'n'}, {.name = "content", .has_arg = 1, .val = 'c'}, {.name = "file", .has_arg = 1, .val = 'f'}, {.name = "help", .has_arg = 0, .val = 'h'}, {NULL} }; static void print_help(void) { printf("-h Print this help\n"); printf("-n Insert the number of rows \n"); printf("-c Insert content\n"); printf("-f Destination file\n"); exit(-1); } static int edit_file(int line, char const *file, char const *content) { FILE *fd_in, *fd_out; int num , n , tmp, pos; char buf[BUFSIZE], *p; if ((fd_in = fopen(file, "r")) == NULL) { fprintf(stderr, "open file faild\n"); return -1; } if ((fd_out = fopen(SWPFILE, "w")) == NULL) { fprintf(stderr, "create file faild\n"); return -2; } num = 0; pos = 0; while((n = fread(buf, 1, BUFSIZE, fd_in)) > 0) { p = buf; tmp = n; //读取字节数递减,p指针递增,逐个判断字符是否为换行符,直到遍历完buf. while (tmp > 0) { if (*p++ == '\n') { num++; if (num == line) { //把pos偏移位定位到找到的第line个\n位置 pos += p - buf; goto find; } } tmp--; } pos += n; } find: fseek(fd_in, 0, SEEK_SET); //把偏移位重新回到文件起始处 tmp = 0; if (pos > 0) { while((n = fread(buf, 1, BUFSIZE, fd_in)) > 0) { if (tmp + n < pos) { //把面前的数据写入fd_out fwrite(buf, 1, n, fd_out); } else { //把第N个\n之前到buf开始的这段数据写入fd_out fwrite(buf, 1, pos - tmp, fd_out); fprintf(fd_out, "%s\n", content); //把第N个\n剩下的数据写入fd_out fwrite(buf + (pos - tmp), 1, n - (pos - tmp), fd_out); break; } tmp += n; } } else { fprintf(fd_out, "%s\n", content); } //这里继续把剩下的文件写完,内核知道偏移位是多少. while((n = fread(buf, 1, BUFSIZE, fd_in)) > 0) { fwrite(buf, 1, n, fd_out); } fclose(fd_in); fclose(fd_out); return 0; } static void mv_file(char const *file) { if (rename(SWPFILE, file) < 0) { printf("rename faild: %s\n", strerror(errno)); } } int main(int argc, char **argv) { int n = 0; char *content = NULL, *file = NULL; char c; while((c = getopt_long(argc, argv, "hn:c:f:", opts, NULL)) != -1) { switch(c) { case 'n': n = atoi(optarg); break; case 'c': content = optarg; break; case 'f': file = optarg; break; case 'h': default: print_help(); } } if (content == NULL) { fprintf(stderr, "content is null\n"); exit(-1); } else if (file == NULL) { fprintf(stderr, "Please enter the file name\n"); exit(-2); } if (edit_file(n, file, content) < 0) { fprintf(stderr, "edit file faild\n"); exit(-3); } else { mv_file(file); } return 0; }
利用存储映射I/O,优点是效率高,但是目标文件不宜太大.
#include#include #include #include #include #include #include #define SWPFILE "./.swp" #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) static struct option opts[] = { {.name = "number", .has_arg = 1, .val = 'n'}, {.name = "content", .has_arg = 1, .val = 'c'}, {.name = "file", .has_arg = 1, .val = 'f'}, {.name = "help", .has_arg = 0, .val = 'h'}, {NULL} }; static void print_help(void) { printf("-h Print this help\n"); printf("-n Insert the number of rows \n"); printf("-c Insert content\n"); printf("-f Destination file\n"); exit(-1); } static int edit_file(int line, char const *file, char const *content) { int fd_in, fd_out, num=0; long int offset; char *src, *dst, *p; struct stat statbuf; int bufsize = strlen(content); char buf[bufsize + 1]; memcpy(buf, content, bufsize); buf[bufsize] = '\n'; if ((fd_in = open(file, O_RDONLY)) < 0) { fprintf(stderr, "can't open %s for reading\n", file); exit(-11); } if ((fd_out = open(SWPFILE, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0) { fprintf(stderr, "can't creat temp file\n"); exit(-12); } /* need size of input file */ if (fstat(fd_in, &statbuf) < 0) { fprintf(stderr, "fstat error\n"); exit(-13); } /* 把偏移位拉到最后,然后写入一个空字节,这样才能改变文件大小 在写入之间就要创建好目标文件的大小, 源文件 + 插入内容 */ if (lseek(fd_out, statbuf.st_size + bufsize, SEEK_SET) == -1) { fprintf(stderr, "lseek error\n"); exit(-14); } if (write(fd_out, "", 1) != 1) { fprintf(stderr, "write error\n"); exit(-15); } if ((src = (char *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd_in, 0)) == MAP_FAILED) { fprintf(stderr, "mmap error for input\n"); exit(-16); } if ((dst = (char *)mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_out, 0)) == MAP_FAILED) { fprintf(stderr, "mmap error for output\n"); exit(-17); } /* 找出第n个换行符的偏移位 */ p = src; for (offset = 1; offset < statbuf.st_size; offset++) { if (*p++ == '\n') { num++; if (num == line) { break; } } } memcpy(dst, src, offset); dst += offset; memcpy(dst, buf, bufsize + 1); dst += bufsize + 1; memcpy(dst, src + offset, statbuf.st_size -offset); return 0; } static void mv_file(char const *file) { if (rename(SWPFILE, file) < 0) { printf("rename faild: %s\n", strerror(errno)); exit(23); } } int main(int argc, char **argv) { int n = 0; char *content = NULL, *file = NULL; char c; while((c = getopt_long(argc, argv, "hn:c:f:", opts, NULL)) != -1) { switch(c) { case 'n': n = atoi(optarg); break; case 'c': content = optarg; break; case 'f': file = optarg; break; case 'h': default: print_help(); } } if (content == NULL) { fprintf(stderr, "content is null\n"); exit(-1); } else if (file == NULL) { fprintf(stderr, "Please enter the file name\n"); exit(-2); } if (edit_file(n, file, content) < 0) { fprintf(stderr, "edit file faild\n"); exit(-3); } else { mv_file(file); } return 0; }