OSError:[Errno 36]使用Popen-Python时文件名太长

时间:2015-05-28 12:36:44

标签: python pipe stdout

当我开始询问上一个问题时,我正在使用python的tarfile模块提取tarball。我不希望将提取的文件写在磁盘上,而是直接通过管道传输到另一个程序,特别是bgzip。

#!/usr/bin/env python
import tarfile, subprocess, re
mov = []
def clean(s):
   s = re.sub('[^0-9a-zA-Z_]', '', s)
   s = re.sub('^[^a-zA-Z_]+', '', s)
   return s
with tarfile.open("SomeTarballHere.tar.gz", "r:gz") as tar:
    for file in tar.getmembers():
        if file.isreg():
            mov = file.name
            proc = subprocess.Popen(tar.extractfile(file).read(), stdout = subprocess.PIPE)
            proc2 = subprocess.Popen('bgzip -c > ' + clean(mov), stdin = proc, stdout = subprocess.PIPE)           
            mov = None

但现在我对此感到困惑:

Traceback (most recent call last):
  File "preformat.py", line 12, in <module>
    proc = subprocess.Popen(tar.extractfile(file).read(), stdout = subprocess.PIPE)
  File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1335, in _execute_child
raise child_exception
OSError: [Errno 36] File name too long

这有什么解决方法吗?我一直在使用LightTableLinux.tar.gz(它包含文本编辑器程序的文件)作为tarball来测试它上面的脚本。

1 个答案:

答案 0 :(得分:1)

尝试从此调用执行目标程序时,在分叉子进程中引发异常:

proc = subprocess.Popen(tar.extractfile(file).read(), stdout = subprocess.PIPE)

  1. 读取tar文件中条目的内容
  2. 尝试使用该条目的内容名称执行程序。
  3. 此外,您的第二次调用无效,因为您尝试使用shell重定向而不使用shell=True中的Popen()

    proc2 = subprocess.Popen('bgzip -c > ' + clean(mov), stdin = proc, stdout = subprocess.PIPE) 
    

    重定向也可能没有必要,因为您应该能够直接将bgzip的输出重定向到python中的文件。

    修改:很遗憾,尽管extractfile()返回类似文件的对象,但Popen()仍需要真实的filefileno}。因此,需要一点包装:

    with tar.extractfile(file) as tarfile, file(clean(mov), 'wb') as outfile:
        proc = subprocess.Popen(
            ('bgzip', '-c'),
            stdin=subprocess.PIPE,
            stdout=outfile,
        )
        shutil.copyfileobj(tarfile, proc.stdin)
        proc.stdin.close()
        proc.wait()