2016-07-01 8 views
0

압축을 풀고 편집하고 재 압축해야하는 꽤 큰 gzipped 텍스트 파일로 작업하고 있습니다. 참을 느리다파이썬 서브 프로세스를 통해 파일이나 셸 프로그램에 파이프하는 방법은 무엇입니까?

input_file = gzip.open(input_file_name, 'rb') 

output_file = gzip.open(output_file_name, 'wb') 

for line in input_file: 
    # Edit line and write to output_file 

이러한 접근 방식 -에 부합 반복 당 일에 관여 큰 오버 헤드가 아마 때문에 : 나는 압축 해제 및 압축에 대한 비단뱀은 gzip 모듈을 사용하지만, 나는 나의 현재 구현은 최적의 거리가 멀다는 것을 발견했다 gzip 모듈 : 처음에는 gzip 모듈을 사용하여 라인 카운트 루틴을 실행했습니다. 파일의 청크를 읽은 다음 각 청크에서 개행 문자의 수를 계산하면 매우 빠릅니다!

그래서 최적화 중 하나는 청크로 내 파일을 읽은 다음 청크 압축을 풀면 한 줄 반복마다 수행해야합니다.

추가 최적화로서, 하위 프로세스를 통해 쉘 명령에서 압축을 풀려면 몇 가지 제안을 보았습니다. 이 방법을 사용하여, 상기의 제 1 라인의 상응 될 수있다 : 이러한 접근 INPUT_FILE 사용

from subprocess import Popen, PIPE 

file_input = Popen(["zcat", fastq_filename], stdout=PIPE) 

input_file = file_input.stdout 

파일과 같은 개체가된다. 사용 가능한 속성과 메소드면에서 실제 파일 객체와 다른 점은 정확히 알지 못하지만 한 가지 차이점은 파일이 아니라 스트림이므로 분명히 탐색을 사용할 수 없다는 것입니다.

이것은 더 빨리 실행됩니다. 스크립트를 단일 핵심 컴퓨터에서 실행하지 않는 한 소유권 주장은 다음과 같습니다. 후자는 서브 프로세스가 가능하다면 다른 스레드를 다른 코어에 자동으로 배송한다는 것을 의미해야합니다. 그러나 나는 전문가가 아닙니다.

이제 내 현재 문제 : 비슷한 방식으로 출력을 압축하고 싶습니다. 즉 Pythons gzip 모듈을 사용하는 대신 하위 프로세스로 파이프를 연결 한 다음 쉘 gzip을 호출하고 싶습니다. 이 방법을 사용하면 잠재적으로 독서, 편집 및 글쓰기를 별도의 코어에서 수행 할 수 있습니다. 나는 이것에 힘이없는 시도를했지만, output_file에 쓰려고하면 빈 파일이 생겼다. , 어떤 도움이 크게 감사합니다

call('touch ' + output_file_name, shell=True) 

output = Popen(["gzip", output_file_name], stdin=PIPE) 

output_file = output.stdin 

을 나는 방법으로 파이썬 2.7을 사용하고 있습니다 : 처음에 파일이 존재하지 않는 경우는 popen 실패 때문에 터치 명령을 사용하여 빈 파일을 만듭니다. 감사.

+0

성능 질문이있는 경우 벤치 마크로 사용하고 원하는 목표를 명시 할 수있는 최소 코드 예제를 만듭니다 (예 :(gzipped) 데이터를 100MB/s로 만드십시오. - 디스크가 그보다 훨씬 빠르다고 생각합니다. 디스크를 읽고 쓸 수있는 것보다 빠르게 (압축 된) 데이터를 처리 할 필요가 없습니다.) --- 그리고 게시하십시오. 별도의 질문으로 – jfs

+0

사실이게 다가오고있는 경우에 대비해 배경을 제공하는 것은 아닙니다. 내가 정말로 알고 싶은 것은 셸 프로그램으로 파이프하는 것이고 내 경우에는 멋진 gzipped 파일로 끝내는 것이다. 읽기/쓰기 속도는 여기에서 문제가되지 않습니다. 입력 및 출력 파일이 일반 텍스트 파일, 즉 더 많은 데이터가있는 읽기/쓰기가 큰 파일 인 경우 훨씬 빠르게 실행됩니다. 전반적으로 쉘에서 입력 파일의 압축을 풀고 스크립트를 실행하고 쉘에서 출력 파일을 압축하는 것이 더 빠릅니다. –

답변

1

는이 작업을 수행 할 수있는 방법의 일 예이다
script_that_writes_to_console | gzip > output.txt.gz 
+1

1- 내가 제안한 바입니다 (크레딧을 주어야합니다). 2- 입력이 미리 알려졌다면, 대신에'gzip_process.communicate ("\ n".join (output))'를 사용할 수 있습니다. 3-'gzip_output_file.close()'는'Popen()'바로 다음에 호출 될 수 있습니다. 부모 4-'gzip_process'는'output_stream'보다 더 나은 이름입니다 (gzip 프로세스는 스트림 자체가 아닙니다 (파일과 같은 객체가 아닙니다), stdin/stdout/stderr 스트림이있을 수있는 프로세스입니다). – jfs

+0

@ J.F. Sebastian 여기에 문제가 있습니다. 마침내 내가 이것을 깨뜨린 것은 당신의 대답 때문이 아니 었습니다. 나는 Popen을 완전히 오해했다. 그래서 내가 너를 오해하고있다. 효과가 있었던 것은 내가 당신의 음산한 음색에 완전히 화가났다는 것이 었습니다. 갑자기 모든 코드가 클릭되어 제 코드 작업을 할 때까지 클래스의 문서를 다시 읽도록했습니다. 나에게 당신의 대답이 명확하지 않았고 나는 그것을 이해하지 못했기 때문에 나는 당신에게 신용을주지 않았다. 옳고 명확한 것의 차이가 있다는 것을 알고 계십니까? 그런 세부 사항에 더 많은주의를 기울여야합니다. –

+0

의견에 감사드립니다. 나는이 [이 코멘트가 당신에게 불쾌감을 준다고 가정합니다.] (http://stackoverflow.com/questions/38146282/how-do-i-pipe-to-a-file-or-shell-program-via-pythons-subprocess/38146835?noredirect = 1 # comment63747888_38146835). 같은 정보를 적은 "응축음"*으로 어떻게 전달하겠습니까? ('output_file'과'gzip_output_file'은 다른 객체를 참조하는 다른 이름입니다 - 이해하기 위해서는'subprocess' 모듈에 대해 * 아무것도 * 알 필요가 없습니다) – jfs

1

당신은 output_file = gzip_process.stdin을 의미했습니다. 그 후에 gzip.open() 개체를 이전에 (no-seeking) 사용 했으므로 output_file을 사용할 수 있습니다.

결과 파일이 비어 있으면 Python 스크립트의 끝에 output_file.close()gzip_process.wait()을 호출하는지 확인하십시오. 또한 gzip의 사용법이 올바르지 않을 수 있습니다. gzip이 압축 된 출력을 stdout에 쓰는 경우 stdout=gzip_output_file 인 경우 gzip_output_file = open(output_file_name, 'wb', 0)을 전달하십시오. 우리의 스크립트는 콘솔에 쓴 우리는 출력이 압축 원한다면

#!/usr/bin/env python 

from subprocess import Popen, PIPE 

output = ['this', 'is', 'a', 'test'] 

output_file_name = 'pipe_out_test.txt.gz' 

gzip_output_file = open(output_file_name, 'wb', 0) 

output_stream = Popen(["gzip"], stdin=PIPE, stdout=gzip_output_file) # If gzip is supported 

for line in output: 
    output_stream.stdin.write(line + '\n') 

output_stream.stdin.close() 
output_stream.wait() 

gzip_output_file.close() 

이의 쉘 명령과 동등한 위의 수 :

다음
+0

예, 당신은 첫 번째 부분에 대해 옳습니다. 나는 그것을 편집 했으므로 이제는 더 분명하다. 또한 이전에 생략 된 call 명령을 추가했습니다. 이전에 파일을 닫고 wait() 메서드를 시도했지만 여전히 파일이 비어 있습니다. –

+0

@StephenMiller 이미 말했듯이, gzip 사용이 올바르지 않을 수 있습니다. 'Popen ([ "gzip"], stdout = gzip_output_file, ...)'을 사용하십시오. 'touch' 콜을 버리십시오 (쓸모가 없습니다). – jfs

+0

자, 이제 알았다. 나는 당신의 제안을 시도했지만 결과물이 파일과 같은 것이 아닌 것 같다. 내가 할 때 : output_file.stdout.write (줄) 얻을 : AttributeError : 'NoneType'개체에 '쓰기'특성이 없습니다. –