web-dev-qa-db-ja.com

ファイル全体をメモリにロードせずに、Windowsで1GB以上のテキストファイルの最初/最後の行を編集する

最大3GBのサイズのフラットテキストデータファイル(「CSV」)がいくつかあり、テキストの最初の3行を削除して、最後に空の行を追加する必要があります。私はこれらのファイルをたくさん持っているので、これを行うための迅速な方法を見つけたいと思います。

これらの最初の行の問題は、CSVデータではなく、列形式に従わないランダムなテキストであるということです。このため、SQLServerの一括挿入ステートメントはこれらのファイルを処理できません。

1つのオプションは、PowerShellスクリプトを使用することですが、Get-contentまたはstreamsを使用するには、常にファイル全体を読み取り、完全に再度出力する必要があります。ファイルを完全にメモリにロードしてファイルを再作成せずに、ディスク上のファイルを直接変更する方法はありますか?

できれば、これを行うPowerShellの方法を探しています。サードパーティのツールも面白いかもしれませんが...

3
Wouter

ファイルの先頭からコンテンツを削除するには、ファイルを書き換える必要があります。

tail -n +4 input.csv > output.csvを使用して、最初の3行を削除できます(ローエンドサーバーで15 GBのWikipediaダンプを作成するには105秒かかります。つまり、1秒あたり約150 MBです)。 Windowsでは、tailはCygwinで使用できます。

3
aventurin

メモリ内のファイル全体を読み取らない方法はないと思いますが、少なくとも私にはわかりません。

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

これは、ファイル全体をメモリにロードする必要があるPowerShellソリューションになります。

  • gciの場所からすべてのcsvを検索します。
  • 見つかったcsvファイルをforeachエイリアス%でループし、
  • get-contentを使用して、コンテンツ全体を取得します(時間がかかる場合があります)。
  • すべてを選択しますが、最初の3行をスキップしますselect -skip
  • そのコンテンツをset-contentでファイルに設定します。
  • 最後の行はファイルに新しい行を追加しますadd-content

編集:-ReadCountパラメータをget-content呼び出しに追加することで、この全体をより速くすることができます。

-ReadCount(int)

パイプラインを介して一度に送信されるコンテンツの行数を指定します。デフォルト値は1です。値0(ゼロ)は、すべてのコンテンツを一度に送信します。

このパラメーターは表示されるコンテンツを変更しませんが、コンテンツの表示にかかる時間には影響します。 ReadCountの値が大きくなると、最初の行を返すのにかかる時間は長くなりますが、操作の合計時間は短くなります。これにより、非常に大きなアイテムに知覚可能な違いが生じる可能性があります。

Edit2:get-contentreadcountでテストしました。残念ながら、89MBを超えるテキストファイルが見つかりませんでした。しかし、その違いはすでに重要です。

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

だからget-content $_.FullName -readcount 0は行く方法です

2
SimonS

もう少し深く掘り下げた後、私はこの質問が要約すると次のようになると思います:

NTFSを使用してフォーマットされたHDD上のファイルを直接インプレースで編集する方法はありますか?

私の答えは、ハードドライブレベルで直接変更を行う16進エディターを使用して小さな変更を加えることができるということですが、ファイルの一部全体を削除するなどの大きな変更を行うと、ファイルシステムが破損する可能性があります。したがって、質問は次のように要約されます。

NTFSは、ファイル全体を書き換えることなく、ファイルに割り当てられたデータブロックの編集をサポートしていますか?

私の推測は...いいえ。しかし、私はこれの詳細についてもう少し学びたいと思います...

0
Wouter