在我的数据分析中,我通常必须处理各种 ascii 文件(使用空格或逗号分隔值),以及我定期压缩的大型文件,特别是如果它们最终位于 svn
中。有没有办法编写一个 anyOpen()
函数,从文件名中找出 zip 状态并以适当的方式打开它?
最佳答案
是的。例如,将下面的示例放入文件 util.py
中。它实现了一个解决方案,您可以简单地打开文件(用于读取或写入),例如在
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
使用 Python 库,使用 external=PROCESS
外部 gzip
>、bzip2
或 xz
进程被使用;对于 external=PARALLEL
,使用并行版本 pigz
和 pbzip2
。如果没有找到外部命令,该函数将回退到 python 库(但不适用于 xz
)。
添加的功能是通过添加感叹号作为filename
参数的第一个字符(类似于Mathematica语法)来打开unix管道的简单方法,即
date = util.anyOpen('!date').readline()
或
ssv_data = util.anyOpen('!cat foo.csv | tr "," " "')
您可能想知道为什么需要外部进程来解压缩?有几个原因:(1) 现在几乎每个 CPU 都有多个核心,外部解压过程使您的 Python 代码使用完整核心处理此文件的 I/O。由于 zip/unzip 非常慢,因此 .bz2
文件的加速效果尤其明显。 (2) Python 的 gzip
和 bz
模块不支持解压缩 pigz
和 pbzip2
创建的多流文件。 (3) Python 不支持 .xz
文件。
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
which()
函数取自 Test if executable exists in Python?例子...
我们非常欢迎清理所有的案件。快乐的数据挖掘!
关于python - 为Python打开的一般文件,不关心文件压缩,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18675471/