现在的位置: 首页 > 综合 > 正文

文件逆顺输出到新文件(三种方案)

2019年08月10日 ⁄ 综合 ⁄ 共 3127字 ⁄ 字号 评论关闭

方法一:利用递归

/*
	功能:文件以行为单位,逆顺输出到新文件
	示例: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;
}

抱歉!评论已关闭.