encoding powershell utf-8 byte-order-mark

encoding - Uso de PowerShell para escribir un archivo en UTF-8 sin BOM



byte-order-mark (14)

Al usar Set-Content lugar de Out-File , puede especificar el Byte codificación, que puede usarse para escribir una matriz de bytes en un archivo. Esto, en combinación con una codificación UTF8 personalizada que no emite la lista de materiales, da el resultado deseado:

# 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

La diferencia con el uso de [IO.File]::WriteAllLines() o similar es que debería funcionar bien con cualquier tipo de elemento y ruta, no solo con las rutas de archivo reales.

Out-File parece forzar la lista de materiales cuando se usa UTF-8:

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

¿Cómo puedo escribir un archivo en UTF-8 sin BOM utilizando PowerShell?


Cambie varios archivos por extensión a UTF-8 sin BOM:

$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) }


El uso de la clase UTF8Encoding de .NET y pasar $False al constructor parece funcionar:

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


Este funciona para mí (use "Predeterminado" en lugar de "UTF8"):

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

El resultado es ASCII sin BOM.


Este script convertirá, a UTF-8 sin BOM, todos los archivos .txt en DIRECTORY1 y los enviará a DIRECTORY2

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


La forma correcta a partir de ahora es utilizar una solución recomendada por @Roman Kuzmin en los comentarios a @M. answer Dudley:

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

(También lo he reducido un poco eliminando la aclaración innecesaria System espacio de nombres del System ; se sustituirá automáticamente de forma predeterminada).


Pensé que esto no sería UTF, pero acabo de encontrar una solución bastante simple que parece funcionar ...

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

Para mí, esto resulta en un utf-8 sin archivo bom, independientemente del formato de origen.


Podría usarse a continuación para obtener UTF8 sin BOM

$MyFile | Out-File -Encoding ASCII


Por el motivo que sea, las llamadas de WriteAllLines seguían generando una lista de materiales para mí, con el argumento BOMless UTF8Encoding y sin él. Pero lo siguiente me funcionó:

$bytes = gc -Encoding byte BOMthetorpedoes.txt [IO.File]::WriteAllBytes("$(pwd)/BOMthetorpedoes.txt", $bytes[3..($bytes.length-1)])

Tuve que hacer que la ruta del archivo fuera absoluta para que funcione. De lo contrario escribía el archivo a mi escritorio. Además, supongo que esto solo funciona si sabe que su lista de materiales es de 3 bytes. No tengo idea de lo confiable que es esperar un determinado formato / longitud de la lista de materiales en función de la codificación.

Además, tal como está escrito, esto probablemente solo funcione si su archivo se ajusta a una matriz powershell, que parece tener un límite de longitud de algún valor inferior a [int32]::MaxValue en mi máquina.


Si desea usar [System.IO.File]::WriteAllLines() , debe convertir el segundo parámetro a String[] (si el tipo de $MyFile es Object[] ), y también especificar la ruta absoluta con $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath) , como:

$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)

Si desea usar [System.IO.File]::WriteAllText() , a veces debe [System.IO.File]::WriteAllText() el segundo parámetro en | Out-String | | Out-String | para agregar CRLF al final de cada línea explícitamente (especialmente cuando los usa con 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)

O puede usar [Text.Encoding]::UTF8.GetBytes() con 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"

consulte: Cómo escribir el resultado de ConvertTo-Csv en un archivo en UTF-8 sin BOM


Tenía el mismo problema. Eso hizo el truco para mí:

$MyFile | Out-File -Encoding Oem $MyPath

Al abrir el archivo con Visual Studio Code o Notepad ++ se muestra como UTF-8


Una técnica que utilizo es redirigir la salida a un archivo ASCII usando el cmdlet Out-File .

Por ejemplo, a menudo ejecuto scripts SQL que crean otro script SQL para ejecutar en Oracle. Con una redirección simple (">"), la salida estará en UTF-16 que no es reconocida por SQLPlus. Para evitar esto:

sqlplus -s / as sysdba "@create_sql_script.sql" | Out-File -FilePath new_script.sql -Encoding ASCII -Force

El script generado puede ejecutarse a través de otra sesión de SQLPlus sin preocupaciones de Unicode:

sqlplus / as sysdba "@new_script.sql" | tee new_script.log


Nota: esta respuesta se aplica a Windows PowerShell ; por el contrario, en la edición multiplataforma de PowerShell Core , UTF-8 sin BOM es la codificación predeterminada .

Para complementar la respuesta simple y pragmática de M. Dudley (y la reformulación más concisa de ForNeVeR ):

Para mayor comodidad, aquí está la función avanzada Out-FileUtf8NoBom , una alternativa basada en canalización que imita Out-File , lo que significa:

  • Puedes usarlo como Out-File en una tubería.
  • los objetos de entrada que no son cadenas se formatean como lo harían si los enviara a la consola, al igual que con Out-File .

Ejemplo:

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

Observe cómo (Get-Content $MyPath) se (Get-Content $MyPath) en (...) , lo que garantiza que todo el archivo se abra, se lea en su totalidad y se cierre antes de enviar el resultado a través de la canalización. Esto es necesario para poder volver a escribir en el mismo archivo (actualizarlo en su lugar ).
En general, sin embargo, esta técnica no es aconsejable por 2 razones: (a) todo el archivo debe caber en la memoria y (b) si el comando se interrumpe, los datos se perderán.

Una nota sobre el uso de la memoria :

  • La propia respuesta de M. Dudley requiere que todo el contenido del archivo se cree primero en la memoria, lo que puede ser problemático con archivos grandes.
  • La siguiente función mejora solo ligeramente: todos los objetos de entrada se almacenan primero en búfer, pero las representaciones de cadenas se generan y se escriben en el archivo de salida una por una.

Código fuente de Out-FileUtf8NoBom (también disponible como Gist con licencia MIT ):

<# .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() } }


[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" }

Fuente Cómo eliminar la marca de orden de bytes UTF8 (BOM) de un archivo con PowerShell