Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3031754
  • 博文数量: 272
  • 博客积分: 5544
  • 博客等级: 大校
  • 技术积分: 5496
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-08 00:48
个人简介

  每个人都要有一个骨灰级的爱好,不为金钱,而纯粹是为了在这个领域享受追寻真理的快乐。

文章分类

全部博文(272)

文章存档

2015年(2)

2014年(5)

2013年(25)

2012年(58)

2011年(182)

分类: 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;
}

阅读(2812) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

joepayne2013-05-09 15:38:55

分析得很到位!我还是习惯用映射,只是平时没有注意到文件的大小,可能文件大小没有超过8M吧?^_^