python - 为Python打开的一般文件,不关心文件压缩

标签 python file-io

在我的数据分析中,我通常必须处理各种 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 >、bzip2xz 进程被使用;对于 external=PARALLEL,使用并行版本 pigzpbzip2。如果没有找到外部命令,该函数将回退到 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 的 gzipbz 模块不支持解压缩 pigzpbzip2 创建的多流文件。 (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/

相关文章:

python - 大型正则表达式模式中的正则表达式 'sre_constants.error: bad character range'

python - 如何使用 Python 和 web3.py 调用智能合约函数

python - 由于缺少 EntitySet.read_pickle() 方法,无法部署功能工具

java - 打开和分析 ASCII 文件

c# - 优化 C# 文件 IO

delphi - 文件操作 - 复制和移动 - Delphi

java getBytes() 在 python 中等效

python - 图形显示窗口保持隐藏状态

c - c语言从文件中读取数据

java - Spring FileInputStream 缓冲区偶尔包含不正确的字符