linux中txt转xml,记一次800多万XML文本文件预处理经历

一.背景

由于某些需求,现需对系统在最近几个月生成的xml文件进行预处理,提取标签内的数据进行分析。这些需要预处理的数据大概有280GB左右880多万,存放在gysl目录下,gysl的下一层按天命名,分为若干个目录,接下来一层目录下又有多个目录,我们所需的xml目录就在这一层。我们现在需要将此目录下面的xml文件使用Python脚本进行处理,并将处理结果按天(与源文件一致)保存到~/temp目录下。

二.操作过程

2.1 Python脚本准备。

#!/usr/bin/python3

# -*- coding:utf-8 -*-

import glob,os,sys, re

from concurrent.futures import ProcessPoolExecutor

import argparse

import random

def find_xs(str, list):

i = 0

for i in range(0,len(str)):

if str[i] in list:

return i

return -1

def segement_aux(para, OUT, sep_list, max_length, merge_prob):

pos = 0

res_sentence = ""

sentence_size = 0

while True:

#segment one line.

pos = find_xs(para,sep_list)

if pos == -1:

break

cur_sentence = para[:pos+1].strip()

cur_sentence_filtering = cur_sentence

res_sentence = res_sentence + cur_sentence_filtering

sentence_size = sentence_size + 1

if sentence_size == 2:

OUT.write(res_sentence + '\n')

else:

rand = random.random()

if rand > merge_prob:

OUT.write(res_sentence + '\n')

res_sentence = ""

sentence_size = 0

else:

sentence_size = sentence_size + 1

para = para[pos+1:]

def loadXMLfile(inputfile):

sep_list= ['。', '?', '!']

targetfolder = "Target"

max_length = 100000

merge_prob = 0.6

basefilename =os.path.basename(inputfile)

outputfile = targetfolder + '/'+ os.path.splitext(basefilename)[0] + ".tsv"

textSessionPattern = re.compile(r'(.*?)\s*', re.I|re.MULTILINE)

OUT = open(outputfile, 'w',encoding="utf8")

for line in open(inputfile,encoding="utf8"):

line = line.strip().rstrip("\r\n")

alltextsessions = re.findall(textSessionPattern, line)

for textsession in alltextsessions:

textsession = re.sub(r'\t', r' ', textsession)

textsession = re.sub(r'\]+\>', r'', textsession)

textsession = re.sub(r'\{[^\}|\{]+\}', r'', textsession)

textsession = re.sub(r'\s+',r'',textsession)

OUT.write(textsession+'\n')

OUT.close()

return outputfile

def processXMLfilesWithThreads(input):

with ProcessPoolExecutor() as executor:

xmlfiles = glob.glob(input + "/*.xml")

for xmlfile, outputfile in zip( xmlfiles, executor.map( loadXMLfile, xmlfiles) ):

print("Processed" + outputfile)

if __name__ == '__main__':

ap = argparse.ArgumentParser()

ap.add_argument("-i", "--input", required=True, help="the directory of input files")

args = ap.parse_args()

processXMLfilesWithThreads(input = args.input)

2.2 Shell脚本准备。

for folder in `find /home/ivandu/gysl -path "*/xml" -print`;do mkdir Target;python3 XMLPreProcess.py --input $folder;mv Target ~/temp/$(echo $folder|awk -F "/" '{print $5}');done

看着有点费劲,改一下:

#!/bin/bash

for folder in `find /home/ivandu/gysl -path "*/xml" -print`;

do

mkdir Target;

python3 XMLPreProcess.py --input $folder;

mv Target ~/temp/$(echo $folder|awk -F "/" '{print $5}');

done

2.3 执行脚本。

此步骤就不展示了,涉及到某些商业机密。在Python脚本所在的目录下,执行Shell脚本就行。

三.遇到问题

3.1 “Argument list too long”。

在执行某目录下的文件移动、复制、删除操作时,发现提示“Argument list too long”,命令执行不成功。这个目录下的文件数量超过30万,操作命令如下:

cp * ~/gysl_test

提示:

-sh: /bin/cp: Argument list too long

解决方案:

for file in `ls`;do cp $file ~/gysl_test/;done

rm,mv也类似,太忙了也就没继续探讨其他解决方案。

3.2 双for循环执行效率太低。

for folder in `find /home/ivandu/gysl/ -mindepth 2 -maxdepth 2 -print|grep "xml"`;do cd $folder;for file in $(ls);do cp $file ~/gysl_test/;done;done

如果使用这命令来拷贝这些文件的话,那么这一天可能就过去了!这个肯定不妥,必须改进。find也用得不够简洁,后来都进行优化了。

3.3 Python单线程执行效率太低。

Python脚本使用了多线程来进行处理。不过多解释,大家见谅\^_^

四.总结

4.1 总体来说今天处理这些数据还是挺给力的,差不多5000秒就完成了。我写了一条命令动态观察了一下。

4.2 正则表达式随时都能用上,要不是处理一下特殊任务和Python多线程,直接一个grep命令写到shell命令或许早就完事了。

4.3 多线程。bash shell中的多线程还不会使用,以后还得加强学习一下。

4.4 就写这么多了,不足之处还望诸位不吝赐教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值