免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: lyl2002

[C] 求日志文件最后的行输出 [复制链接]

论坛徽章:
0
发表于 2013-05-04 11:25 |显示全部楼层
本帖最后由 hbmhalley 于 2013-05-04 11:26 编辑

回复 11# lyl2002
  1. #include <assert.h>
  2. #include <stdio.h>

  3. int main (int argc , char *argv[]) {
  4.         FILE *fp ;
  5.         int m ;

  6.         if (argc != 3
  7.                         || (fp = fopen (argv[1] , "r")) == NULL
  8.                         || sscanf (argv[2] , "%d" , &m) != 1
  9.                         || m <= 0) {
  10.                 fputs ("arg error\n" , stderr) ;
  11.                 return 1 ;
  12.         }

  13.         long st ;
  14.         int cnt = m ;
  15.         fseek (fp , 0 , SEEK_END) ;
  16.         for (st = 1 ; ftell (fp) != 0 ; st <<= 1) {
  17.                 if (fseek (fp , -st , SEEK_CUR) != 0) {
  18.                         st = ftell (fp) ;
  19.                         fseek (fp , 0 , SEEK_SET) ;
  20.                 }

  21.                 long i ;
  22.                 for (i = 0 ; i < st ; ++i)
  23.                         cnt -= fgetc (fp) == '\n' ;

  24.                 fseek (fp , -st , SEEK_CUR) ;
  25.                 if (cnt < 0)
  26.                         break ;
  27.         }

  28.         while (cnt < 0)
  29.                 cnt += fgetc (fp) == '\n' ;

  30. #define MAX_M 10
  31.         static char caBuf[MAX_M][1024] ;
  32.         int i = 0 ;
  33.         while (fgets (caBuf[i] , sizeof(caBuf[i]) , fp) != NULL) // 末尾有'\n'
  34.                 ++i , assert (i < MAX_M) ;

  35.         return 0 ;
  36. }
复制代码

论坛徽章:
0
发表于 2013-05-04 12:32 |显示全部楼层
本帖最后由 Frahm 于 2013-05-04 12:56 编辑

为什么我这个不行,貌似ftell得到的不是字节数,像是文件的大小。用binary模式读取,就可以跳过\r\n之类的

  1. #define LINELEN 23
  2. int main() {

  3.     FILE *file = fopen( "aaa.txt", "rb" ); //哦,我知道了,这里rb
  4.     if( !file )
  5.       return 1;
  6.     const size_t m = 3;
  7.     char buf[m * LINELEN+1];
  8.     fseek(file, 0, FILE_END);
  9.     long total_bytes = ftell(file);

  10.     size_t last_bytes = total_bytes - total_bytes / LINELEN * LINELEN;//number of bytes of the last line
  11.     size_t num_line = (total_bytes - last_bytes)/  LINELEN + 1;
  12.     size_t n = m < num_line ? m : num_line; //trim

  13.     long to_read = LINELEN * (n-1) + last_bytes;
  14.     fseek(file, -to_read, FILE_END);
  15.     fread(buf, sizeof(char), to_read, file);
  16.     buf[to_read] = '\0';
  17.     fclose(file);
  18.     printf("%s", buf);
复制代码
}

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2013-05-04 12:36 |显示全部楼层
本帖最后由 linux_c_py_php 于 2013-05-04 12:48 编辑

写了一个优化的, 性能比hbmhalley的好一点, 思路都一样, 主要是减少了fgetc调用, 使用4KB一读优化磁盘读效率, 另外查找使用向前查找可以避免最后的回滚逻辑, 代码丑莫见怪:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>

  5. /* linux only */
  6. int tail_lines(const char *file, int nline)
  7. {
  8.     if (!nline)
  9.         return 0;

  10.     int fd = open(file, O_RDONLY);
  11.     if (fd == -1)
  12.         return -1;

  13.     off_t size = lseek(fd, 0, SEEK_END);
  14.    
  15.     int cnt = 0;
  16.     char buf[4096]; /*faster with 4kb per read*/
  17.     off_t last = size;
  18.     off_t respos = 0;
  19.     while (last) {
  20.         off_t cur = lseek(fd, last - sizeof(buf), SEEK_SET);
  21.         off_t toread;
  22.         if (cur == (off_t)-1) {
  23.             cur = lseek(fd, 0, SEEK_SET);
  24.             toread = last;
  25.         } else
  26.             toread = sizeof(buf);

  27.         int nread = read(fd, buf, toread);
  28.         if (nread != toread)
  29.             return -1; /*never happen*/
  30.         
  31.         int i;
  32.         for (i = nread - 1; i >=0; --i) {
  33.             if (buf[i] == '\n') {
  34.                 cnt++;
  35.                 if (cnt == nline + 1) {
  36.                     respos = cur + i + 1;
  37.                     cnt--;
  38.                     goto end;
  39.                 }
  40.             }
  41.         }
  42.         if (!cur) {
  43.             cnt++;
  44.             break;
  45.         }
  46.         last = cur;
  47.     }

  48. end:
  49.     lseek(fd, respos, SEEK_SET);
  50.     while (1) {
  51.         int n = read(fd, buf, sizeof(buf));
  52.         if (n > 0)
  53.             write(1, buf, n);
  54.         else
  55.             break;
  56.     }
  57.     close(fd);
  58.     return --cnt;
  59. }

  60. int main(int argc, char *const argv[])
  61. {
  62.     if (argc < 3)
  63.         return -1;
  64.     int cnt = tail_lines(argv[1], atoi(argv[2]));
  65.     printf("line_count=%d\n", cnt);
  66.     return 0;
  67. }
复制代码

论坛徽章:
0
发表于 2013-05-04 12:53 |显示全部楼层
回复 14# linux_c_py_php


    你看我那个思路对不对?

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2013-05-04 12:58 |显示全部楼层
啊, 你怎么知道每一行多长的。。

论坛徽章:
0
发表于 2013-05-04 13:02 |显示全部楼层
本帖最后由 Frahm 于 2013-05-04 13:06 编辑

回复 16# linux_c_py_php


    看他的日志文件内容。
哦,我错了,n位数不同,要是都补0就好了。我那贴作废。

论坛徽章:
0
发表于 2013-05-04 13:09 |显示全部楼层
回复 14# linux_c_py_php


    10倍 ......
    差在哪啊 .. buffer? 默认的buffer size应该比较合适吧 ..
    那把 fgetc 改成 getc 会好点吗?

论坛徽章:
0
发表于 2013-05-04 13:13 |显示全部楼层
我感觉可以按最大长度(3*MAX_LINE_LEN)一次把文件内容读取到一个buffer里,再对字符串处理比较好。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
发表于 2013-05-04 14:07 |显示全部楼层
本帖最后由 linux_c_py_php 于 2013-05-04 14:16 编辑
hbmhalley 发表于 2013-05-04 13:09
回复 14# linux_c_py_php


目测就差在fgetc上, 调用太多了, 我之前用c-fcgi的时候发现那框架也是类似这种逐字节调用, 虽然FILE有缓冲, 但调用多了也要命啊.

文件有4KB, 我只调一次函数, 你要调用4KB次, 肯定就差开了, 应该是这个原因.

论坛徽章:
9
CU大牛徽章
日期:2013-04-17 11:06:23CU大牛徽章
日期:2013-04-17 11:08:52CU大牛徽章
日期:2013-04-17 11:09:10CU大牛徽章
日期:2013-04-17 11:09:40CU大牛徽章
日期:2013-04-17 11:09:57CU大牛徽章
日期:2013-04-17 11:10:17CU大牛徽章
日期:2013-05-20 10:43:41CU大牛徽章
日期:2013-05-20 10:44:06CU大牛徽章
日期:2013-05-20 10:44:16
发表于 2013-05-06 10:06 |显示全部楼层
:wink:
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP