【问题标题】:zlib to compress/decompress in a file with python [duplicate]zlib用python压缩/解压缩文件[重复]
【发布时间】:2020-04-11 17:48:06
【问题描述】:

使用 zlib,我希望能够压缩 numpy 数组并将它们写入文件,然后能够将它们读回。我做了以下

with open(outputFile, 'wb') as zFile:
    for row in array:
        compressed = zlib.compress(row, compressionLevel)
        zFile.write(compressed)
with open(os.path.join(path, fileName), 'rb') as zFile:
    for line in zFile:
        decompressed = zlib.decompress(line)
        data.append(decompressed)
data = np.array(data)

写入过程在填充文件时起作用,如果我使用compressionLevel = 0 写入更简单的数据,就可以了。但我无法使阅读过程正常工作。我尝试对zlib.compress(row.tobytes() + '\n'.encode(), compressionLevel) 执行操作,以便可以读取正确的行,但我的数据中的某些元素似乎被解释为\n,因此它不会读取真正的行。

我还尝试在 while 循环中读取执行 zFile.read(bufferSize) 的文件,并在没有更多内容可读取时中断循环,但之前压缩的每个元素都有不同的大小(由于每一行的性能不同)所以我无法提前知道缓冲区大小。

编辑: 关于答案,似乎 np.savez_compress 更适合,但现在,我坚持使用 zlib,因为它可以在项目的其他地方使用,我不能自己更改它现在。

【问题讨论】:

  • @snakecharmerb 非常感谢。这比我尝试的要好得多。它实际上对我有用。但是我仍然遇到问题,因为当流很大时,这个解决方案似乎很慢。我用于测试的文件大约是 10Mo,但真正的文件可能大约是 500Mo,但我需要大约 25 秒来解压缩我的测试文件。这就是我尝试逐行读取文件的部分原因,这样我就不必每次都处理整个剩余的未解压缩部分。
  • 关于 decompressobj,我认为它不会输出任何内容,除非它具有完整的真实行(知道标题的长度),以便我可以循环“假”行并将它们提供给 compressobj .但这不是我所拥有的行为,因为它可以随时输出一些东西,而没有完整的真实线路。
  • 就速度而言,AFAICT zlib 只是用 C 语言编写的围绕系统 zlib 库的包装器 - 在 stdlib 中甚至没有 zlib.py。所以我不确定如何在不使用较少压缩的情况下加速它。

标签: python python-3.x zlib


【解决方案1】:

压缩 numpy 数组的最佳选择之一是使用 np.savez_compressed。 这会更好,但会更慢。我不认为你的压缩代码是正确的

import numpy as np
import zlib
input_arr = np.arange(100)
dtype = input_arr.dtype
compressed_arr = zlib.compress(input_arr, 2)
decompressed_arr = np.fromstring(zlib.decompress(compressed_arr), dtype)

你也可以使用blosc,性能更好

【讨论】:

  • 谢谢!你可以在我编辑的时候查看我的帖子。我现在无法从 zlib 更改。但是你的意思是我的压缩代码不正确?
  • 我认为你应该在读取字符串时使用 np.fromstring,就像我在示例代码中所做的那样
  • 是的,你说得对,它与 np.fromstring/np.frombuffer 一起工作得更好,但我仍然无法读取文件,因为我无法读取固定缓冲区大小(每行压缩导致不同大小),并且压缩行的某些元素被视为\n,因此它不会检索实际行。
【解决方案2】:

使用内置的numpy.savez_compressed? 来自numpy docs

>>> test_vector = np.random.rand(4)
>>> np.savez_compressed('/tmp/123', a=test_array, b=test_vector)
>>> loaded = np.load('/tmp/123.npz')
>>> print(np.array_equal(test_array, loaded['a']))
True
>>> print(np.array_equal(test_vector, loaded['b']))
True

【讨论】:

  • 不知道,看起来不错,如果用 zlib 真的不可能做到这一点,我会考虑这个解决方案,但如果有一个 zlib 的解决方案也可能会很棒在项目的其他地方使用。谢谢!
  • 我明白了。我确信使用 zlib 是可能的,但我最近的态度是使用库几乎总是更容易,并且很高兴其他人为我找出了所有的问题和极端情况。
  • 你说得对。问题是整个项目包含与 python 模块交互的 C++ 模块(使用 zlib),并且文件可能被两者使用。
【解决方案3】:

所以,总而言之,我现在不能使用 zlib 以外的其他东西,但是:

  • 我可以完全压缩/解压缩(唯一的)numpy 数组并将其写入/读取到文件中/从文件中读取,具体操作如下:
row = array[0,:]
with open(outputFile, 'wb') as zFile:
    print(row)
    compressed = zlib.compress(row, compressionLevel)
    zFile.write(compressed)
with open(os.path.join(path, fileName), 'rb') as zFile:
    decompressed = zlib.decompress(zFile.read())
    data = np.frombuffer(decompressed, dtype=np.float))
    print(data)
  • 我添加了 np.frombuffer,正如 sagarwal 所指出的(实际上 np.frombuffernp.fromstring 好)和 print(row)print(data) 给出了同样的结果。当我在编写过程中添加一个 for 循环以在文件中添加几个压缩行时,问题就来了。因此我很难检索每个完整大小的压缩行(带有for line in zFile: ...)来一次解压缩它们。实际上,每个压缩行中的某些元素被视为\n,因此不会检索到真正的行(至尊给出zlib.error: Error -5 while decompressing data: incomplete or truncated stream

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多