[encoding] PowerShell을 사용하여 BOM없이 UTF-8로 파일 작성

Out-File UTF-8을 사용할 때 BOM을 강제하는 것 같습니다.

$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath

PowerShell을 사용하여 BOM없이 UTF-8로 파일을 작성하려면 어떻게해야합니까?



답변

.NET UTF8Encoding클래스를 사용 $False하고 생성자에 전달 하면 작동하는 것 같습니다.

$MyRawString = Get-Content -Raw $MyPath
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[System.IO.File]::WriteAllLines($MyPath, $MyRawString, $Utf8NoBomEncoding)


답변

현재 올바른 방법은 @Roman Kuzmin이 권장하는 솔루션을 @M 에 대한 의견으로 사용 하는 것입니다. 더들리 답변 :

[IO.File]::WriteAllLines($filename, $content)

(또한 불필요한 System네임 스페이스 설명 을 제거하여 약간 줄 였습니다. 기본적으로 자동으로 대체됩니다.)


답변

나는 이것이 UTF-8이 아니라고 생각했지만 작동하는 것처럼 보이는 매우 간단한 해결책을 찾았습니다 …

Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext

나에게 이것은 소스 형식에 관계없이 bom 파일이없는 utf-8이됩니다.


답변

참고 :이 답변 Windows PowerShell에 적용됩니다 . 반대로 크로스 플랫폼 PowerShell Core 버전 (v6 +)에서 BOM없는 UTF-8 은 모든 cmdlet 에서 기본 인코딩 입니다.
즉 : 당신이 사용하는 경우 PowerShell을 [코어] 버전 6 이상을 , 당신의 get BOM없는 UTF-8 파일을 기본적으로 (당신이 명시 적으로 요청할 수 있습니다 -Encoding utf8/ -Encoding utf8NoBOM당신이 얻을 수있는 반면 와 -BOM 인코딩 -utf8BOM).


M. Dudley의 간단하고 실용적인 답변 을 보완하기 위해 (그리고 ForNeVeR의 더 간결한 개혁 ) :

편의를 위해, 여기에 고급 기능의 Out-FileUtf8NoBom, 모방하는 파이프 라인 기반의 대체Out-File 수단 :

  • 당신은 그것을 그대로 사용할 수 있습니다 Out-File파이프 라인 .
  • 문자열이 아닌 입력 개체는을 사용하여 콘솔에 보냈을 때와 같이 형식이 지정됩니다 Out-File.

예:

(Get-Content $MyPath) | Out-FileUtf8NoBom $MyPath

로 묶는 방법 (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.ProviderPath) # Caveat: Older .NET Core versions don'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()
  }

}


답변

버전 6 부터 powershell은 set-contentout-fileUTF8NoBOM 모두에 대한 인코딩을 지원 하며 기본 인코딩으로도 사용합니다.

위의 예에서 간단히 다음과 같아야합니다.

$MyFile | Out-File -Encoding UTF8NoBOM $MyPath


답변

사용하는 경우 Set-Content대신 Out-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

사용 [IO.File]::WriteAllLines()또는 유사 의 차이점 은 실제 파일 경로뿐만 아니라 모든 유형의 항목 및 경로에서 잘 작동한다는 것입니다.


답변

이 스크립트는 BOM없이 UTF-8로 DIRECTORY1의 모든 .txt 파일을 변환하여 DIRECTORY2로 출력합니다.

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