繁体   English   中英

有没有更快的方法来解析这个文本文件?

[英]Is there a faster way to parse this text file?

我正在从一些类似于此的文本文件中解析日期/时间/测量信息:

[Sun Jul 15 09:05:56.724 2018] *000129.32347
[Sun Jul 15 09:05:57.722 2018] *000129.32352
[Sun Jul 15 09:05:58.721 2018] *000129.32342
[Sun Jul 15 09:05:59.719 2018] *000129.32338
[Sun Jul 15 09:06:00.733 2018] *000129.32338
[Sun Jul 15 09:06:01.732 2018] *000129.32352

结果进入这样的输出文件:

07-15-2018 09:05:56.724, 29.32347
07-15-2018 09:05:57.722, 29.32352
07-15-2018 09:05:58.721, 29.32342
07-15-2018 09:05:59.719, 29.32338
07-15-2018 09:06:00.733, 29.32338
07-15-2018 09:06:01.732, 29.32352

我正在使用的代码如下所示:

import os
import datetime

with open('dq_barorun_20180715_calibtest.log', 'r') as fh, open('output.txt' , 'w') as fh2:
    for line in fh:
        line = line.split()
        monthalpha = line[1]
        month = datetime.datetime.strptime(monthalpha, '%b').strftime('%m')
        day = line[2]
        time = line[3]
        yearbracket = line[4]
        year = yearbracket[0:4]
        pressfull = line[5]
        press = pressfull[5:13]
        timestamp = month+"-"+day+"-"+year+" "+time
        fh2.write(timestamp + ", " + press + "\n")

这段代码运行良好并完成了我的需要,但我正在尝试学习更有效的 Python 文件解析方法。 处理一个 100MB 的文件大约需要 30 秒,我有几个大小为 1-2GB 的文件。 有没有更快的方法解析这个文件?

您可以声明months dict 不使用datetime模块,这应该会快一点。

months = {"Jan": "01", "Feb": "02", "Mar": "03", "Apr": "04", "May": "05", "Jun": "06",
          "Jul": "07", "Aug": "08", "Sep": "09", "Oct": "10", "Nov": "11", "Dec": "12"}

您也可以使用解包使您的代码更简单:

for line in fh:
    _, month, day, time, year, last = line.split()
    res = months[month] + "-" + day + "-" + year[:4] + " " + time + ", " + last[5:]
    fh2.write(res)

PS timeit显示它大约快 10 倍

您应该使用 Pandas DataFrames 来快速加载和操作大数据:

import pandas as pd, datetime

df = pd.read_csv('dq_barorun_20180715_calibtest.log',header=None,sep=' ')
df[0] = df.apply(lambda x: x[0][1:],axis=1)
df[1] = df.apply(lambda x: datetime.datetime.strptime(x[1], '%b').strftime('%m'), axis=1)
df[4] = df.apply(lambda x: x[4][:-1],axis=1)
df[5] = df.apply(lambda x: ' ' + x[5][5:],axis=1)
df['timestamp'] = df.apply(lambda x: x[1]+"-"+str(x[2])+"-"+x[4]+" "+x[3], axis = 1)
df.to_csv('output.txt',columns=['timestamp',5],header=False, index=False)

由于您有固定的职位和从月份名称到数字的简单转换,这应该有效

#! /usr/bin/env python3

m = {'Jan':'01', 'Feb':'02', 'Mar':'03', 'Apr':'04', 'May':'05', 'Jun':'06', 'Jul':'07', 'Aug':'08', 'Sep':'09', 'Oct':'10', 'Nov':'11', 'Dec':'12'}
with open('dq_barorun_20180715_calibtest.log', 'r') as fh, open('output.txt' , 'w') as fh2:
    for line in fh:
        day = line[9:11]
        month = m[line[5:8]]
        year = line[25:29]
        time = line[12:24]
        val = line[36:44]
        print('{}-{}-{} {}, {}'.format(month, day, year, time, val), file=fh2)

这是使用 Pandas read_csv 的另一种方法,如果你有很多大文件,你可以使用dask它也支持这个。

import pandas as pd
import datetime

df = pd.read_csv('D:\\test.txt',sep='\*0001')

df.columns = ['dates','val']
df.dates = pd.to_datetime(df.dates.str[1:-2])
df.to_csv("output.csv",header=None,index=None)

然后,您可以使用不同的方法将日期转换为您想要的格式。

我可能有一个完全不同的想法,但它并没有加快解析速度。
如果这不是您想要的,因为您要求更快的解析,请发表评论,我将删除此答案。

您应该将大型输入文件拆分为较小的段。 例如,您可以尝试获取行数并将其除以合适的数字。 假设有 40,000 行,那么您可以将其分成 4 段,每段接近 10,000 行。 记下起始索引以及要处理的行数。 请注意,最后一个偏移量可能小于 10,000。

然后将输入文件传递给多个线程,这些线程只读取从start-index到输入文件offset的给定部分并解析这部分。 各个线程将解析的部分写入共享文件夹中,但使用索引文件名。 每个线程完成后,您可以将共享文件夹中的所有文件合并为一个output.txt


以下是一些有关如何实现其中一些目标的链接资源:

为避免打开文件过大,导致内存占用过多,本代码使用Python yield技术,使用常规内容。 具体的实际性能,可以和自己写的代码进行性能对比。

以下代码已在本地运行!

import datetime
import re

# File path to be cleaned
CONTENT_PATH = './test03.txt'
# File path of cleaning results
RESULT_PATH = './test03.log'


def read(file):
    with open(file) as obj:
        while True:
            line = obj.readline()
            if line:
                yield line
            else:
                return


def tsplit(line):
    _m, _d, _y = line[5:8], line[9:11], line[25:29]
    _m = datetime.datetime.strptime(_m, '%b').strftime('%m')
    rt = "%s-%s-%s" % (_m, _d, _y)
    return rt


hour_min_sen = re.compile(r'(\d{2}:\d{2}:\d{2}.\d{2})')
end = re.compile(r'(\d{2}\.\d{5})')


with open(RESULT_PATH, 'a+') as obj:
    for line in read(CONTENT_PATH):
        line = line.strip()
        """
        [Sun Jul 15 09:06:01.732 2018] *000129.32352
        """
        group = hour_min_sen.findall(line)
        end_group = end.findall(line)
        """
        07-15-2018 09:05:56.724, 29.32347
        """
        obj.write("%s %s, %s\n" % (tsplit(line), group[0], end_group[0]))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM