【问题标题】:How to do a copy /b in a powershell script to insert a BOM marker, but as a batch for files that match a filter and changes the ext on output?如何在powershell脚本中复制/ b以插入BOM标记,但作为与过滤器匹配并更改输出的ext文件的批处理?
【发布时间】:2026-01-12 14:00:01
【问题描述】:

这不是重复的原因

既然已经有 3 人投票结束,我想我应该解释一下为什么这个问题不是重复的:

  1. 我不能使用 cat 或 >>,因为它们会弄乱文件的编码,输入时为 UTF8,输出时需要为 UTF8-BOM。

  2. 链接的问题没有显示如何遍历目录中与给定模式匹配的所有文件,并将单个文件连接到输出中的每个匹配文件,并为新文件提供不同的扩展名。

  3. 使用 Set-Content 不是 Powershell 6 的未来证明,因为 Set-Content 不会添加 BOM 标记。在 Powershell 5 及更低版本中,有时会添加 BOM 标记,有时不会添加,具体取决于执行用户的配置设置。请参阅this article 末尾的“编码快速说明”。

因此,总而言之,我正在寻找一种使用副本(因此是问题标题)且不使用 Cat 或 Set-Content 的解决方案。


我需要遍历给定目录中的某些文件并在每个文件上运行以下命令:

copy /b BOMMarker.txt+InputFile.dat OutputFile.txt

这会在InputFile.dat 的开头插入BOMMarker.txt 文件的内容并将输出写入OutputFile.txt

我找到了this question,它解释了如何遍历文件夹以将每个文件加载到 Powershell 中,但是如何应用“复制 /b”命令以便在每个文件的开头获取 BOM 标记?

编辑

Jeroen 的评论表明我可以对输出文件执行 Set-Content,因为 Powershell 会在开始时自动添加 BOM。

但我还需要更改扩展名。因此输出文件名需要与输入文件名相同,只是扩展名有所改变(从 .dat 到 .txt)并包括 BOM。

我猜我可以使用 Path.ChangeExtension 以某种方式执行此操作,但不确定如何将其与添加 BOM 结合起来。

编辑 - 赏金

我发布的示例答案在我测试它的所有环境中都不起作用,我不知道为什么(可能不同的默认 Powershell 设置)而且,它不是未来的证明,因为 Powershell 6 将not output BOM by default

从给定目录中,我需要处理与过滤器匹配的所有文件 (DIL_BG_TXN*.dat)。

对于这些文件中的每一个,我需要在开始时使用 BOM 复制它,但生成的新文件需要具有相同的名称,但扩展名为 .txt 而不是 .dat。

【问题讨论】:

  • 如果您想为每个文件添加 BOM 标记,而不是像这样连接文件,您可能需要使用Set-Content OutputFile.txt (Get-Content InputFile.txt) -Encoding UTF8(或UTF16)。默认情况下,PowerShell 恰好添加了 BOM,因此您不需要cmd 的通常扭曲。
  • @JeroenMostert 谢谢,请将其作为答案发布,我会接受。
  • “但我还需要更改扩展名。” 可能只是Set-Content OutputFile.txt (Get-Content InputFile.dat) -Encoding UTF8

标签: powershell


【解决方案1】:

此解决方案使用流,可以按原样可靠地读写:

$bomStream = [IO.File]::OpenRead('BOMMarker.txt')
$location = "" # set this to the folder location

$items = Get-ChildItem -Path $location -Filter DIL_BG_TXN*.dat

foreach ($item in $items) {
    $sourceStream = [IO.File]::OpenRead($item.FullName)
    $targetStream = [IO.File]::OpenWrite([IO.Path]::ChangeExtension($item.FullName, '.txt'))
    $bomStream.CopyTo($targetStream)
    $sourceStream.CopyTo($targetStream)
    $targetStream.Flush()
    $targetStream.Close()
    $sourceStream.Close()
    $bomStream.Position = 0
}
$bomStream.Close()

当然请根据位置写出BOMMarker.txt(第一行)的绝对路径。

【讨论】:

    【解决方案2】:

    这终于奏效了:

    $Location = "C:\Code\Bulgaria_Test"
    
    $items = Get-ChildItem -Path $Location -Filter DIL_BG_TXN*.dat
    
    ForEach ($item in $items) {
    
        Write-Host "Processing file - " $item
    
        cmd /c copy /b BOMMarker.txt+$item ($item.BaseName + '.txt')
    
    }
    

    说明:

    1. 设置所有 .dat 文件所在的目录位置。

    2. 仅将那些与过滤器匹配的文件加载到数组 $items 中。

    3. 遍历数组中的每个 $item。

    4. 对于每个 $item,使用 copy /b 命令调用 cmd shell,并将 bom 标记文件与 $item 文件连接起来,并将结果写入 $item 的基本名称加上新的扩展名。

    【讨论】:

      最近更新 更多