Editando as primeiras / últimas linhas de um arquivo de texto de 1GB + no Windows sem carregar o arquivo inteiro na memória

3

Eu tenho alguns arquivos de dados de texto plano ("CSV") com tamanhos de até 3 GB e simplesmente preciso remover as primeiras 3 linhas de texto e adicionar uma linha vazia no final. Como tenho muitos desses arquivos, gostaria de encontrar uma maneira rápida de fazer isso.

O problema com essas primeiras linhas é que elas não são dados CSV, mas texto aleatório que não segue o formato da coluna. Devido a isso, a instrução Bulk Insert do SQL Server não pode processar esses arquivos.

Uma opção seria usar um script do PowerShell, mas o uso de Get-content ou de streams sempre envolveria a leitura do arquivo inteiro e a saída completa dele novamente. Existe uma maneira de modificar diretamente o arquivo no disco, sem carregá-lo totalmente na memória e recriar o arquivo?

De preferência, estou procurando uma maneira do PowerShell de fazer isso. Embora ferramentas de terceiros também possam ser interessantes ...

    
por Wouter 01.12.2016 / 15:50

3 respostas

3

Eu acho que não há como não ler todo o arquivo na memória, pelo menos eu não conheço nenhum.

$csv = gci "C:\location" -filter *.csv | % { 
    (Get-Content $_.FullName | select -skip 3) | Set-Content $_.FullName 
    Add-Content -path $_.FullName -value ""
}

Esta seria uma solução do PowerShell que requer o carregamento de todo o arquivo na memória.

  • pesquise todos os csv de um local com gci ,
  • execute o loop sobre os arquivos csv encontrados com foreach alias % ,
  • obtenha todo o conteúdo (pode levar algum tempo) com get-content
  • selecione tudo, mas pule as 3 primeiras linhas select -skip
  • e defina esse conteúdo para o arquivo com set-content .
  • a última linha adicionará uma nova linha ao arquivo add-content

Editar: Você pode tentar agilizar tudo isso adicionando o -ReadCount Parameter à sua chamada get-content .

-ReadCount (int)

Specifies how many lines of content are sent through the pipeline at a time. The default value is 1. A value of 0 (zero) sends all of the content at one time.

This parameter does not change the content displayed, but it does affect the time it takes to display the content. As the value of ReadCount increases, the time it takes to return the first line increases, but the total time for the operation decreases. This can make a perceptible difference in very large items.

Edit2: testei get-content com readcount . infelizmente eu não consegui encontrar um arquivo de texto maior que 89mb. mas a diferença já é significativa:

PS C:\Windows\System32> Measure-Command { gc "C:\Pub.log" -readcount 0 }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 1
Milliseconds      : 22
Ticks             : 10224578
TotalDays         : 1.18340023148148E-05
TotalHours        : 0.000284016055555556
TotalMinutes      : 0.0170409633333333
TotalSeconds      : 1.0224578
TotalMilliseconds : 1022.4578




PS C:\Windows\System32> Measure-Command { gc "C:\Pub.log" -readcount 1 }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 10
Milliseconds      : 594
Ticks             : 105949457
TotalDays         : 0.000122626686342593
TotalHours        : 0.00294304047222222
TotalMinutes      : 0.176582428333333
TotalSeconds      : 10.5949457
TotalMilliseconds : 10594.9457

então get-content $_.FullName -readcount 0 é o caminho a percorrer

    
por 02.12.2016 / 09:17
2

A remoção de conteúdo do início de um arquivo requer a regravação do arquivo.

Você pode usar tail -n +4 input.csv > output.csv para remover as três primeiras linhas (requer 105 segundos para um dump de 15 GB da Wikipedia no meu servidor de baixo custo, ou seja, cerca de 150 MB por segundo). No Windows tail está disponível com o Cygwin, por exemplo

    
por 01.12.2016 / 21:10
0

Depois de cavar um pouco mais, acho que esta pergunta se resume ao seguinte:

Is there a way to edit a file on a HDD formatted using NTFS, directly, in-place?

Minha resposta seria que pequenas alterações poderiam ser feitas usando editores Hex que fizessem alterações diretas no nível do disco rígido, mas fazer grandes mudanças como remover partes inteiras do arquivo provavelmente corromperia o sistema de arquivos. Então a questão novamente, resume-se a:

Does NTFS support editing data-blocks assigned to a file without rewriting the entire file?

Meu palpite será ... não. Mas eu estaria interessado em aprender um pouco mais sobre os detalhes disso ...

    
por 01.12.2016 / 16:19