替换巨大的 csv 文件的第一行

Replace the first line of a humongous csv file

替换 HUMONGOUS CSV 文件第一行的最有效方法是什么?我正在处理的文件大小接近 40gb。我目前正在读取 header 行,清理它,然后尝试将它写回到文件中。这是我目前在写回文件时在 powershell 中所做的:

Import-CSV $file -Header $newHeader | Select -Skip 1 | Export-CSV -Path $newFile -NoTypeInformation

我想知道是否有办法替换第一行,而无需将整个文件读入内存,然后将其写入新文件。

更新

我已使用以下内容将我的脚本修改为 read/write:

$sr = [System.IO.StreamReader] $inputFile
$sw = [System.IO.StreamWriter] $outputFile

#Get rid of the first row
$null = $sr.ReadLine()

$Header = #my new header
$sw.WriteLine($Header)
        
#Write the remainder of the old file to the new report file
while($line = $sr.ReadLine()) {
    $sw.WriteLine($line)
}

这最初是由 zett42 in his helpful comment 前段时间提出的,我认为在这种情况下这将是速度和内存效率之间的最佳平衡。概念是分块读写。

重要的是要了解这可能会带来编码问题,正如我在同一个链接答案中所解释的那样,您需要自己测试代码 as-is 是否有效正确或您需要更改编码(该答案中还解释了如何使用特定编码进行读写)。


使用 4kb 作为建议的缓冲区大小,基于这些优秀的答案:


using namespace System.IO
using namespace System.Text

try {
    $sr = [File]::OpenRead('absolute\path\to\input.csv')
    $sw = [File]::OpenWrite('absolute\path\to\output.csv')
    $buffer = [char[]]::new(4kb)
    $reader = [StreamReader]::new($sr, [Encoding]::UTF8, $true, $buffer.Length)
    $writer = [StreamWriter]::new($sw, [Encoding]::UTF8, $true, $buffer.Length)

    # ignore the first line (headers)
    $null = $reader.ReadLine()
    # define the new headers
    $header = '"ColumnA","ColumnB","ColumnC"'
    # and write them to the first line of our output file
    $writer.WriteLine($Header)

    # read the file in chunks of `$buffer` size
    while($len = $reader.Read($buffer)) {
        # write the output in chunks of `$buffer` size
        $writer.Write($buffer, 0, $len)
    }
}
finally {
    # flush and dispose the streams
    $writer.ForEach('Flush')
    ($reader, $writer, $sr, $sw).ForEach('Dispose')
}

您可以使用非常简单的脚本。不确定效率。但会起作用。这并没有被证明是最快的(但我的性能比其他命令好得多)。但它一次读取一行文件,因此极大地减少了内存使用量,从而可以完成任务。

$count =1
For each ($line in [system.io.file]::readlines()) {
    If ($count -eq 1) {
        $count++
        Continue
    }
    $line | Out-File c:\out.csv -Append 
}

您可以不断增加计数并每 1000 行保存一次,以防止过多的 Out-File 调用。这可能会对其进行一些优化。

如果您只是想删除第一行,notepad++ 之类的软件可能会部分打开它,这样您就可以编辑该行并保存文件。 (它不会打开整个文件,只在您要查找的地方加上几页)

另一种选择是使用 Linux。 Wsl 可能会工作。他们的文件编辑能力让 PowerShell 脱颖而出。

使用 awk 或 sed 等工具。或者也许只是获取行数并尾随文件的最后一个(长度 -1)。相信我。它很快。让我们这样说吧。 PowerShell 处理一个 150meg 的文件需要 15 分钟,Linux 在 2 或 3 秒内完成。