2013-09-07 1 views
1

내 데이터 분석에서는 보통 모든 종류의 아스키 파일 (공백 또는 쉼표로 구분 된 값으로)을 처리해야하며 큰 파일은 정기적으로 압축합니다. 특히 최대 svn에 끝납니다. 파일 이름에서 지퍼 상태를 파악하고 적절한 방식으로 열어주는 anyOpen() 함수를 작성하는 방법이 있습니까?파일 압축에 신경 쓰지 않는 Python 용 일반 파일 열기

+0

최신 버전 파이썬 3 이후 https://github.com/DarkoVeberic/utl/tree/master/futile –

답변

3

예. 예를 들어 아래 예제를 파일 util.py에 넣으십시오. 예를 들어 파일을 (읽기 또는 쓰기 용으로) 열 수있는 솔루션을 구현합니다. in

f1 = util.anyOpen('data.txt') 
f2 = util.anyOpen('data.txt.gz') 
f3 = util.anyOpen('data.txt.bz2') 
f3 = util.anyOpen('data.txt.xz') 

이것은 파일 이름을 명령 줄에서 읽을 때 매우 유용합니다. anyOpen()로 당신은 당신이 압축 풀기가 완료 위치를 제어 할 수 있습니다, 또한,

with util.anyOpen(sys.argv[1]) as f: 
    for line in f: 
     ... 

을 취급 어떤 경우를 다만 따라 파일 이름을 전달할 필요가 없습니다 : external=NORMAL 파이썬 라이브러리와 함께 사용되며,와 함께 external=PROCESS 외부 gzip, bzip2 , 또는 xz 프로세스가 사용됩니다. external=PARALLEL의 경우 병렬 버전 pigzpbzip2이 사용됩니다. 외부 명령이 없으면 함수는 파이썬 라이브러리로 돌아갑니다 (그러나 xz 제외).

추가 된 기능 (티카 구문 유사) filename 인수의 첫 번째 문자로서 느낌표 추가하여 UNIX 파이프를 여는 간단한 방법, 즉 인

date = util.anyOpen('!date').readline() 

또는

ssv_data = util.anyOpen('!cat foo.csv | tr "," " "') 

외부 압축 해제 프로세스가 필요한 이유가 궁금 할 수 있습니다. 몇 가지 이유가 있습니다. (1) 요즘 거의 모든 CPU에 코어가 하나 이상 있고 외부 압축 해제 프로세스로 인해 전체 파일을 사용하여 Python 코드가 I/O를 처리합니다. zip/unzip이 매우 느리기 때문에 파일의 속도는 특히 .bz2 파일에서 눈에 띄게 나타납니다. (2) 파이썬의 gzipbz 모듈은 pigzpbzip2으로 생성 된 다중 스트림 파일의 압축을 지원하지 않습니다. (3) .xz 파일에 대한 Python 지원이 없습니다. which() 기능은 Test if executable exists in Python? 예에서 가져

NORMAL = 0 # use python zip libraries 
PROCESS = 1 # use (zcat, gzip) or (bzcat, bzip2) 
PARALLEL = 2 # (pigz -dc, pigz) or (pbzip2 -dc, pbzip2) 

def anyOpen(filename, mode='r', buff=1024*1024, external=PARALLEL): 
    if 'r' in mode and 'w' in mode: 
     return None 
    if filename.startswith('!'): 
     import subprocess 
     if 'r' in mode: 
      return subprocess.Popen(filename[1:], shell=True, bufsize=buff, 
            stdout=subprocess.PIPE).stdout 
     elif 'w' in mode: 
      return subprocess.Popen(filename[1:], shell=True, bufsize=buff, 
            stdin=subprocess.PIPE).stdin 
    elif filename.endswith('.bz2'): 
     if external == NORMAL: 
      import bz2 
      return bz2.BZ2File(filename, mode, buff) 
     elif external == PROCESS: 
      if not which('bzip2'): 
       return anyOpen(filename, mode, buff, NORMAL) 
      if 'r' in mode: 
       return anyOpen('!bzip2 -dc ' + filename, mode, buff) 
      elif 'w' in mode: 
       return anyOpen('!bzip2 >' + filename, mode, buff) 
     elif external == PARALLEL: 
      if not which('pbzip2'): 
       return anyOpen(filename, mode, buff, PROCESS) 
      if 'r' in mode: 
       return anyOpen('!pbzip2 -dc ' + filename, mode, buff) 
      elif 'w' in mode: 
       return anyOpen('!pbzip2 >' + filename, mode, buff) 
    elif filename.endswith('.gz'): 
     if external == NORMAL: 
      import gzip 
      return gzip.GzipFile(filename, mode, buff) 
     elif external == PROCESS: 
      if not which('gzip'): 
       return anyOpen(filename, mode, buff, NORMAL) 
      if 'r' in mode: 
       return anyOpen('!gzip -dc ' + filename, mode, buff) 
      elif 'w' in mode: 
       return anyOpen('!gzip >' + filename, mode, buff) 
     elif external == PARALLEL: 
      if not which('pigz'): 
       return anyOpen(filename, mode, buff, PROCESS) 
      if 'r' in mode: 
       return anyOpen('!pigz -dc ' + filename, mode, buff) 
      elif 'w' in mode: 
       return anyOpen('!pigz >' + filename, mode, buff) 
    elif filename.endswith('.xz'): 
     if which('xz'): 
      if 'r' in mode: 
       return anyOpen('!xz -dc ' + filename, mode, buff) 
      elif 'w' in mode: 
       return anyOpen('!xz >' + filename, mode, buff) 
    else: 
     return open(filename, mode, buff) 
    return None 

...

모든 많은 경우의 정리는 가장 환영받을 것입니다. 행복한 데이터 원숭이!

+0

에서 찾을 수있다.3xz 파일은 표준 파이썬 라이브러리에서 열 수 있습니다. http://docs.python.org/3.3/library/lzma –

+0

이 솔루션의 최신 버전은 https://github.com/DarkoVeberic/utl/tree/master에서 찾을 수 있습니다./futile –

0

나는 @Darko Vebric 's보다 간단한 해결책을 제안합니다. 내 솔루션은 파이썬 라이브러리 만 사용하므로 다중 스레드 압축 풀기를 지원하지 않습니다. 효율성이 중요하면 자신의 해결책을 찾아야합니다. 단순하고 휴대 가능한 무언가가 필요하면 같은 목표를 달성하는 동안 내 솔루션이 덜 복잡하다고 생각합니다.

나는 이것을 파이썬 3.5에서 테스트했지만 필자가 볼 수있는 한 일반적인 생각은 모든 파이썬 버전에서 작동해야한다. 물론 Python 버전이 lzma와 with 키워드를 지원하는지 확인해야합니다. 다음 용액

import sys 
import gzip 
import bz2 
import lzma 

fn = sys.argv[1] 
if fn.endswith("gz"): 
    anyopen = gzip.open 
elif fn.endswith("bz2"): 
    anyopen = bz2.open 
elif fn.endswith("xz"): 
    anyopen = lzma.open 
else: 
    anyopen = open 

with anyopen(fn) as f: 
    for line in f: 
     # Do something with the lines of the input file 
+0

python2 bz2 모듈에 버그가있어 pbzip2에서 생성 한 다중 스트림 bzip2 파일을 잘못 종료합니다. https://docs.python.org/2/library/bz2.html의 첫 번째 "참고"를 참조하십시오. –

+0

감사합니다. 그걸 지적하면서 @DarkoVeberic! docs에 가면 파이썬 3.3의 어떤 것이라도 안전하다. 파이썬 2.7의 경우 이전에 언급 한 솔루션으로 되돌 리거나 PyPI를 통해 bz2 파일을 설치해야합니다. – Thor

관련 문제