输出文本文件倒数n行数据

面试时曾2次被问到如何实现输出文本文件(可能非常非常大)后n行数据的问题,这个功能基本是Linux下tail命令的简化版,随意写了下。

因为涉及到不同系统及编码下回车换行的问题,情境比较复杂,在这里暂时未处理,但是基本处理思想是一样的。

代码目前在linux下运行正确,在windows下输出异常,就是因为字符编码(主要是回车换行)问题 >_> 仅供参考。

#include 

#include 

#include 

#include 



//#define DEBUG



#define MAX_BUF_SIZE 4096



#define MIN(a, b) ((a) < (b) ? (a) : (b))



int main(int argc, char *argv[]) 

{

#ifndef DEBUG

	if (argc != 3)

	{

		printf("usage: %s number_of_line(s) file\n", argv[0]);

		exit(1);

	}



	int nline = atoi(argv[1]);

	const char *filename = argv[2];

#else

	int nline = 4;

	const char *filename = "test.txt";

#endif



	int nl = 0;

	FILE *fp;

	int buflen;

	char buf[MAX_BUF_SIZE];

	int fsz = 0, pos = 0;

	int nblock = 0;

	bool tobreak = false;



	if ((fp = fopen(filename, "r")) == NULL)

	{

		printf("open file \"%s\" error\n", filename);

		exit(2);

	}



	fseek(fp, 0, SEEK_END);

	fsz = ftell(fp);



	nblock = ceil(fsz / (float)MAX_BUF_SIZE);

	for (int k = 0; k < nblock; k++)

	{

		int blocksz = MIN(fsz - k * MAX_BUF_SIZE, MAX_BUF_SIZE);

		int offset = -MIN(fsz, (k + 1) * MAX_BUF_SIZE);



		fseek(fp, offset, SEEK_END);

		buflen = fread(buf, 1, blocksz, fp);

		for (int i = buflen - 1; i >= 0; i--)

		{

			if (buf[i] == '\n')

			{

				nl++;

				//if (nl == nline)

				if (nl > nline)

				{

					pos += buflen - i - 1;

					tobreak = true;

					break;

				}

			}

		}

		if (tobreak) break;

		pos += blocksz;

	}



	if (tobreak)

		fseek(fp, -pos, SEEK_END);

	else

		fseek(fp, 0, SEEK_SET);



	while ((buflen = fread(buf, 1, MAX_BUF_SIZE - 1, fp)) > 0)

	{

		buf[buflen] = '\0';

		printf("%s", buf);

	}

	//printf("\n");



	fclose(fp);



	return 0;

}


你可能感兴趣的:(输出文本文件倒数n行数据)