将文件转换为UTF-8编码:Get-Content:抛出了类型为“System.OutOfMemoryException”的异常。

4

我正在尝试将包含日语字符的大型dat文件转换为UTF-8格式,以便将它们加载到数据库中。最大的文件大小为17 GB,整个目录大小为34 GB。以下是我的PowerShell脚本。

$files = Get-ChildItem 'E:\datamig_bkp_SCMDB\data\bigfiles' -Recurse |
         ? {Test-Path $_.FullName -PathType Leaf}
foreach ($file in $files) {
    $content = Get-Content $file.FullName
    $content | Out-File $file.FullName -Encoding UTF8
}

我遇到以下错误:

Get-Content: 抛出了“System.OutOfMemoryException”类型的异常。
在第3行第16个字符处:
+     $content = Get-Content $file.FullName
+                ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : 无效操作: (:) [Get-Content],OutOfMemoryException
    + FullyQualifiedErrorId : ProviderContentReadError,Microsoft.PowerShell.Commands.GetContentCommand
1个回答

5
不要将大文件读入内存。将输出写入新的(临时)文件,然后删除原始文件并将临时文件移动到其位置。
$tmp = 'C:\path\to\temp.txt'
Get-ChildItem 'E:\datamig_bkp_SCMDB\data\bigfiles' -Recurse | Where-Object {
    -not $_.PSIsContainer
} | ForEach-Object {
    $file = $_.FullName
    Get-Content $file | Out-File $tmp -Encoding UTF8
    Remove-Item $file -Force
    Move-Item $tmp $file
}

正如评论中TheIncorrigible1所指出的那样,如果您使用PowerShell v3或更新版本,则可以简化代码:
$tmp = 'C:\path\to\temp.txt'
Get-ChildItem 'E:\datamig_bkp_SCMDB\data\bigfiles' -Recurse -File | ForEach-Object {
    $file = $_.FullName
    Get-Content $file | Out-File $tmp -Encoding UTF8
    Remove-Item $file -Force
    Move-Item $tmp $file
}

不要使用 Where-Object,使用 -File 开关更易读。您还可以将 FileInfo 对象直接传递到 Get-Content - Maximilian Burszley
@TheIncorrigible1 参数-File是在PowerShell v3中引入的。我更喜欢保持向后兼容性,因此我倾向于避免较新的功能,除非问题说明用户正在运行足够新的版本。至于将文件对象传递到Get-Content中:我没有看到优势,因为每个文件应该单独处理,并且移动临时文件后删除原始文件需要完整路径。我不确定FileInfo对象中的信息是否会在删除文件后保留,因此我采取了安全的方法。 - Ansgar Wiechers
在我看来,使用管道而不是使用位置参数只会使代码更具可读性。 FileInfo对象在项本身被删除后仍保留为FYI。 $_ | Get-Content | Out-File -FilePath $tmp -Encoding utf8 等等。 - Maximilian Burszley
我并不反对可读性方面的观点。尽管如此,我仍然强调兼容性,因为这样答案就能够服务更广泛的受众。 - Ansgar Wiechers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接