Python - 如何在大文件中搜索字符串
Python - How to search a string in a large file
我有一个大文件,其中可以包含 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]
- 我怎样才能使它适用于大文件?
- 有没有比 Python 脚本更好的方法来获得这些结果?
提前致谢!
先把现有的收集起来,然后寻找缺失的。
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 中它也会挂起。
我建议您只需逐行阅读输入文件并解析每一行的文件编号。然后将该文件号用作最初设置为 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]
让我们看看你在这里实际做了什么:
内存映射文件。
每个数字
一个。编译该数字的正则表达式。
b.在整个文件中搜索正则表达式。
这对于大数来说效率很低。虽然内存映射为文件提供了一个类似字符串的 接口 ,但这并不神奇。您仍然可以加载文件块以在其中移动。同时,您正在为每个正则表达式进行传递,可能遍及整个文件。正则表达式匹配也很昂贵。
此处的解决方案是逐行通过文件一次。如果要搜索大量数字,则应预编译正则表达式而不是每个数字编译一次。要一次获得所有数字,您可以对所有数字进行 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
注意正则表达式在file_
之后使用了reluctant quantifier.*?
。这将在查找数字之前匹配尽可能少的字符。如果您有 .*
的默认贪婪量词,一行中的多个数字将只匹配最后一个。
我有一个大文件,其中可以包含 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]
- 我怎样才能使它适用于大文件?
- 有没有比 Python 脚本更好的方法来获得这些结果?
提前致谢!
先把现有的收集起来,然后寻找缺失的。
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 中它也会挂起。
我建议您只需逐行阅读输入文件并解析每一行的文件编号。然后将该文件号用作最初设置为 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]
让我们看看你在这里实际做了什么:
内存映射文件。
每个数字
一个。编译该数字的正则表达式。
b.在整个文件中搜索正则表达式。
这对于大数来说效率很低。虽然内存映射为文件提供了一个类似字符串的 接口 ,但这并不神奇。您仍然可以加载文件块以在其中移动。同时,您正在为每个正则表达式进行传递,可能遍及整个文件。正则表达式匹配也很昂贵。
此处的解决方案是逐行通过文件一次。如果要搜索大量数字,则应预编译正则表达式而不是每个数字编译一次。要一次获得所有数字,您可以对所有数字进行 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
注意正则表达式在file_
之后使用了reluctant quantifier.*?
。这将在查找数字之前匹配尽可能少的字符。如果您有 .*
的默认贪婪量词,一行中的多个数字将只匹配最后一个。