AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 415799
Accepted
k0pernikus
k0pernikus
Asked: 2018-01-10 03:42:05 +0800 CST2018-01-10 03:42:05 +0800 CST 2018-01-10 03:42:05 +0800 CST

如何部分提取压缩的巨大纯文本文件?

  • 772

我有一个大小为 1.5 GB 的 zip 文件。

它的内容是一个可笑的大纯文本文件(60 GB),我目前的磁盘上没有足够的空间来提取它,我也不想全部提取它,即使我有。

至于我的用例,如果我可以检查部分内容就足够了。

因此,我想将文件解压缩为流并访问文件的范围(就像可以通过普通文本文件的头部和尾部一样)。

通过内存(例如,从 32GB 标记开始提取最大 100kb)或按行(给我纯文本行 3700-3900)。

有没有办法做到这一点?

text-processing zip
  • 6 6 个回答
  • 10755 Views

6 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2018-01-10T06:17:01+08:002018-01-10T06:17:01+08:00

    注意gzip可以提取zip文件(至少是文件中的第一个条目zip)。因此,如果该存档中只有一个大文件,您可以执行以下操作:

    gunzip < file.zip | tail -n +3000 | head -n 20
    

    例如,提取从第 3000 行开始的 20 行。

    或者:

    gunzip < file.zip | tail -c +3000 | head -c 20
    

    对于与字节相同的事情(假设head实现支持-c)。

    对于存档中的任意成员,以 Unixy 方式:

    bsdtar xOf file.zip file-to-extract | tail... | head...
    

    使用head内置的ksh93(例如 when /opt/ast/binis ahead in $PATH),您还可以执行以下操作:

    .... | head     -s 2999      -c 20
    .... | head --skip=2999 --bytes=20
    

    请注意,在任何情况下gzip//始终需要解压缩bsdtar(unzip并在此处丢弃)指向您要提取的部分的文件的整个部分。这取决于压缩算法的工作方式。

    • 31
  2. tonioc
    2018-01-10T04:23:10+08:002018-01-10T04:23:10+08:00

    一种使用 unzip -p 和 dd 的解决方案,例如以 1000 个块偏移量提取 10kb:

    $ unzip -p my.zip | dd ibs=1024 count=10 skip=1000 > /tmp/out
    

    注意:我没有用非常大的数据尝试这个......

    • 14
  3. 111---
    2018-01-10T05:10:07+08:002018-01-10T05:10:07+08:00

    如果您可以控制该大 zip 文件的创建,为什么不考虑使用gzip和的组合zless呢?

    这将允许您zless用作寻呼机并查看文件的内容,而不必费心提取。

    如果您无法更改压缩格式,那么这显然行不通。如果是这样,我觉得zless还是比较方便的。

    • 4
  4. Diomidis Spinellis
    2018-01-10T07:38:57+08:002018-01-10T07:38:57+08:00

    要查看文件的特定行,请将输出通过管道传输到 Unix 流编辑器sed。这可以处理任意大的数据流,因此您甚至可以使用它来更改数据。要按照您的要求查看第 3700-3900 行,请运行以下命令。

    unzip -p file.zip | sed -n 3700,3900p
    
    • 3
  5. Peter Cordes
    2018-01-11T07:17:42+08:002018-01-11T07:17:42+08:00

    我想知道是否有可能做任何比从文件开头一直解压缩更有效的事情。看来答案是否定的。但是,在某些 CPU (Skylake)zcat | tail上不会将 CPU 提升到全时钟速度。见下文。自定义解码器可以避免该问题并节省管道写入系统调用,并且可能快约 10%。(或者,如果您不调整电源管理设置,Skylake 的速度会提高约 60%)。


    使用带有skipbytes函数的自定义 zlib 可以做的最好的事情是解析压缩块中的符号以到达结尾,而无需执行实际重建解压缩块的工作。这可能比调用 zlib 的常规解码函数覆盖相同的缓冲区并在文件中前进要快得多(可能至少 2 倍)。但我不知道是否有人写过这样的功能。(而且我认为这实际上不起作用,除非文件是专门编写的以允许解码器在某个块重新启动)。

    我希望有一种方法可以跳过 Deflate 块而不解码它们,因为那样会快得多。霍夫曼树在每个块的开头发送,因此您可以从任何块的开头解码(我认为)。哦,我认为解码器状态不仅仅是霍夫曼树,它也是之前的 32kiB 解码数据,默认情况下不会跨块边界重置/遗忘。相同的字节可以不断被重复引用,因此在一个巨大的压缩文件中可能只出现一次。(例如,在日志文件中,主机名可能一直在压缩字典中保持“热”,并且它的每个实例都引用前一个,而不是第一个)。

    该zlib手册说,如果您希望压缩流可搜索到该点,则必须Z_FULL_FLUSH在调用时使用。deflate它“重置压缩状态”,所以我认为没有它,向后引用可以进入前一个块。因此,除非您的 zip 文件是用偶尔的全刷新块编写的(例如每 1G 或其他东西对压缩的影响可以忽略不计),否则我认为您将不得不做更多的工作来解码到您想要的点,而不是我最初思维。我猜您可能无法从任何块的开头开始。


    其余部分是在我认为可以找到包含所需第一个字节的块的开头并从那里解码时编写的。

    但不幸的是,对于压缩块,Deflate 块的开头并不表示它有多长。不可压缩的数据可以使用前面有 16 位字节大小的未压缩块类型进行编码,但压缩块没有:RFC 1951 描述了这种格式非常可读。具有动态霍夫曼编码的块在块的前面有树(因此解压缩器不必在流中查找),因此压缩器必须在写入之前将整个(压缩的)块保存在内存中。

    最大后向参考距离仅为 32kiB,因此压缩器不需要在内存中保留太多未压缩的数据,但这并不限制块大小。块可以有数兆字节长。(如果可以在不解析当前块的情况下找到当前块的结尾,那么即使在磁驱动器上,磁盘寻道也足够​​大,而不是顺序读入内存并跳过 RAM 中的数据)。

    zlib 使块尽可能长: 根据 Marc Adler的说法,zlib 仅在符号缓冲区填满时才开始一个新块,默认设置为 16,383 个符号(文字或匹配)


    我压缩了seq(这是极其冗余的,因此可能不是一个很好的测试)的输出,但pv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -c在 Skylake i7-6700k 上以 3.9GHz 运行,压缩数据仅为 62 MiB/s,DDR4-2666 RAM。这是 246MiB/s 的解压缩数据,与memcpy因块大小太大而无法放入缓存的 ~12GiB/s 的速度相比,这是一个巨大的变化。

    (energy_performance_preference设置为默认值balance_power而不是balance_performance,Skylake 的内部 CPU 调控器决定仅以 2.7GHz 运行,压缩数据约为 43 MiB /s。我sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'用来调整它。可能如此频繁的系统调用看起来不像真正的 CPU 绑定工作到电源管理单元。)

    TL:DR:zcat | tail -c即使在快速 CPU 上也会受到 CPU 限制,除非您的磁盘非常慢。 gzip 使用了它运行的 100% 的 CPU(并且每个时钟运行 1.81 条指令,根据perf),并tail使用了它运行的 CPU 的 0.162(0.58 IPC)。否则,系统大多处于空闲状态。

    我正在使用 Linux 4.14.11-1-ARCH,它默认启用了 KPTI以解决 Meltdown,因此所有这些write系统调用gzip都比以前更昂贵:/


    将 seek 内置到unzipor zcat(但仍使用常规zlib解码功能)将保存所有这些管道写入,并使 Skylake CPU 以全时钟速度运行。(这种针对某些负载的降频是英特尔 Skylake 及更高版本所独有的,它们从操作系统中卸载了 CPU 频率决策,因为它们有更多关于 CPU 正在做什么的数据,并且可以更快地加速/减速。这是通常很好,但这里会导致 Skylake 无法在更保守的调速器设置下全速运行)。

    没有系统调用,只需重写适合 L2 缓存的缓冲区,直到您到达所需的起始字节位置,可能至少会产生几个 % 的差异。甚至可能是 10%,但我只是在这里编造数字。我没有zlib详细分析它有多大的缓存占用空间,以及启用 KPTI 时每个系统调用上的 TLB 刷新(以及因此 uop-cache 刷新)有多少伤害。


    有一些软件项目确实为 gzip 文件格式添加了搜索索引。如果您无法让任何人为您生成可搜索的压缩文件,这对您没有帮助,但其他未来的读者可能会受益。

    据推测,这些项目都没有解码功能,知道如何在没有索引的情况下跳过 Deflate 流,因为它们仅设计为在索引可用时工作。

    • GZinga:可搜索和可拆分的 Gzip。允许大块大小。
    • BGZF - 封锁、更大、更好的 GZIP!(小的最大块大小 = 64kiB 会稍微损害压缩率。设计用于生物信息学数据,如 FASTA,通常未压缩使用,在某些 python 库中具有透明支持。)
    • 3
  6. Steve Barnes
    2018-01-13T10:41:36+08:002018-01-13T10:41:36+08:00

    您可以在 python 会话中打开 zip 文件,zf = zipfile.ZipFile(filename, 'r', allowZip64=True)一旦打开,您就可以打开 zip 存档中的任何文件并从中读取行等,就像它是普通文件一样。

    • 1

相关问题

  • grep 从 $START 到 $END 的一组行并且在 $MIDDLE 中包含匹配项

  • 重新排列字母并比较两个单词

  • 在awk中的两行之间减去相同的列

  • 多行文件洗牌

  • 如何更改字符大小写(从小到大,反之亦然)?同时[重复]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve