2017-09-28 4 views
0

内の文字列を検索するにはどうすればなどfile_+0.txt, file_[]1.txt, file_~8.txt私が一定数まで行方不明files_*.txtを見つけたいPythonは - 大きなファイル

のような文字列を持つことができ、大きなファイルを持っています。私は、以下のファイルおよび数5を与えた場合、それが欠けているものが1 and 4

asdffile_[0.txtsadfe 
asqwffile_~2.txtsafwe 
awedffile_[]2.txtsdfwe 
qwefile_*0.txtsade 
zsffile_+3.txtsadwe 

であることを教えてください私は、ファイルのパスと番号を与えることができますしているPythonスクリプトを書いて、例えば

その番号まで見つからないすべてのファイル名を私に渡します。

私のプログラムは小さなファイルでも動作します。しかし、10000までファイル番号を持つことができる大きなファイル(12MB)を渡すと、ハングアップするだけです。ここで

が私の現在の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() 

である私は0から9999までのファイルを持つことができます12メガバイトのファイルを与えるときに出力がハング

$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] 
  1. どのように私はトンを作ることができます大きなファイルのための彼の仕事?
  2. Pythonスクリプトの代わりにこれらの結果を得るための良い方法はありますか?

ありがとうございます!

+0

大きな点では何ですか?検索するファイルの数、ファイル内のデータのサイズ、名前の長さ? – Mark

+0

12MBのファイルを入力し、検索可能なファイル数は10,000です – SyncMaster

+0

名前を取得するだけでファイルをメモリにマップする必要はありません。 – Mark

答えて

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に入れてもハングします。

+2

OPが複数の数字が1行で出現することが示唆される場合は、正規表現で '。*?'を使用する必要があります。 –

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() 

これはあなたのfilesPresentfilesMissingが容易に回収され、そこから生成される結果は次のとおり。

filenames.txt 
5 
[ True False True True False False] 
1

のは、あなたが実際にここで何をしているかを見てみましょう:

  1. メモリがファイルをマッピングします。
  2. 各数字について

    a。その番号の正規表現をコンパイルします。
    b。ファイル全体の正規表現を検索します。

これは、大量には非常に効率が悪いです。メモリマッピングでは文字列のようなインターフェイスがファイルに与えられますが、それは魔法ではありません。あなたはまだそれの中を移動するためにファイルの読み込みチャンクを持っています。同時に、正規表現ごとにファイル全体に潜在的にパスを渡しています。正規表現のマッチングも高価です。

ここでの解決策は、1行ずつファイルを1回通過させることです。検索する番号が大きい場合は、正規表現を数値ごとにコンパイルするのではなく、あらかじめコンパイルしておく必要があります。 1回のパスですべての数字を取得するには、「欠落」と呼ばれるすべての数字のを作成し、「見つかった」という空のsetを作成します。数字のある行に出会うたびに、「見つからない」から「見つかった」に番号を移動します。正規表現はfile_reluctant quantifier.*?を使用していることを

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 

注意:ここで

は、サンプルの実装です。これは、数字を探す前に可能な限り少数の文字と一致します。デフォルトの貪欲量限定子が .*の場合、1行の複数の数値は最後の唯一の数値と一致します。

関連する問題