bash 与 python 中的 gzip
gzip in bash vs python
在Bash中,当你gzip一个文件时,原始文件不会被保留,而在Python中,你可以像这样使用gzip库(如here中所示“使用示例”部分):
import gzip
import shutil
with open('/home/joe/file.txt', 'rb') as f_in:
with gzip.open('/home/joe/file.txt.gz', 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
默认情况下,这会保留原始文件。我找不到在压缩时不保留它的方法。我是否必须等到 gzip 完成后才能删除文件?
考虑到 GZip 运行时(在 Bash 或其他任何地方):
- GZip 需要原始数据才能执行压缩操作
- GZip 旨在处理基本上任意大小的数据
- 因此:GZip 不太可能在内存中创建临时文件,而是几乎肯定会在 gzip 完成后删除原始文件。
考虑到这些要点,您的代码的相同策略是执行 gzip,然后 删除文件。
当然,删除文件并不麻烦 — 有几种方法可以做到这一点 — 当然,您可以将整个事情打包在一个过程中,这样您就再也不必担心了。
如果你在类unix系统上,你可以在打开文件后取消链接,这样它就不会再出现在文件系统中。但在您关闭现在匿名的文件之前,它仍会占用磁盘 space。
import gzip
import shutil
import os
with open('deleteme', 'rb') as f_in:
with gzip.open('deleteme.gz', 'wb') as f_out:
os.unlink('deleteme') # *after* we knew the gzip open worked!
shutil.copyfileobj(f_in, f_out)
据我所知,这不适用于 Windows。您需要在压缩过程完成后进行删除。您可以将其名称更改为 "thefile.temporary"
之类的名称,甚至可以将其移动到不同的目录(如果目录是相同的文件系统,则速度很快,但如果目录不同,则复制)。
下面的代码(部分基于 tdelaney 的回答)将执行以下操作:
- 读取文件,即时压缩,并将所有压缩数据存储在内存中
- 删除输入文件
- 然后写入压缩数据
这是针对文件系统已满的用例,这会阻止您在磁盘上存在未压缩文件的同时写入压缩数据。为了解决这个问题,因此有必要将所有数据存储在内存中(除非您可以访问外部存储),但为了尽可能减少内存成本,只有 compressed 数据完全存储在内存中,而 未压缩的 数据以块的形式读取。
如果程序在删除输入文件和完成将压缩数据写入磁盘之间中断,当然存在数据丢失的风险。
如果内存不足也有可能失败,但是输入文件不会被删除,因为MemoryError
会在到达os.unlink
之前产生。
值得注意的是,这不是具体回答了问题的要求,即在删除输入文件的同时仍然从中读取。这在类 unix 操作系统下是可能的,但与常规命令行 gzip
行为相比,这样做没有实际优势,因为在文件关闭之前释放磁盘 space 仍然不会发生,因此它会在发生故障时牺牲可恢复性,而不会获得任何额外的 space 来处理数据以换取这种牺牲。 (仍然 需要磁盘 space 才能使未压缩和压缩的数据共存。)
import gzip
import shutil
import os
from io import BytesIO
filename = 'deleteme'
buf = BytesIO()
# compress into memory - don't store all the uncompressed data in memory
# but do store all the compressed data in memory
with open(filename, 'rb') as fin:
with gzip.open(buf, 'wb') as zbuf:
shutil.copyfileobj(fin, zbuf)
# sanity check for already compressed data
length = buf.tell()
if length > os.path.getsize(filename):
raise RuntimeError("data *grew* in size - refusing to delete input")
# delete input file and then write out the compressed data
buf.seek(0)
os.unlink(filename)
with open(filename + '.gz', 'wb') as fout:
shutil.copyfileobj(buf, fout)
在Bash中,当你gzip一个文件时,原始文件不会被保留,而在Python中,你可以像这样使用gzip库(如here中所示“使用示例”部分):
import gzip
import shutil
with open('/home/joe/file.txt', 'rb') as f_in:
with gzip.open('/home/joe/file.txt.gz', 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
默认情况下,这会保留原始文件。我找不到在压缩时不保留它的方法。我是否必须等到 gzip 完成后才能删除文件?
考虑到 GZip 运行时(在 Bash 或其他任何地方):
- GZip 需要原始数据才能执行压缩操作
- GZip 旨在处理基本上任意大小的数据
- 因此:GZip 不太可能在内存中创建临时文件,而是几乎肯定会在 gzip 完成后删除原始文件。
考虑到这些要点,您的代码的相同策略是执行 gzip,然后 删除文件。
当然,删除文件并不麻烦 — 有几种方法可以做到这一点 — 当然,您可以将整个事情打包在一个过程中,这样您就再也不必担心了。
如果你在类unix系统上,你可以在打开文件后取消链接,这样它就不会再出现在文件系统中。但在您关闭现在匿名的文件之前,它仍会占用磁盘 space。
import gzip
import shutil
import os
with open('deleteme', 'rb') as f_in:
with gzip.open('deleteme.gz', 'wb') as f_out:
os.unlink('deleteme') # *after* we knew the gzip open worked!
shutil.copyfileobj(f_in, f_out)
据我所知,这不适用于 Windows。您需要在压缩过程完成后进行删除。您可以将其名称更改为 "thefile.temporary"
之类的名称,甚至可以将其移动到不同的目录(如果目录是相同的文件系统,则速度很快,但如果目录不同,则复制)。
下面的代码(部分基于 tdelaney 的回答)将执行以下操作:
- 读取文件,即时压缩,并将所有压缩数据存储在内存中
- 删除输入文件
- 然后写入压缩数据
这是针对文件系统已满的用例,这会阻止您在磁盘上存在未压缩文件的同时写入压缩数据。为了解决这个问题,因此有必要将所有数据存储在内存中(除非您可以访问外部存储),但为了尽可能减少内存成本,只有 compressed 数据完全存储在内存中,而 未压缩的 数据以块的形式读取。
如果程序在删除输入文件和完成将压缩数据写入磁盘之间中断,当然存在数据丢失的风险。
如果内存不足也有可能失败,但是输入文件不会被删除,因为MemoryError
会在到达os.unlink
之前产生。
值得注意的是,这不是具体回答了问题的要求,即在删除输入文件的同时仍然从中读取。这在类 unix 操作系统下是可能的,但与常规命令行 gzip
行为相比,这样做没有实际优势,因为在文件关闭之前释放磁盘 space 仍然不会发生,因此它会在发生故障时牺牲可恢复性,而不会获得任何额外的 space 来处理数据以换取这种牺牲。 (仍然 需要磁盘 space 才能使未压缩和压缩的数据共存。)
import gzip
import shutil
import os
from io import BytesIO
filename = 'deleteme'
buf = BytesIO()
# compress into memory - don't store all the uncompressed data in memory
# but do store all the compressed data in memory
with open(filename, 'rb') as fin:
with gzip.open(buf, 'wb') as zbuf:
shutil.copyfileobj(fin, zbuf)
# sanity check for already compressed data
length = buf.tell()
if length > os.path.getsize(filename):
raise RuntimeError("data *grew* in size - refusing to delete input")
# delete input file and then write out the compressed data
buf.seek(0)
os.unlink(filename)
with open(filename + '.gz', 'wb') as fout:
shutil.copyfileobj(buf, fout)