Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用PowerShell将大型csv的\x00(ASCII 0,NUL)替换为空字符串_Powershell - Fatal编程技术网

使用PowerShell将大型csv的\x00(ASCII 0,NUL)替换为空字符串

使用PowerShell将大型csv的\x00(ASCII 0,NUL)替换为空字符串,powershell,Powershell,我有这样的代码,就像一个小文件的魅力。它只是将整个文件转储到内存中,替换NUL并写回同一个文件。当文件大小大于可用内存时,这对于大型文件来说并不是很实用。有人能帮我把它转换成流媒体模式,这样它就不会被大文件阻塞 Get-ChildItem -Path "Drive:\my\folder\path" -Depth 2 -Filter *.csv | Foreach-Object { $content = Get-Content $_.FullName #Replace NUL

我有这样的代码,就像一个小文件的魅力。它只是将整个文件转储到内存中,替换NUL并写回同一个文件。当文件大小大于可用内存时,这对于大型文件来说并不是很实用。有人能帮我把它转换成流媒体模式,这样它就不会被大文件阻塞

Get-ChildItem -Path "Drive:\my\folder\path" -Depth 2 -Filter *.csv | 
Foreach-Object {
$content = Get-Content $_.FullName
#Replace NUL and save content back to the original file
$content -replace "`0","" | Set-Content $_.FullName
}

按照这种结构化方式,必须将整个文件内容读入内存。注意:将文件读入内存会使用RAM中文件大小的3-4倍,这是有文档记录的

如果不进入.Net类,尤其是
[System.IO.StreamReader]
获取内容实际上非常节省内存,您只需利用管道,就不会在内存中构建数据

注意:如果您决定尝试
StreamReader
,本文将为您提供一些语法线索。此外,网络上的许多其他人也谈到了这个话题

Get-ChildItem -Path "C:\temp" -Depth 2 -Filter *.csv | 
ForEach-Object{
    $CurrentFile = $_
    $TmpFilePath = Join-Path $CurrentFile.Directory.FullName ($CurrentFile.BaseName + "_New" + $CurrentFile.Extension)
    
    Get-Content $CurrentFile.FullName |
    ForEach-Object{ $_ -replace "`0","" } |
    Add-Content $TmpFilePath 

    # Now that you've got the new file you can rename it & delete the original:
    Remove-Item -Path $CurrentFile.FullName
    Rename-Item -Path $TmpFilePath -NewName $CurrentFile.Name
} 
这是一个流模型,
Get Content
在外部
ForEach对象
循环内流。可能还有其他的方法,但我选择了这个,这样我就可以跟踪名称并在最后进行文件交换

注意:根据同一篇文章,就速度而言,
Get Content
相当慢。然而,您的原始代码可能已经承受了这种负担。此外,您可以使用
-ReadCount XXXX
参数将其加速一点。这将一次向管道输送一些管线。这当然会占用更多内存,因此您必须在可用RAM的范围内找到一个级别来帮助您说话。注释中提到了使用
-ReadCount
提高性能

根据评论更新:

下面是一个使用StreamReader/Writer执行与上一个示例相同的操作的示例。这应该和
获取内容
一样节省内存,但应该快得多

Get-ChildItem -Path "C:\temp" -Depth 2 -Filter *.csv | 
ForEach-Object{
    $CurrentFile = $_.FullName
    $CurrentName = $_.Name
    $TmpFilePath = Join-Path $_.Directory.FullName ($_.BaseName + "_New" + $_.Extension)
    
    $StreamReader = [System.IO.StreamReader]::new( $CurrentFile )
    $StreamWriter = [System.IO.StreamWriter]::new( $TmpFilePath )

    While( !$StreamReader.EndOfStream )
    {
        $StreamWriter.WriteLine( ($StreamReader.ReadLine() -replace "`0","") )
    }
    
    $StreamReader.Close()
    $StreamWriter.Close()

    # Now that you've got the new file you can rename it & delete the original:
    Remove-Item -Path $CurrentFile
    Rename-Item -Path $TmpFilePath -NewName $CurrentName
} 
注意:我觉得这个问题的根源在于编码。流构造函数确实接受编码枚举作为参数

可用编码:

[System.Text.Encoding]::BigEndianUnicode
[System.Text.Encoding]::Default
[System.Text.Encoding]::Unicode
[System.Text.Encoding]::UTF32
[System.Text.Encoding]::UTF7
[System.Text.Encoding]::UTF8
因此,如果您想使用UTF8实例化流:

    $StreamReader = [System.IO.StreamReader]::new( $CurrentFile, [System.Text.Encoding]::UTF8 )
    $StreamWriter = [System.IO.StreamWriter]::new( $TmpFilePath, [System.Text.Encoding]::UTF8 )

这些流默认为UTF8。我认为系统默认值通常是代码页Windows 1251。

这是使用最少内存(每次一行)访问另一个文件的最简单方法。但它需要两倍的磁盘空间

get-content file.txt | % { $_ -replace "`0" } | set-content file2.txt 

到目前为止,您进行了哪些研究工作?替换模式如何?您正在逃离0。如果您的目的是替换零,那么它可能不起作用。让我知道,我会相应地更新我的答案。@powershell中的steven backtick0是CSV文件中的ASCII 0/NUL字符,我正试图用空字符串替换它。我刚刚想到了这一点,但尝试匹配
\0
可能是更好的做法。我知道其他的正则表达式的味道会和NUL相匹配。PowerShell中的典型建议是对诸如
-replace
-split
之类的运算符使用正则表达式元字符。感谢您的回复。我将探索StreamReader,因为这似乎是非常大的文件前进的正确途径> = 50GbNO压力,我只指出,因为你是一个新的贡献者,但如果这个答案帮助你找到一个解决方案,如果你喜欢它考虑标记它使用左边的复选标记。抱歉是关键的,但我认为(我的答案)[中包含了这一点。我介绍了其他步骤,如重命名文件,以及使用流的替代方法。