AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 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

Como extrair parcialmente um enorme arquivo de texto simples compactado?

  • 772

Eu tenho um arquivo zip com tamanho de 1,5 GB.

Seu conteúdo é um arquivo de texto simples grande e ridículo (60 GB) e atualmente não tenho espaço suficiente em meu disco para extrair tudo nem quero extrair tudo, mesmo que tivesse.

Quanto ao meu caso de uso, seria suficiente se eu pudesse inspecionar partes do conteúdo.

Portanto, desejo descompactar o arquivo como um fluxo e acessar um intervalo do arquivo (como se pode fazer cabeça e cauda em um arquivo de texto normal).

Tanto pela memória (por exemplo, extraia no máximo 100kb a partir da marca de 32GB) ou por linhas (me dê as linhas de texto simples 3700-3900).

Existe uma maneira de conseguir isso?

text-processing zip
  • 6 6 respostas
  • 10755 Views

6 respostas

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

    Observe que gzippode extrair ziparquivos (pelo menos a primeira entrada no ziparquivo). Portanto, se houver apenas um arquivo enorme nesse arquivo, você poderá fazer:

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

    Para extrair as 20 linhas começando com a 3000, por exemplo.

    Ou:

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

    Para o mesmo com bytes (assumindo uma headimplementação que suporta -c).

    Para qualquer membro arbitrário no arquivo, de forma Unixy:

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

    Com o headembutido de ksh93(como quando /opt/ast/binestá à frente em $PATH), você também pode fazer:

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

    Observe que em qualquer caso gzip/ bsdtar/ unzipsempre será necessário descompactar (e descartar aqui) toda a seção do arquivo que leva à parte que você deseja extrair. Isso depende de como o algoritmo de compactação funciona.

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

    Uma solução usando unzip -p e dd, por exemplo, para extrair 10kb com deslocamento de 1000 blocos:

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

    Nota: não tentei isso com dados realmente grandes ...

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

    Se você tem controle sobre a criação desse grande arquivo zip, por que não considerar o uso de uma combinação de gzipe zless?

    Isso permitiria que você usasse zlesscomo um pager e visualizasse o conteúdo do arquivo sem ter que se preocupar com a extração.

    Se você não puder alterar o formato de compactação, isso obviamente não funcionará. Se assim for, sinto que zlessé bastante conveniente.

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

    Para visualizar linhas específicas do arquivo, canalize a saída para o editor de fluxo do Unix, sed . Isso pode processar fluxos de dados arbitrariamente grandes, então você pode até mesmo usá-lo para alterar os dados. Para visualizar as linhas 3700-3900 conforme solicitado, execute o seguinte.

    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

    Eu me perguntei se era possível fazer algo mais eficiente do que descompactar desde o início do arquivo até o ponto. Parece que a resposta é não. No entanto, em algumas CPUs (Skylake) zcat | tailnão acelera a CPU até a velocidade máxima do clock. Veja abaixo. Um decodificador personalizado pode evitar esse problema e salvar as chamadas do sistema de gravação de canal e talvez ser ~ 10% mais rápido. (Ou ~ 60% mais rápido no Skylake se você não ajustar as configurações de gerenciamento de energia).


    O melhor que você poderia fazer com um zlib personalizado com uma skipbytesfunção seria analisar os símbolos em um bloco de compactação para chegar ao fim sem fazer o trabalho de realmente reconstruir o bloco descompactado. Isso pode ser significativamente mais rápido (provavelmente pelo menos 2x) do que chamar a função de decodificação regular do zlib para sobrescrever o mesmo buffer e avançar no arquivo. Mas não sei se alguém escreveu essa função. (E acho que isso realmente não funciona, a menos que o arquivo tenha sido escrito especialmente para permitir que o decodificador reinicie em um determinado bloco).

    Eu esperava que houvesse uma maneira de pular os blocos Deflate sem decodificá-los, porque seria muito mais rápido. A árvore Huffman é enviada no início de cada bloco, para que você possa decodificar desde o início de qualquer bloco (eu acho). Ah, acho que o estado do decodificador é mais do que a árvore Huffman, é também os 32kiB anteriores de dados decodificados, e isso não é redefinido / esquecido nos limites do bloco por padrão. Os mesmos bytes podem continuar sendo referenciados repetidamente, portanto, podem aparecer apenas uma vez literalmente em um arquivo compactado gigante. (por exemplo, em um arquivo de log, o nome do host provavelmente permanece "quente" no dicionário de compactação o tempo todo e cada instância dele faz referência ao anterior, não ao primeiro).

    O zlibmanual diz que você deve usar Z_FULL_FLUSHao chamar deflatese quiser que o fluxo compactado seja pesquisável até esse ponto. Ele "redefine o estado de compactação", então acho que sem isso, as referências reversas podem ir para o (s) bloco (s) anterior (is). Portanto, a menos que seu arquivo zip tenha sido escrito com blocos full-flush ocasionais (como cada 1G ou algo assim teria um impacto insignificante na compactação), acho que você teria que fazer mais trabalho de decodificação até o ponto desejado do que inicialmente pensamento. Eu acho que você provavelmente não pode começar no início de qualquer bloco.


    O resto disso foi escrito enquanto eu pensava que seria possível apenas encontrar o início do bloco contendo o primeiro byte que você deseja e decodificar a partir daí.

    Mas, infelizmente, o início de um bloco Deflate não indica quanto tempo ele dura , para blocos compactados. Os dados incompressíveis podem ser codificados com um tipo de bloco não compactado que tem um tamanho de 16 bits em bytes na frente, mas os blocos compactados não: RFC 1951 descreve o formato de forma bastante legível . Os blocos com codificação Huffman dinâmica têm a árvore na frente do bloco (para que o descompactador não precise procurar no fluxo), portanto, o compressor deve ter mantido todo o bloco (compactado) na memória antes de escrevê-lo.

    A distância máxima de referência para trás é de apenas 32kiB, portanto o compressor não precisa manter muitos dados não compactados na memória, mas isso não limita o tamanho do bloco. Os blocos podem ter vários megabytes de comprimento. (Isso é grande o suficiente para que a busca em disco valha a pena mesmo em uma unidade magnética, versus leitura sequencial na memória e apenas pulando dados na RAM, se fosse possível encontrar o final do bloco atual sem analisá-lo).

    zlib torna os blocos tão longos quanto possível: De acordo com Marc Adler , o zlib só inicia um novo bloco quando o buffer de símbolos é preenchido, que com a configuração padrão é de 16.383 símbolos (literais ou correspondências)


    Compactei a saída de seq(que é extremamente redundante e, portanto, provavelmente não é um ótimo teste), mas pv < /tmp/seq1G.gz | gzip -d | tail -c $((1024*1024*1000)) | wc -croda a apenas ~ 62 MiB/s de dados compactados em um Skylake i7-6700k a 3,9 GHz, com RAM DDR4-2666. São 246 MiB/s de dados descompactados, o que é uma mudança grosseira em comparação com a memcpyvelocidade de aproximadamente 12 GiB/s para tamanhos de bloco muito grandes para caber no cache.

    (Com energy_performance_preferenceo padrão definido em balance_powervez de balance_performance, o controlador interno da CPU do Skylake decide executar apenas a 2,7 GHz, ~ 43 MiB / s de dados compactados. Eu uso sudo sh -c 'for i in /sys/devices/system/cpu/cpufreq/policy[0-9]*/energy_performance_preference;do echo balance_performance > "$i";done'para ajustá-lo. Provavelmente, essas chamadas de sistema frequentes não parecem reais vinculadas à CPU funciona para a unidade de gerenciamento de energia.)

    TL:DR: zcat | tail -cé vinculado à CPU mesmo em uma CPU rápida, a menos que você tenha discos muito lentos. O gzip usou 100% da CPU em que foi executado (e executou 1,81 instruções por clock, de acordo com perf) e tailusou 0,162 da CPU em que foi executado (0,58 IPC). Caso contrário, o sistema estava ocioso.

    Estou usando o Linux 4.14.11-1-ARCH, que tem o KPTI ativado por padrão para contornar o Meltdown, então todas essas writechamadas de sistema gzipsão mais caras do que costumavam ser :/


    Ter o seek embutido em unzipou (mas ainda usando a função de decodificação zcatregularzlib ) salvaria todas as gravações de pipe e faria com que as CPUs Skylake rodassem na velocidade máxima do clock. (Esse downclock para alguns tipos de carga é exclusivo do Intel Skylake e posteriores, que descarregaram a tomada de decisão de frequência da CPU do sistema operacional, porque eles têm mais dados sobre o que a CPU está fazendo e podem aumentar / diminuir mais rapidamente. Isso é normalmente bom, mas aqui faz com que o Skylake não atinja a velocidade máxima com uma configuração de regulador mais conservadora).

    Nenhuma chamada do sistema, apenas reescrever um buffer que caiba no cache L2 até você atingir a posição inicial do byte desejada, provavelmente faria pelo menos alguns % de diferença. Talvez até 10%, mas estou apenas inventando números aqui. Não criei zlibum perfil detalhado para ver o tamanho da pegada de cache que ele tem e quanto a liberação de TLB (e, portanto, liberação de cache uop) em cada chamada do sistema dói com o KPTI ativado.


    Existem alguns projetos de software que adicionam um índice de busca ao formato de arquivo gzip . Isso não ajuda se você não conseguir que ninguém gere arquivos compactados pesquisáveis ​​para você, mas outros leitores futuros podem se beneficiar.

    Presumivelmente, nenhum desses projetos possui uma função de decodificação que saiba como pular um fluxo Deflate sem um índice, porque eles foram projetados para funcionar apenas quando um índice estiver disponível.

    • GZinga: Gzip pesquisável e divisível . Permite grandes tamanhos de bloco.
    • BGZF - GZIP bloqueado, maior e melhor! (pequeno tamanho máximo do bloco = 64kiB prejudica um pouco as taxas de compactação. Projetado para uso com dados de bioinformática, como FASTA, que geralmente são usados ​​sem compactação, com suporte transparente em algumas bibliotecas python.)
    • 3
  6. Steve Barnes
    2018-01-13T10:41:36+08:002018-01-13T10:41:36+08:00

    Você pode abrir o arquivo zip em uma sessão python, usando zf = zipfile.ZipFile(filename, 'r', allowZip64=True)e uma vez aberto você pode abrir, para leitura, qualquer arquivo dentro do arquivo zip e ler linhas, etc., dele como se fosse um arquivo normal.

    • 1

relate perguntas

  • Grep para um conjunto de linhas de $START a $END AND que contém uma correspondência em $MIDDLE

  • Reorganize as letras e compare duas palavras

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Embaralhamento de arquivo de várias linhas

  • como posso alterar o caso do caractere (de baixo para cima e vice-versa)? ao mesmo tempo [duplicado]

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve