方法一:利用递归
/*功能:文件以行为单位,逆顺输出到新文件示例:file1.txt为:123456要求逆顺后输出到文件file2.txt,结果为:563412*/#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') // 最后一个字节不是换行符或0t = p + 1;p--;while(p >= mapped_mem) // 从末尾向前扫描{while(p >= mapped_mem && *p != '\n')p--;write(fout, p+1, t-p-1); // 将[p+1, t)的内容输出到文件foutwrite(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_outclose(fd);close(fd_out);munmap(mapped_mem, flength);return 0;
}