方法一:利用递归
/* 功能:文件以行为单位,逆顺输出到新文件 示例:file1.txt为: 12 34 56 要求逆顺后输出到文件file2.txt,结果为: 56 34 12 */ #include <stdio.h> #include <string.h> // 递归读取文件 void doread(FILE *fp1, FILE *fp2, int next) { char buf[1024] = {0}; if(next && fgets(buf, 1024, fp1) != NULL) doread(fp1, fp2, next); else if(next) next = 0; // 读到文件尾 fwrite(buf, strlen(buf), 1, fp2); // 写入新文件 } int run(char *infile, char *outfile) { FILE *fp1 = NULL, *fp2 = NULL; if( NULL == (fp1 = fopen(infile, "r")) || NULL == (fp2 = fopen(outfile, "w")) ) return 0; doread(fp1, fp2, 1); fclose(fp1); fclose(fp2); return 1; } int main() { char infile[] = "file1.txt"; char outfile[] = "file2.txt"; run(infile, outfile); return 0; }
====================================================================================
方法二:利用链表(头插入法)
考虑到逆序的思想就是后进先出,这与栈的功能非常相似,于是产生了下面这种解法:
/* 功能:演示了将文件中的内容以行为单位,逆顺输出到另一文件 思路:考虑到后进先出,采用类似于栈的思想 */ #include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct _tagNode { char *line; struct _tagNode *next; }Node; Node* insert(Node *head, char *line) // 头插法建立链表 { Node *p = malloc(sizeof(Node)); p->line = malloc(strlen(line)+1); strcpy(p->line, line); p->next = head; head = p; return head; } void display(Node *head) { int i = 0; while(head) { printf("L%d: [%s]\n", ++i, head->line); head = head->next; } } // 将文件中的内容以行为单位逆顺输出到另一文件 void reverse(FILE *fp1, FILE *fp2) { int i = 0; char line[1024] = {0}; Node *head = NULL, *t = NULL; // 读文件,建立链表 while(fgets(line, 1024, fp1) != NULL) // fgets默认会将换行符读入到line中 { if(line[strlen(line)-1] == '\n') // 最后一个是换行符 line[strlen(line)-1] = 0; //printf("L%d: [%s]\n", ++i, line); head = insert(head, line); // 头插法建立链表 } // display(head); // 顺序读取链表,输出内容到文件,并释放结点 while(head) { fprintf(fp2, "%s\n", head->line); // 将内容写入输出文件 t = head; // t指向要删除的结点 head = head->next; // head后移 free(t->line); free(t); } } int main() { FILE *fp1, *fp2; char fin[] = "a.txt", fout[] = "a_out.txt"; fp1 = fopen(fin, "r"); fp2 = fopen(fout, "w"); if(fp1 == NULL || fp2 == NULL) { printf("Open file error\n"); return 1; } reverse(fp1, fp2); // 将文件中的内容以行为单位逆顺输出到另一文件 fclose(fp1); fclose(fp2); return 0; }
==================================================================================================
方法三:利用内存映射
/* 功能:利用内存映射将文件中的内容以行为单位,逆顺输出到另一文件 说明:如果最后一行无换行符,在输出文件中会被添加上去(否则会与第二行连在一起) */ #include <sys/mman.h> /* for mmap and munmap */ #include <sys/types.h> /* for open */ #include <sys/stat.h> /* for open */ #include <fcntl.h> /* for open */ #include <unistd.h> /* for lseek and write */ #include <stdio.h> // 以行为单位,将mapped_mem中的内容逆顺输出到文件fout void reverse(char *mapped_mem, int flen, int fout) { char *p, *t; t = p = mapped_mem + flen - 1; // p指向内容的最后一个字节 if(*p != '\n' && *p != '\0') // 最后一个字节不是换行符或0 t = p + 1; p--; while(p >= mapped_mem) // 从末尾向前扫描 { while(p >= mapped_mem && *p != '\n') p--; write(fout, p+1, t-p-1); // 将[p+1, t)的内容输出到文件fout write(fout, "\n", 1); // 输出换行符 t = p--; } if(t == mapped_mem) // 第一行是空行 { write(fout, "\n", 1); } } int main(int argc, char **argv) { int fd, fd_out; char *mapped_mem = NULL; int flength = 1024; void * start_addr = 0; if(argc < 3) { printf("Usage: %s <file_in> <file_out>\n", argv[0]); return 1; } fd = open(argv[1], O_RDONLY, S_IRUSR | S_IWUSR); fd_out = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if(fd == -1 || fd_out == -1) { perror("open"); return 1; } flength = lseek(fd, 0, SEEK_END); // 求得文件长度 mapped_mem = mmap(start_addr, flength, PROT_READ, //允许读 MAP_PRIVATE, //不允许其它进程访问此内存区域 fd, 0); if(mapped_mem == MAP_FAILED) { perror("mmap"); return 1; } reverse(mapped_mem, flength, fd_out); // 逆顺输出文件内容到fd_out close(fd); close(fd_out); munmap(mapped_mem, flength); return 0; }