免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 8039 | 回复: 12
打印 上一主题 下一主题

file的readlines问题请教 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-10 18:33 |只看该作者 |倒序浏览
用python写了一个web服务器日志分析程序类似如下


logfile = open('access.log', 'r')    # web服务器的日志文件,这个文件在不断增加新的行
logfile.seek(0, os.SEEK_END)      # 我们只关心新产生的日志信息
while True:
        lines = logfile.readlines()    # 读取新产生的日志
        for line in lines:
            item = logline2item(line) # 把当前这一行日志中我们关心的内容用正规分析出来,并存在item这个新的对象中
            if not item:
                continue
            dealitem(item)                # 对这个item对象进行处理
        time.sleep(1)                      # 等1秒钟,然后再去读取新产生的日志



logline2item()函数是用于把取得的一行日志信息用正规分析出来,并生成一个表示一行信息的对象
dealitem()函数是业务需要对日志中的信息进行分析,和我们现在的问题无关

这个程序在99%的情况下都工作得很好,但有时就会出问题。

问题主要出在readlines()这个函数上,因为web服务器的日志是被频繁写入的,
所以如果在调用readlines()时,正好web服务器也在向日志文件中写入一行日志信息, 而这一行信息还没写完,只写了一半,
那么readlines读取出来的最后一行日志是不完整的,从而造成正规匹配失败。
而且在接下来的第二次用readlines读取日志时,读取到的第一行日志也是不完整的。

如果不想丢失任何一行日志,请问有什么简便的方法能解决这个问题?


[ 本帖最后由 gnujava 于 2009-8-10 18:37 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-08-10 18:40 |只看该作者
把你全部的代码贴出来看看

论坛徽章:
0
3 [报告]
发表于 2009-08-10 18:44 |只看该作者
倒,这和其它部分有关吗?

论坛徽章:
0
4 [报告]
发表于 2009-08-10 18:46 |只看该作者
web 服务器生成的日志格式大家都知道,类似这样子
192.168.1.1 www.abc.com - [10/Aug/2009:06:42:28 +0800] "GET /index.html HTTP/1.1" 200 3362 "-" "Mozilla/4.0 (compatible"

论坛徽章:
0
5 [报告]
发表于 2009-08-10 20:02 |只看该作者
可否设置一个变量,当在写的时候设为1,写完为0。readlines()之前先查看变量

未验证 。。

论坛徽章:
0
6 [报告]
发表于 2009-08-10 20:06 |只看该作者
原帖由 chen24360 于 2009-8-10 20:02 发表
可否设置一个变量,当在写的时候设为1,写完为0。readlines()之前先查看变量

未验证 。。


我的程序只用于读取日志文件,写日志文件是Web服务器,是另一个程序。

论坛徽章:
0
7 [报告]
发表于 2009-08-10 20:32 |只看该作者
换个readLine吧.可能效率没readlines高

logfile = open('access.log', 'r')   
logfile.seek(0, os.SEEK_END)      
while True:   
    line = logfile.readline()
    while not re.search(r'\n$',line):
        line = line+logfile.readline()  
        time.sleep(1)      
    item = logline2item(line)
    if not item:
        continue
    dealitem(item)   


[ 本帖最后由 bohemia 于 2009-8-10 20:41 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2009-08-10 22:18 |只看该作者
原帖由 bohemia 于 2009-8-10 20:32 发表
换个readLine吧.可能效率没readlines高

logfile = open('access.log', 'r')   
logfile.seek(0, os.SEEK_END)      
while True:   
    line = logfile.readline()
    while not re.search(r'\n$',li ...



这个方法不行,line = logfile.readline()这一句有问题,
因为如果读取的是文件的最后一行,尽管最后一行不是以'\n'结尾,但readline()返回时会自动在返回值的最后加上'\n'

论坛徽章:
0
9 [报告]
发表于 2009-08-10 22:23 |只看该作者
应该不会吧?
readline() 默认不一定会带 \n 的.

见Python文档说明
"""
Read one entire line from the file. A trailing newline character is kept in the string (but may be absent when a file ends with an incomplete line).

The advantage of leaving the newline on is that returning an empty string is then an unambiguous EOF indication. It is also possible (in cases where it might matter, for example, if you want to make an exact copy of a file while scanning its lines) to tell whether the last line of a file ended in a newline or not (yes this happens!).
"""

论坛徽章:
0
10 [报告]
发表于 2009-08-10 23:09 |只看该作者
原帖由 bohemia 于 2009-8-10 22:23 发表
应该不会吧?
readline() 默认不一定会带 \n 的.

见Python文档说明
"""
Read one entire line from the file. A trailing newline character is kept in the string (but may be absent when a file ends ...



谢谢!确实没有\n,是我刚才测试程序的时候用的txt是用vi编译的,vi竟然自动加了一个\n

估计也能用readfiles,同时考虑效率,如下:

    logfile = open('access.log', 'r')           # web服务器的日志文件,这个文件在不断增加新的行
    logfile.seek(0, os.SEEK_END)                # 我们只关心新产生的日志信息
    while True:
        lines = logfile.readlines()             # 读取新产生的日志
        while len(lines) > 0 and lines[-1][-1] != '\n': #  如果读到了日志,并且日志的最后一行的最后一个字符不是换行,说明日志文件的最后一行没有完,要特别处理,这个地方不用正则效率要高一点
            time.sleep(1)                       
            newlines = logfile.readlines()
            if len(newlines) == 1:                 # 如果读取到了一行日志,这行日志一定是上次读的时候没有读完的,这里要注意这一次读也不一定把这一行读取完了,所以要循环处理
                lines[-1] += newlines[0]        # 所以把这一行和上次读的最后一行连接在一起
            elif len(newlines) > 1:                # 如果读取到的内容超过一行,和上面一样这一次读也不一定把最后一行读取完了,所以要循环处理
                lines[-1] += newlines[0]        # 那第一行一定是上一次没有读取完的后半部分,直接加在一起就行了
                lines.extend(newlines[1:])      # 把新读取到的其它行加入到前面已经读取了的列表中,这个地方用extend效率要高于用+号连接,不过后面的切片的效率可能不好,不知道有更好的办法没有
        for line in lines:
           item = logline2item(line)            # 把当前这一行日志中我们关心的内容用正规分析出来,并存在item这个新的对象中
           if not item:
               continue
           dealitem(item)                       # 对这个item对象进行处理
        time.sleep(1)                           # 等1秒钟,然后再去读取新产生的日志


程序这么写不知道有什么问题没有?而且即使这样能解决,也不知道有更好的方法没有。

[ 本帖最后由 gnujava 于 2009-8-10 23:28 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP