如何用Python创建一个关闭不当的gzip文件?

0 投票
2 回答
44 浏览
提问于 2025-04-12 08:05

我有一个应用程序,有时候需要读取那些没有正确关闭的gzip文件。这些文件的表现是这样的:

>>> import gzip
>>> f = gzip.open("path/to/file.gz", 'rb')
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/gzip.py", line 292, in read
    return self._buffer.read(size)
  File "/usr/lib/python3.8/gzip.py", line 498, in read
    raise EOFError("Compressed file ended before the "
EOFError: Compressed file ended before the end-of-stream marker was reached

我写了一个函数来处理这个问题,它是逐行读取文件,并捕捉EOFError错误,现在我想测试一下这个函数。

我测试的输入应该是一个gz文件,它的表现和上面示例中的一样。我该如何在一个可控的测试环境中做到这一点呢?

我真的很不想复制那些在生产环境中得到的没有正确关闭的文件。

2 个回答

0

我并不想批评这个答案,因为它从技术上来说确实很好地回答了我提出的问题。

我还成功地创建了一个 gzip.GzipFile 的模拟对象,它的行为正好符合我的预期。

% python3 -m pytest test.py
============================================================= test session starts =============================================================
platform darwin -- Python 3.12.2, pytest-8.1.1, pluggy-1.4.0
rootdir: /private/tmp
collected 1 item                                                                                                                              

test.py .                                                                                                                               [100%]

============================================================== 1 passed in 0.03s ==============================================================
% cat test.py
from unittest import mock
import gzip
import pytest

def test_foo():
    f = mock.Mock(gzip.GzipFile)
    f.readline = mock.Mock(side_effect=["hello", EOFError()])
    assert f.readline() == "hello"
    with pytest.raises(EOFError):
        f.readline()

我觉得为了单元测试,这可能是个更干净的解决方案,而不是实际创建文件并读取它,因为我可以简单地模拟打开文件的函数,让它返回我模拟的文件。

2

非常简单:先进行压缩,然后剪切结果。

import gzip
plain = b"Stuff"
compressed = gzip.compress(plain)
bad_compressed = compressed[:-1]

gzip.decompress(bad_compressed)     # EOFError

更简单的是,只有两个字节就足够让gzip模块识别gzip格式,但这显然不是一个完整的压缩文件。

bad_compressed = b'\x1f\x8b'
gzip.decompress(bad_compressed)     # EOFError

这里为了演示方便,都是在内存中操作;如果你对文件进行操作而不是字符串,效果也是一样的。例如:

echo Stuff | gzip | head -c 2 >file.gz

撰写回答