Out-File
UTF-8을 사용할 때 BOM을 강제하는 것 같습니다.
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
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)
[System.IO.File]::WriteAllLines($MyPath, $MyFile)
충분합니다. 이 WriteAllLines
과부하는 BOM없이 정확하게 UTF8을 씁니다.
WriteAllLines
것 같습니다 $MyPath
.
WriteAllLines
는에서 현재 디렉토리를 가져옵니다 [System.Environment]::CurrentDirectory
. 당신이 PowerShell을 열고 현재 디렉토리 (사용 변경하는 경우 cd
또는 Set-Location
), 다음 [System.Environment]::CurrentDirectory
변경되지 않습니다 및 파일이 잘못된 디렉토리에 끝나게됩니다. 에 의해이 문제를 해결할 수 있습니다 [System.Environment]::CurrentDirectory = (Get-Location).Path
.
현재 올바른 방법은 @Roman Kuzmin이 권장하는 솔루션을 @M 에 대한 의견으로 사용 하는 것입니다. 더들리 답변 :
[IO.File]::WriteAllLines($filename, $content)
(또한 불필요한 System
네임 스페이스 설명 을 제거하여 약간 줄 였습니다. 기본적으로 자동으로 대체됩니다.)
[IO.File]::WriteAllLines(($filename | Resolve-Path), $content)
나는 이것이 UTF-8이 아니라고 생각했지만 작동하는 것처럼 보이는 매우 간단한 해결책을 찾았습니다 ...
Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext
나에게 이것은 소스 형식에 관계없이 bom 파일이없는 utf-8이됩니다.
-encoding utf8
내 요구 사항에 사용한 것을 제외하고는 나를 위해 일했습니다 .
-Encoding ASCII
BOM 문제를 피할 수 있지만 분명히 7 비트 ASCII 문자 만 얻을 수 있습니다. ASCII가 UTF-8의 서브 세트 인 경우 결과 파일은 기술적으로 유효한 UTF-8 파일이지만 입력의 모든 비 ASCII 문자는 리터럴 ?
문자 로 변환됩니다 .
-encoding utf8
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) 명령이 중단되면 데이터가 손실됩니다.
메모리 사용 에 대한 참고 사항 :
소스 코드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-content 및 out-fileUTF8NoBOM
모두에 대한 인코딩을 지원 하며 기본 인코딩으로도 사용합니다.
위의 예에서 간단히 다음과 같아야합니다.
$MyFile | Out-File -Encoding UTF8NoBOM $MyPath
$PSVersionTable.PSVersion
사용하는 경우 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);
}
[System.IO.FileInfo] $file = Get-Item -Path $FilePath
$sequenceBOM = New-Object System.Byte[] 3
$reader = $file.OpenRead()
$bytesRead = $reader.Read($sequenceBOM, 0, 3)
$reader.Dispose()
#A UTF-8+BOM string will start with the three following bytes. Hex: 0xEF0xBB0xBF, Decimal: 239 187 191
if ($bytesRead -eq 3 -and $sequenceBOM[0] -eq 239 -and $sequenceBOM[1] -eq 187 -and $sequenceBOM[2] -eq 191)
{
$utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLines($FilePath, (Get-Content $FilePath), $utf8NoBomEncoding)
Write-Host "Remove UTF-8 BOM successfully"
}
Else
{
Write-Warning "Not UTF-8 BOM file"
}
소스 PowerShell을 사용하여 파일에서 UTF8 BOM (Byte Order Mark)을 제거하는 방법
당신이 사용하려는 경우 [System.IO.File]::WriteAllLines()
, 당신은에 두 번째 매개 변수를 캐스팅해야 String[]
(의 유형이있는 경우 $MyFile
이다 Object[]
), 또한으로 절대 경로를 지정$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
같은 :
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem | ConvertTo-Csv | Set-Variable MyFile
[System.IO.File]::WriteAllLines($ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath), [String[]]$MyFile, $Utf8NoBomEncoding)
을 사용하려면 [System.IO.File]::WriteAllText()
때로는 두 번째 매개 변수를 파이프하여 | Out-String |
각 줄의 끝에 CRLF를 명시 적으로 추가해야합니다 (특히ConvertTo-Csv
).
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem | ConvertTo-Csv | Out-String | Set-Variable tmp
[System.IO.File]::WriteAllText("/absolute/path/to/foobar.csv", $tmp, $Utf8NoBomEncoding)
또는 [Text.Encoding]::UTF8.GetBytes()
함께 사용할 수 있습니다Set-Content -Encoding Byte
.
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
Get-ChildItem | ConvertTo-Csv | Out-String | % { [Text.Encoding]::UTF8.GetBytes($_) } | Set-Content -Encoding Byte -Path "/absolute/path/to/foobar.csv"
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
은 Convert-Path $MyPath
; 당신은 뒤에 CRLF를 확인하려는 경우, 단순히 사용 [System.IO.File]::WriteAllLines()
로도 하나의 입력 문자열 (필요 없음 Out-String
).
내가 사용하는 한 가지 기술은 Out-File을 사용하여 출력을 ASCII 파일로 리디렉션하는 것입니다 cmdlet을 입니다.
예를 들어, Oracle에서 실행할 다른 SQL 스크립트를 작성하는 SQL 스크립트를 자주 실행합니다. 간단한 재 지정 ( ">")을 사용하면 출력이 UTF-16으로되어 SQLPlus에서 인식되지 않습니다. 이 문제를 해결하려면
sqlplus -s / as sysdba "@create_sql_script.sql" |
Out-File -FilePath new_script.sql -Encoding ASCII -Force
그런 다음 생성 된 스크립트는 유니 코드 걱정없이 다른 SQLPlus 세션을 통해 실행될 수 있습니다.
sqlplus / as sysdba "@new_script.sql" |
tee new_script.log
-Encoding ASCII
BOM 문제를 피할 수 있지만 분명히 7 비트 ASCII 문자 만 지원 합니다 . ASCII가 UTF-8의 서브 세트 인 경우 결과 파일은 기술적으로 유효한 UTF-8 파일이지만 입력의 모든 비 ASCII 문자는 리터럴 ?
문자 로 변환됩니다 .
BOM없이 확장자로 여러 파일을 UTF-8로 변경하십시오.
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach($i in ls -recurse -filter "*.java") {
$MyFile = Get-Content $i.fullname
[System.IO.File]::WriteAllLines($i.fullname, $MyFile, $Utf8NoBomEncoding)
}
어떤 이유에서든, WriteAllLines
콜리스는 BOMless UTF8Encoding
인수와 함께없이 BOM을 계속 생성하고 있었습니다. 그러나 다음은 저에게 효과적이었습니다.
$bytes = gc -Encoding byte BOMthetorpedoes.txt
[IO.File]::WriteAllBytes("$(pwd)\BOMthetorpedoes.txt", $bytes[3..($bytes.length-1)])
파일 경로가 절대적으로 작동하도록해야했습니다. 그렇지 않으면 파일을 내 데스크탑에 썼습니다. 또한 BOM이 3 바이트임을 알고있는 경우에만 작동한다고 가정합니다. 인코딩을 기반으로 주어진 BOM 형식 / 길이를 기대하는 것이 얼마나 안정적인지 잘 모르겠습니다.
또한 작성된 것처럼 파일이 powershell 배열에 맞는 경우에만 작동하며 길이 제한이 [int32]::MaxValue
내 컴퓨터 보다 낮습니다 .
WriteAllLines
인코딩 인수가 없으면 BOM 자체를 쓰지 않지만 문자열 이 BOM 문자 ( U+FEFF
) 로 시작 하여 UTF-8 BOM을 효과적으로 생성 한 것으로 생각할 수 있습니다 . 예 : $s = [char] 0xfeff + 'hi'; [io.file]::WriteAllText((Convert-Path t.txt), $s)
( BOM이 작성 되지 않았 음[char] 0xfeff +
을 보려면 생략 ).
[Environment]::CurrentDirectory = $PWD.ProviderPath
하거나 "$(pwd)\..."
접근 방식에 대한보다 일반적인 대안 (더 "$pwd\..."
나은 : "$($pwd.ProviderPath)\..."
또는 더 나은 : 또는 (Join-Path $pwd.ProviderPath ...)
)으로(Convert-Path BOMthetorpedoes.txt)
U+FEFF
.
BOM없이 UTF8을 얻기 위해 아래를 사용할 수 있습니다.
$MyFile | Out-File -Encoding ASCII
ASCII
이 UTF-8이 아니라는 것이 맞지만 현재 ANSI 코드 페이지가 아닙니다 Default
. ASCII
실제로 7 비트 ASCII 인코딩이며 128보다 큰 코드 포인트는 리터럴 ?
인스턴스 로 변환됩니다 .
-Encoding ASCII
실제로 7 비트 ASCII 전용인지 확인하려면 다음을 시도하십시오 'äb' | out-file ($f = [IO.Path]::GetTempFilename()) -encoding ASCII; '?b' -eq $(Get-Content $f; Remove-Item $f)
.- ä
이 (가) 음역되었습니다 ?
. 반대로 -Encoding Default
( "ANSI")는이를 올바르게 보존합니다.
이것은 나를 위해 작동합니다 ( "UTF8"대신 "Default"사용).
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "Default" $MyPath
결과는 BOM이없는 ASCII입니다.