我有一个大文件,可以包含file_+0.txt, file_[]1.txt, file_~8.txt
等字符串。
我希望找到丢失的files_*.txt
,直到某个数字。
例如,如果我给出下面的文件和数字5,它应该告诉缺少的文件是1 and 4
asdffile_[0.txtsadfe
asqwffile_~2.txtsafwe
awedffile_[]2.txtsdfwe
qwefile_*0.txtsade
zsffile_+3.txtsadwe
我编写了一个Python脚本,我可以给它提供文件路径和一个数字,它将为我提供在该数字之前缺少的所有文件名。
我的程序适用于小文件。但是,当我提供一个大文件(12MB),文件编号可以达到10000时,它就会挂起。
这是我目前的Python代码
#! /usr/bin/env/python
import mmap
import re
def main():
filePath = input("Enter file path: ")
endFileNum = input("Enter end file number: ")
print(filePath)
print(endFileNum)
filesMissing = []
filesPresent = []
f = open(filePath, 'rb', 0)
s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
for x in range(int(endFileNum)):
myRegex = r'(.*)file(.*)' + re.escape(str(x)) + r'\.txt'
myRegex = bytes(myRegex, 'utf-8')
if re.search(myRegex, s):
filesPresent.append(x)
else:
filesMissing.append(x)
#print(filesPresent)
print(filesMissing)
if __name__ == "__main__":
main()
当我提供一个12MB的文件时,输出会挂起,该文件可以包含0到9999的文件
$python findFileNumbers.py
Enter file path: abc.log
Enter end file number: 10000
小文件的输出(与上例相同)
$python findFileNumbers.py
Enter file path: sample.log
Enter end file number: 5
[0, 2, 3]
[1, 4]
提前致谢!
答案 0 :(得分:2)
首先收集一组中现有的,然后寻找遗漏的那些。
my_regex = re.compile('.*file.*(\d+)\.txt.*')
present_ones = set()
for line in open(filepath):
match = my_regex.match(line)
if match:
present_ones.add(int(match.group(1)))
for num in range(...):
if num not in present_ones:
print("Missing" + num)
你的原因因为你要浏览每个号码的整个文件而挂起。即12MB * 10000 = 120GB脚本将通过120GB,因此即使你在mmap中使用它也会挂起。
答案 1 :(得分:1)
我建议您只需逐行读取输入文件并解析每行的文件编号。然后使用该文件号作为布尔数组的索引,最初设置为False。
您不需要执行任何需要将文件存入内存的处理。这种方法适用于非常大的文件。
#~ import mmap
import re
import numpy as np
def main():
#~ filePath = input("Enter file path: ")
filePath = 'filenames.txt'
#~ endFileNum = input("Enter end file number: ")
endFileNum = 5
print(filePath)
print(endFileNum)
found = np.zeros(1+endFileNum, dtype=bool)
patt = re.compile(r'[^\d]+(\d+)')
with open(filePath) as f:
for line in f.readlines():
r = patt.search(line).groups(0)[0]
if r:
found[int(r)]=True
print (found)
#~ filesMissing = []
#~ filesPresent = []
#~ files = np.zeros[endFileNum, dtype=bool]
#~ f = open(filePath, 'rb', 0)
#~ s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
#~ for x in range(int(endFileNum)):
#~ myRegex = r'(.*)file(.*)' + re.escape(str(x)) + r'\.txt'
#~ myRegex = bytes(myRegex, 'utf-8')
#~ if re.search(myRegex, s):
#~ filesPresent.append(x)
#~ else:
#~ filesMissing.append(x)
#print(filesPresent)
#~ print(filesMissing)
if __name__ == "__main__":
main()
这会产生以下结果:filesPresent
和filesMissing
可以轻松恢复。
filenames.txt
5
[ True False True True False False]
答案 2 :(得分:1)
让我们来看看你在这里做了什么:
每个号码
一个。编译该数字的正则表达式 湾在整个文件中搜索正则表达式。
对于大数字来说这是非常低效的。虽然内存映射为文件提供了类似字符串的接口,但它并不神奇。您仍然有文件的加载块在其中移动。同时,您正在为每个正则表达式传递一个可能在整个文件中的传递。正则表达式匹配也很昂贵。
这里的解决方案是逐行遍历文件。如果要搜索的数字很大,则应预编译正则表达式,而不是每个数字编译一次。要一次性获取所有数字,您可以将set
所有数字设置为所需数字,称为“缺失”,并将空set
称为“找到”。每当遇到带数字的行时,您都会将数字从“缺失”移动到“找到”。
以下是一个示例实现:
filePath = input("Enter file path: ")
endFileNum = int(input("Enter end file number: "))
missing = set(range(endFileNum))
found = set()
regex = re.compile(r'file_.*?(\d+)\.txt')
with open(filePath) as file:
for line in file:
for match in regex.finditer(line)
num = int(match.groups(1))
if num < endFileNum:
found.add(num)
missing -= found
请注意,正则表达式在.*?
之后使用reluctant quantifier file_
。在查找数字之前,这将匹配尽可能少的字符。如果您有默认的贪心量词.*
,则一行中的多个数字只会匹配最后一个。