使用PowerShell以UTF-8编写文件而不使用BOM

M. *_*ley 225 powershell encoding byte-order-mark utf-8

Out-File 似乎在使用UTF-8时强制BOM:

$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
Run Code Online (Sandbox Code Playgroud)

如何使用PowerShell以UTF-8编写没有BOM的文件?

M. *_*ley 208

使用.NET的UTF8Encoding类并传递$False给构造函数似乎工作:

$MyFile = Get-Content $MyPath
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[System.IO.File]::WriteAllLines($MyPath, $MyFile, $Utf8NoBomEncoding)
Run Code Online (Sandbox Code Playgroud)

  • 一行`[System.IO.File] :: WriteAllLines($ MyPath,$ MyFile)就足够了.这个`WriteAllLines`重载完全写入没有BOM的UTF8. (110认同)
  • 呃,我希望这不是唯一的方法. (32认同)
  • @xdhmoore`WriteAllLines`从`[System.Environment] :: CurrentDirectory`获取当前目录.如果你打开PowerShell然后更改当前目录(使用`cd`或`Set-Location`),那么`[System.Environment] :: CurrentDirectory`将不会被更改,文件将最终出现在错误的目录中.你可以通过`[System.Environment] :: CurrentDirectory =(Get-Location).Path`来解决这个问题. (8认同)
  • 在此处创建了MSDN功能请求:https://connect.microsoft.com/PowerShell/feedbackdetail/view/1137121/add-nobom-flag-to-out-file (6认同)
  • 请注意,`WriteAllLines`似乎要求`$ MyPath`是绝对的. (3认同)
  • 如果你不想在文件末尾多出一行,你可以这样做:`[IO.File]::WriteAllText($MyPath, $MyFile)`。 (3认同)
  • 正如 @RosbergLinhares 所指出的,“WriteAllLines”在文件末尾添加了一个额外的新行。但是要使“WriteAllText”工作,您必须为“Get-Content”使用“-Raw”参数,否则所有文本将被压缩成一行。`$fileContent = Get-Content -Raw "$fileFullName"; [System.IO.File]::WriteAllText($fileFullName, $fileContent)` (2认同)

For*_*VeR 71

目前正确的方法是使用@Roman Kuzmin推荐的解决方案给@M 发表评论.达德利回答:

[IO.File]::WriteAllLines($filename, $content)
Run Code Online (Sandbox Code Playgroud)

(我还通过删除不必要的System命名空间澄清来缩短它- 它将默认自动替换.)

  • 这(无论出于何种原因)并没有为我删除 BOM,而接受的答案是 (2认同)
  • 我相信旧版本的 .NET WriteAllLines 函数确实默认写入了 BOM。所以这可能是版本问题。 (2认同)
  • 在Powershell 3中使用BOM写入确认,但在Powershell 4中没有BOM.我不得不使用M. Dudley的原始答案. (2认同)
  • 所以它适用于Windows 10,默认安装它.:)另外,建议改进:`[IO.File] :: WriteAllLines(($ filename | Resolve-Path),$ content)` (2认同)

Len*_*nny 44

我认为这不是UTF,但我发现了一个非常简单的解决方案似乎有效......

Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext
Run Code Online (Sandbox Code Playgroud)

对我来说,无论源格式如何,都会产生没有bom文件的utf-8.

  • 是的,`-Encoding ASCII`避免了BOM问题,但显然你只能获得_7位ASCII字符_.鉴于ASCII是UTF-8的子集,结果文件在技术上也是一个有效的UTF-8文件,但输入中的所有非ASCII字符都将转换为文字`?`characters_. (35认同)
  • **警告:**绝对不是。这将删除所有非 ASCII 字符并将其替换为问号。不要这样做,否则您将丢失数据!(在 Windows 10 上尝试使用 PS 5.1) (11认同)
  • 这对我有用,除了我使用`-encoding utf8`来满足我的要求. (7认同)
  • 10000% 同意@ygoe。应避免使用此解决方案。这里有更好的答案,例如已接受的答案 - 当然,新版本的 x-plat PowerShell 默认情况下不使用 BOM;但对于使用桌面版的用户,请参阅已接受的答案。 (2认同)

mkl*_*nt0 28

注意:此答案适用于Windows PowerShell ; 相比之下,在跨平台的PowerShell 核心版中,没有BOM的 UTF-8 是默认编码.

为了补充M. Dudley自己简单实用的答案(以及ForNeVeR更简洁的重新制定):

为方便起见,这里是高级功能Out-FileUtf8NoBom,一种模仿的基于管道的替代方案Out-File,这意味着:

  • 你可以像Out-File在管道中一样使用它.
  • 非字符串的输入对象的格式与将它们发送到控制台时的格式相同,就像使用它一样Out-File.

例:

(Get-Content $MyPath) | Out-FileUtf8NoBom $MyPath
Run Code Online (Sandbox Code Playgroud)

请注意如何(Get-Content $MyPath)包含(...),这可确保在通过管道发送结果之前打开整个文件,完整读取和关闭.这是必要的,以便能够回写到同一个文件(在适当的位置更新).
但是,一般情况下,这种技术不建议有两个原因:(a)整个文件必须适合内存;(b)如果命令中断,数据将丢失.

关于内存使用的说明:

  • M. Dudley自己的回答要求首先在内存中构建整个文件内容,这对于大文件来说可能会有问题.
  • 下面的函数仅稍微改进了这一点:所有输入对象仍然首先被缓冲,但是它们的字符串表示然后被生成并逐个写入输出文件.

源代码Out-FileUtf8NoBom(也可作为MIT授权的Gist提供):

<#
.SYNOPSIS
  Outputs to a UTF-8-encoded file *without a BOM* (byte-order mark).

.DESCRIPTION
  Mimics the most important aspects of Out-File:
  * Input objects are sent to Out-String first.
  * -Append allows you to append to an existing file, -NoClobber prevents
    overwriting of an existing file.
  * -Width allows you to specify the line width for the text representations
     of input objects that aren't strings.
  However, it is not a complete implementation of all Out-String parameters:
  * Only a literal output path is supported, and only as a parameter.
  * -Force is not supported.

  Caveat: *All* pipeline input is buffered before writing output starts,
          but the string representations are generated and written to the target
          file one by one.

.NOTES
  The raison d'être for this advanced function is that, as of PowerShell v5,
  Out-File still lacks the ability to write UTF-8 files without a BOM:
  using -Encoding UTF8 invariably prepends a BOM.

#>
function Out-FileUtf8NoBom {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory, Position=0)] [string] $LiteralPath,
    [switch] $Append,
    [switch] $NoClobber,
    [AllowNull()] [int] $Width,
    [Parameter(ValueFromPipeline)] $InputObject
  )

  #requires -version 3

  # Make sure that the .NET framework sees the same working dir. as PS
  # and resolve the input path to a full path.
  [System.IO.Directory]::SetCurrentDirectory($PWD) # Caveat: .NET Core doesn't support [Environment]::CurrentDirectory
  $LiteralPath = [IO.Path]::GetFullPath($LiteralPath)

  # If -NoClobber was specified, throw an exception if the target file already
  # exists.
  if ($NoClobber -and (Test-Path $LiteralPath)) {
    Throw [IO.IOException] "The file '$LiteralPath' already exists."
  }

  # Create a StreamWriter object.
  # Note that we take advantage of the fact that the StreamWriter class by default:
  # - uses UTF-8 encoding
  # - without a BOM.
  $sw = New-Object IO.StreamWriter $LiteralPath, $Append

  $htOutStringArgs = @{}
  if ($Width) {
    $htOutStringArgs += @{ Width = $Width }
  }

  # Note: By not using begin / process / end blocks, we're effectively running
  #       in the end block, which means that all pipeline input has already
  #       been collected in automatic variable $Input.
  #       We must use this approach, because using | Out-String individually
  #       in each iteration of a process block would format each input object
  #       with an indvidual header.
  try {
    $Input | Out-String -Stream @htOutStringArgs | % { $sw.WriteLine($_) }
  } finally {
    $sw.Dispose()
  }

}
Run Code Online (Sandbox Code Playgroud)

  • @nhooyr,最好使用 `$null = New-Item -Force $MyPath -Value (Get-Content -Raw $MyPath)` (更快,并保留现有的换行格式) - 我已经更新了答案。 (2认同)

sc9*_*911 13

从开始第6版 PowerShell支持UTF8NoBOM的编码都设置内容出文件,甚至以此为默认的编码。

因此,在上面的示例中,它应该像这样:

$MyFile | Out-File -Encoding UTF8NoBOM $MyPath
Run Code Online (Sandbox Code Playgroud)

  • 好的。仅供参考,使用“$PSVersionTable.PSVersion”检查版本 (2认同)

Luc*_*ero 9

使用Set-ContentOut-File,可以指定编码Byte,可用于将字节数组写入文件.这与不发出BOM的自定义UTF8编码相结合,可以得到所需的结果:

# This variable can be reused
$utf8 = New-Object System.Text.UTF8Encoding $false

$MyFile = Get-Content $MyPath -Raw
Set-Content -Value $utf8.GetBytes($MyFile) -Encoding Byte -Path $MyPath
Run Code Online (Sandbox Code Playgroud)

使用[IO.File]::WriteAllLines()或类似的区别在于它应该适用于任何类型的项目和路径,而不仅仅是实际的文件路径.


And*_*ich 7

重要!:仅当开头的额外空格或换行符对于您的文件用例没有问题时才有效
(例如,如果它是 SQL 文件、Java 文件或人类可读的文本文件)

可以使用创建空(非 UTF8 或 ASCII(UTF8 兼容))文件并向其追加内容的组合(如果源是文件,则替换$str为):gc $src

" "    |  out-file  -encoding ASCII  -noNewline  $dest
$str  |  out-file  -encoding UTF8   -append     $dest
Run Code Online (Sandbox Code Playgroud)

作为单行

根据您的用例替换$dest和:$str

$_ofdst = $dest ; " " | out-file -encoding ASCII -noNewline $_ofdst ; $src | out-file -encoding UTF8 -append $_ofdst
Run Code Online (Sandbox Code Playgroud)

作为简单的函数

function Out-File-UTF8-noBOM { param( $str, $dest )
  " "    |  out-file  -encoding ASCII  -noNewline  $dest
  $str  |  out-file  -encoding UTF8   -append     $dest
}
Run Code Online (Sandbox Code Playgroud)

将其与源文件一起使用:

Out-File-UTF8-noBOM  (gc $src),  $dest
Run Code Online (Sandbox Code Playgroud)

将其与字符串一起使用:

Out-File-UTF8-noBOM  $str,  $dest
Run Code Online (Sandbox Code Playgroud)


jam*_*han 6

该脚本会将 DIRECTORY1 中的所有 .txt 文件转换为无 BOM 的 UTF-8,并将其输出到 DIRECTORY2

foreach ($i in ls -name DIRECTORY1\*.txt)
{
    $file_content = Get-Content "DIRECTORY1\$i";
    [System.IO.File]::WriteAllLines("DIRECTORY2\$i", $file_content);
}
Run Code Online (Sandbox Code Playgroud)

  • WriteAllLines 解决方案非常适合小文件。但是,我需要一个针对较大文件的解决方案。每次我尝试将其与较大的文件一起使用时,我都会收到 OutOfMemory 错误。 (5认同)

Jen*_*nsG 6

老问题,新答案:

虽然“旧”powershell 写入 BOM,但新的与平台无关的变体的行为有所不同:默认为“无 BOM”,可以通过开关进行配置:

-编码

指定目标文件的编码类型。默认值为 utf8NoBOM。

该参数可接受的值如下:

  • ascii:使用 ASCII(7 位)字符集的编码。
  • bigendianunicode:使用 big-endian 字节顺序以 UTF-16 格式进行编码。
  • oem:使用 MS-DOS 和控制台程序的默认编码。
  • unicode:使用小端字节顺序以 UTF-16 格式进行编码。
  • utf7:以 UTF-7 格式编码。
  • utf8:以 UTF-8 格式编码。
  • utf8BOM:使用字节顺序标记 (BOM) 以 UTF-8 格式进行编码
  • utf8NoBOM:以 UTF-8 格式编码,不带字节顺序标记 (BOM)
  • utf32:以 UTF-32 格式编码。

来源: https: //learn.microsoft.com/de-de/powershell/module/Microsoft.PowerShell.Utility/Out-File ?view=powershell-7 重点是我的