linux下使用c语言模拟tail [-n] 命令
为了加深一下对linux下常规命令的理解顺带写作业,就用c语言模拟了一下tail命令。
首先简单介绍一下tali命令的用法。
tail test.txt
:显示test.txt文件的最后十行
tail -n 5 test.txt
:显示test.txt文件最后五行
当然tail命令还有tail -f
这个用法,用于实时更新文件的最后十行,不过为了偷懒就没写了,思路差不多,只是需要隔一段时间重新刷新一下。
同时,如果后面给的文件路径或者文件名等写错了,或者写的参数不正确,导致参数错误或文件找不到的话,也会有提示信息。
作为小白,下面写的内容只要会c语言基本语法就能看懂,不会的地方我均写了解释或者放上了参考文档。
废话不多说,开始讲解思路:
1、初始化默认读取长度line=10,如果使用了-n参数设置了长度为x,那么就让line=x
2、一行一行读取文件并保存在数组。但是我是模拟了一下循环数组,即当数组长度达到line了就将数组下一次写入的位置下标设置为0,这样在一定程度上保证了不会因为文件太大而溢出。
举个例子:假如文件一共15行,保存文件每一行数据的数组为char buffer[][]
,第0-9行存放在buffer[0][] - buffer[9][] 之中,但是第10行数据又会被保存到buffer[0][]中,因为最后只需要输出10行即可,所以只需要保存距离当前位置的最后十行。不过为了输出时候保证位置正确,肯定是要记录数组下标的。
3、开始输出了,输出是对buffer数组进行循环遍历,循环的次数等于min(line,文章行数)。
然后从前面保存的下标开始输出即可。
思路清晰了,就到了具体实现中存在的问题了。
首先,main函数的参数是什么意思?
请参考:http://blog.csdn.net/yhawaii/article/details/7361302
然后,既然需要读取-n 5 文件路径
这些信息,而且并不知道-n 5
这样的参数是否会存在,如何解决?
请参考:https://www.cnblogs.com/qingergege/p/5914218.html
再之后,如何一行一行读取文件?
有两个思路,使用read,或者是用fgets。我们要求是使用read的,但是太麻烦了,我偷懒就还是使用fgets了。下面先简要介绍一下用read实现的思路:
想了解一下read的童鞋请参考:
read的配套用法——open详解
read的用法详解
1) 定义一个缓冲区,用read将文件全部存入缓冲区再通过\n来识别换行。明显的一个缺陷就是当文件太大的时候缓冲区会存不下,浪费了存储空间。
2) 每次读一个字符,然后保存到一个临时缓冲队列里,读取到第一个\n后将缓冲队列里的数据当成一行存储。缺点在于效率低下。
这两种思路是在一个论坛里总结出来的,论坛链接
总之使用read是很麻烦的一件事
,所以接下来还是老实使用fgets吧。这个就很简单啦,参考:fgets读取文件
可运行源代码
最后就是我的源码咯,头文件可能多了点,因为原来使用read加上去的,但是嫌read太麻烦还是改成fgets了。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#define BUFFSIZE 512
int main(int argc,char **argv)
{
char c;
int line = 10;
int count = 0;
char buffer[BUFFSIZE][BUFFSIZE];
//如果有-n,就将line的默认值改了。这里有错误默认是会自动提示的。
while((c=getopt(argc,argv,"n:"))!=-1)
{
int x = atoi(optarg);
line = x;
}
//获取文件路径,optind是某个头文件里的东西,不是我定义的,指示的是argv中下一个要读取的数据的下标
char *path = argv[optind];
FILE *fp;
int index = 0;
//如果文件打开不成功,肯定是文件没找到,就报错
if((fp = fopen(path,"r")) == NULL)
{
printf("File dosen't exit!");
return -1;
}
//下面就是前面讲的思路了,读取文件保存到数组
while(!feof(fp))
{
count++;
fgets(buffer[index],BUFFSIZE,fp);
if(index+1 >= line)
{
index = 0;
}
else{
index++;
}
}
//记得关闭fp
fclose(fp);
int i;
if(count < line)
{
line = count;
}
//因为前面是用的++,多加了1
if(index != 0)
{
index--;
}
for(i = 0;i<line;i++)
{
printf("%s",buffer[index++]);
if(index >= line)
{
index = 0;
}
}
}
运行如图: