1

我正在使用 powershell 脚本将数据附加到一堆文件的末尾。每个文件是一个大约 50Mb 的 CSV(比如 2 百万行),大约有 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

当有 cmdlet 可以处理对象时,不要进入 .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 回答