1

一連のファイルの末尾にデータを追加するために、powershell スクリプトを使用しています。各ファイルは約 50Mb (たとえば 200 万行) の CSV で、約 50 個のファイルがあります。

私が使用しているスクリプトは次のようになります。

$MyInvocation.MyCommand.path

$files = ls *.csv 

foreach($f in $files) 
{
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($f)
$year = $basename.substring(0,4)

Write-Host "Starting" $Basename

$r = [IO.File]::OpenText($f)
while ($r.Peek() -ge 0) {
    $line = $r.ReadLine()
    $line + "," + $year | Add-Content $(".\DR_" + $basename + ".CSV")
}
$r.Dispose()

}

問題は、かなり遅いことです。それらを通過するのに約12時間かかります。それほど複雑ではないので、実行にそれほど時間がかかるとは思いません。スピードアップするにはどうすればよいですか?

4

2 に答える 2

3

ファイルの行ごとの読み取りと書き込みは、少し遅くなる可能性があります。ウイルス対策も速度低下の原因になっている可能性があります。Measure-Commandスクリプトのどの部分が遅いかを確認するために使用します。

一般的なアドバイスとして、小さなブロックをたくさん書くのではなく、いくつかの大きなブロックを書くことをお勧めします。これを実現するには、一部のコンテンツを StringBuilder に格納し、そのコンテンツを、たとえば 1000 行の処理ごとに出力ファイルに追加します。そのようです、

$sb = new-object Text.StringBuilder # New String Builder for stuff
$i = 1 # Row counter
while ($r.Peek() -ge 0) {
    # Add formatted stuff into the buffer
    [void]$sb.Append($("{0},{1}{2}" -f $r.ReadLine(), $year, [Environment]::NewLine ) )

    if(++$i % 1000 -eq 0){ # When 1000 rows are added, dump contents into file
      Add-Content $(".\DR_" + $basename + ".CSV") $sb.ToString()
      $sb = new-object Text.StringBuilder # Reset the StringBuilder
    }
}
# Don't miss the tail of the contents
Add-Content $(".\DR_" + $basename + ".CSV") $sb.ToString()
于 2013-06-26T10:23:10.480 に答える
0

オブジェクトに対して作業を実行できるコマンドレットがある場合は、.NET Framework の静的メソッドや文字列の構築には踏み込まないでください。データを収集し、年の列を追加してから、新しいファイルにエクスポートします。また、大量のファイル I/O を実行しているため、速度も低下します。

これには、おそらくもう少し多くのメモリが必要になります。ただし、ファイル全体を一度に読み取り、ファイル全体を一度に書き込みます。また、CSV ファイルに列見出しがあることも前提としています。しかし、他の誰かが見て、何が起こっているのかを正確に理解する方がはるかに簡単です (スクリプトが読めるようにスクリプトを作成してください!)。

# Always use full cmdlet names in scripts, not aliases
$files = get-childitem *.csv;

foreach($f in $files) 
{
    #basename is a property of the file object in PowerShell, there's no need to call a static method
    $basename = $f.basename;
    $year = $f.basename.substring(0,4)

    # Every time you use Write-Host, a puppy dies
    "Starting $Basename";

    # If you've got CSV data, treat it as CSV data. PowerShell can import it into a collection natively.
    $data = Import-Csv $f;
    $exportData = @();
    foreach ($row in $data) {
# Add a year "property" to each row object
        $row |Add-Member -membertype NoteProperty -Name "Year" -Value $year;
# Export the modified row to the output file
        $row |Export-Csv -NoTypeInformation -Path $("r:\DR_" + $basename + ".CSV") -Append -NoClobber
    }
}
于 2013-06-26T13:15:20.030 に答える