2016-02-17 3 views
8

X12 EDIファイルを処理するためのスクリプトを作成していますが、これは行単位で繰り返したいものです。ファイルは一連の個別のレコードで構成され、それぞれ特殊文字で終了します(例:~、以下を参照)。ファイルは大きくて(> 100 MB)、全体を読み込んで分割したくない場合があります。レコードは改行で区切られていません。最初の行を読み込むとファイル全体が読み込まれる可能性があります。ファイルはすべてASCIIです。文字までのファイルを読み取る

Pythonは、文字が改行であれば、特定の文字までファイルを読むことができます。私は任意の文字で同じことをしたいと思います。私は、行ごとの読みがバッファリングを介して実装されていると推測します。自分でバッファリングされたリーダーを実装することもできますが、より良い解決策がある場合は、余分なコードとオーバーヘッドを避けることになります。

注:私はいくつか似たような質問をしましたが、すべてが合理的なサイズであると仮定して、ファイルをラインで読み込むべきであると結論づけられました。この場合、ファイル全体はおそらく1行になります。

編集:セグメントターミネーター文字は、ファイルの106番目のバイトです。スクリプトが呼び出される前にはわかりません。

+3

ファイルポインタに '.read(some_reasonable_number)'を使用し、 '〜'を見つけるまで結果を検索し、そうであれば '.seek()'を後方に検索しますか? – L3viathan

+0

私はバッファリングされた読者についてあなたが正しいと信じています。残念ながら、 'open'の' newline'引数は '〜'を許可しません。 –

+2

私はio.BytesIO上で専用の実装を書いて、チャンクでファイルを読んで、* line *を送って、特定の区切り文字で終わってしまうのではないかと心配です... –

答えて

2

を最適化していないコードは、それは非常に簡単なバッファのピュアPython実装のようになります。

def my_open(filename, char): 
    with open(filename) as f: 
     old_fb="" 
     for file_buffer in iter(lambda: f.read(1024), ''): 
      if old_fb: 
       file_buffer = old_fb + file_buffer 
      pos = file_buffer.find(char) 
      while pos != -1 and file_buffer: 
       yield file_buffer[:pos] 
       file_buffer = file_buffer[pos+1:] 
       pos = file_buffer.find(char) 
      old_fb = file_buffer 
     yield old_fb 

# Usage: 
for line in my_open("weirdfile", "~"): 
    print(line) 
4

例えば、あなたのPythonスクリプトにそれをパイプする前にファイルを変換する、と開始するファイル内の改行があるように予定されていない場合は、次の

tr '~' '\n' < source.txt | my-script.py 

その後、必要に応じてreadline()readlines()、またはfor line in file_object:を使用。

+1

そして、プログラムがコマンドライン、stdinではなく、少なくともbashではプロセス置換を使うことができます: 'my-script.py <(tr '〜' '\ n' ShadowRanger

+0

セグメントターミネータは、スクリプト起動時には分かりません。私は元の質問を明確にしました。さらに、このスクリプトはWindows環境で実行されますが、あまりよく慣れていないので、標準のUNIXツールを使用できない可能性があります。また、もしPythonスクリプトがそれを十分に素早く読み取らなかったならば、そのプロセス置換はファイルの内容全体をバッファに効果的に入れませんでしたか? –

0

はたぶん、あなたはこの

警告のようなものが必要です。

これは、はるかに最適からまだ
class File(object): 

    def __init__(self, f): 
     self.file = f 

    def readline(self, delimiter='~'): 
     buffer = '' 
     while True: 
      b = self.file.read(1) 
      buffer += b 
      if b: 
       if b == delimiter: 
        yield buffer 
        buffer = '' 
      else: 
       yield buffer 
       break 
関連する問題