Out-File
UTF-8 kullanırken Malzeme Listesini zorladı gibi görünüyor:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
PowerShell kullanarak BOM olmadan UTF-8'de nasıl dosya yazabilirim?
Out-File
UTF-8 kullanırken Malzeme Listesini zorladı gibi görünüyor:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
PowerShell kullanarak BOM olmadan UTF-8'de nasıl dosya yazabilirim?
Yanıtlar:
.NET UTF8Encoding
sınıfını kullanmak ve yapıcıya $False
geçmek işe yarıyor gibi görünüyor:
$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)
yeterlidir. Bu WriteAllLines
aşırı yük BOM olmadan tam olarak UTF8 yazar.
WriteAllLines
görülüyor $MyPath
.
WriteAllLines
geçerli dizini alır [System.Environment]::CurrentDirectory
. PowerShell'i açar ve geçerli dizininizi değiştirirseniz ( cd
veya kullanarak Set-Location
), [System.Environment]::CurrentDirectory
değiştirilmez ve dosya yanlış dizinde olur. Bu sorunu çözebilirsin [System.Environment]::CurrentDirectory = (Get-Location).Path
.
Uygun bugün itibariyle yolu @Roman Kuzmin tarafından önerilen bir çözüm kullanmaktır yorumlarda .m için. Dudley cevabı :
[IO.File]::WriteAllLines($filename, $content)
(Ayrıca gereksiz System
ad alanı açıklamalarını sıyırıp biraz kısalttım - varsayılan olarak otomatik olarak değiştirilecektir.)
[IO.File]::WriteAllLines(($filename | Resolve-Path), $content)
Bunun UTF olmayacağını düşündüm, ama işe yarayan oldukça basit bir çözüm buldum ...
Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext
Benim için bu, kaynak biçimine bakılmaksızın bom dosyası olmayan bir utf-8 ile sonuçlanır.
-encoding utf8
ihtiyacım için kullandım .
-Encoding ASCII
ürün ağacı sorununu önler, ancak sadece 7 bit ASCII karakterleri alırsınız . ASCII'nin UTF-8'in bir alt kümesi olduğu göz önüne alındığında, sonuçta elde edilen dosya teknik olarak geçerli bir UTF-8 dosyasıdır, ancak girişinizdeki tüm ASCII olmayan karakterler değişmez ?
karakterlere dönüştürülecektir .
-encoding utf8
yine de UTF-8'i bir Malzeme Listesi ile çıktı. :(
Not: Bu cevap Windows PowerShell için geçerlidir ; Buna göre, çapraz platform PowerShell içinde Çekirdek baskısında (v6 +), UTF-8 BOM olmadan olduğu varsayılan kodlama tüm cmdlets karşısında.
Başka bir deyişle: Eğer kullanıyorsanız PowerShell [Çekirdek] sürüm 6 veya üstü , sen olsun BOM-az UTF-8 dosyaları varsayılan olarak (siz de açık bir şekilde belirtilen isteyebilir -Encoding utf8
/ -Encoding utf8NoBOM
elde edersiniz oysa ile birlikte -BOM kodlama -utf8BOM
).
Tamamlamak için M. Dudley kendi basit ve pragmatik bir cevap (ve ForNeVeR en fazla özlü yeniden formüle ):
Kolaylık sağlamak için, burada taklit eden boru hattı tabanlı bir alternatif olan gelişmiş işlev Out-FileUtf8NoBom
, yani:Out-File
Out-File
bir boru hattında olduğu gibi kullanabilirsiniz .Out-File
.Misal:
(Get-Content $MyPath) | Out-FileUtf8NoBom $MyPath
Nasıl Not (Get-Content $MyPath)
içine alınır (...)
, hangi tüm dosya boru hattıyla sonucu göndermeden önce, açılan tam olarak okunur ve kapalı olmasını sağlar. Bu, aynı dosyaya geri yazabilmek için gereklidir ( yerinde güncelleyin ).
Genel olarak, bu teknik 2 nedenden dolayı tavsiye edilmez: (a) tüm dosya belleğe sığmalıdır ve (b) komut kesilirse veriler kaybolur.
Bellek kullanımına ilişkin bir not :
Kaynak koduOut-FileUtf8NoBom
( MIT lisanslı Gist olarak da mevcuttur ):
<#
.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()
}
}
Sürüm 6'dan başlayarak powershell, set-content ve out-fileUTF8NoBOM
için kodlamayı destekler ve hatta bunu varsayılan kodlama olarak kullanır.
Yani yukarıdaki örnekte bu sadece şöyle olmalıdır:
$MyFile | Out-File -Encoding UTF8NoBOM $MyPath
$PSVersionTable.PSVersion
Set-Content
Bunun yerine kullanırken Out-File
, Byte
bir dosyaya bir bayt dizisi yazmak için kullanılabilecek kodlamayı belirtebilirsiniz . Bu, Malzeme Listesini yaymayan özel bir UTF8 kodlaması ile birlikte istenen sonucu verir:
# 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
Kullanmanın [IO.File]::WriteAllLines()
veya benzerinin arasındaki fark , yalnızca gerçek dosya yollarıyla değil, her tür öğe ve yolla iyi çalışması gerektiğidir.
Bu komut dosyası, BOM olmadan UTF-8'e, DIRECTORY1 içindeki tüm .txt dosyalarını dönüştürecek ve DIRECTORY2 dizinine çıkaracaktır.
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"
}
Kaynak PowerShell kullanarak bir dosyadan UTF8 Bayt Sipariş İşareti (BOM) nasıl kaldırılır
Kullanmak istiyorsanız [System.IO.File]::WriteAllLines()
, ikinci parametreyi String[]
(türü $MyFile
ise Object[]
) olarak kullanmanız ve ayrıca şu şekilde mutlak yol belirtmeniz gerekir $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)
Kullanmak isterseniz [System.IO.File]::WriteAllText()
, bazen boru içine ikinci parametre olmalıdır | Out-String |
explictly (eğer bunları kullanmak Özellikle her satırın sonuna CRLFs eklemek için 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)
Yoksa kullanabilirsiniz [Text.Encoding]::UTF8.GetBytes()
ile 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"
bkz: ConvertTo-Csv'nin sonucunu BOM olmadan UTF-8'deki bir dosyaya yazma
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
olduğu Convert-Path $MyPath
; bir izleyen CRLF sağlamak istiyorsanız, tek bir giriş dizesi [System.IO.File]::WriteAllLines()
ile bile kullanın (gerek yok ). Out-String
Kullandığım tekniklerden biri çıktıyı Out-File cmdlet'ini kullanarak bir ASCII dosyasına yeniden yönlendirmektir .
Örneğin, genellikle Oracle'da yürütmek için başka bir SQL komut dosyası oluşturan SQL komut dosyaları çalıştırıyorum. Basit yeniden yönlendirme (">") ile çıkış, SQLPlus tarafından tanınmayan UTF-16'da olacaktır. Bu sorunu çözmek için:
sqlplus -s / as sysdba "@create_sql_script.sql" |
Out-File -FilePath new_script.sql -Encoding ASCII -Force
Oluşturulan komut dosyası daha sonra herhangi bir Unicode endişesi olmadan başka bir SQLPlus oturumu aracılığıyla yürütülebilir:
sqlplus / as sysdba "@new_script.sql" |
tee new_script.log
-Encoding ASCII
ürün ağacı sorununu önler, ancak açıkçası yalnızca 7 bit ASCII karakterleri için destek alırsınız . ASCII'nin UTF-8'in bir alt kümesi olduğu göz önüne alındığında, sonuçta elde edilen dosya teknik olarak geçerli bir UTF-8 dosyasıdır, ancak girişinizdeki tüm ASCII olmayan karakterler değişmez ?
karakterlere dönüştürülecektir .
Birden çok dosyayı BOM olmadan UTF-8 olarak değiştirin:
$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)
}
Her ne sebeple olursa olsun, WriteAllLines
çağrılar hala BOMless UTF8Encoding
argümanı ve onsuz bir BOM üretiyordu . Ama aşağıdakiler benim için çalıştı:
$bytes = gc -Encoding byte BOMthetorpedoes.txt
[IO.File]::WriteAllBytes("$(pwd)\BOMthetorpedoes.txt", $bytes[3..($bytes.length-1)])
Dosya yolunu çalışması için mutlak hale getirmek zorunda kaldım. Aksi takdirde dosyayı Masaüstüme yazdı. Ayrıca, bunun yalnızca ürün ağacınızın 3 bayt olduğunu biliyorsanız çalışır. Ben kodlama dayalı verilen bir ürün ağacı biçimi / uzunluğu beklemek ne kadar güvenilir bir fikrim yok.
Ayrıca, yazıldığı gibi, bu muhtemelen sadece dosyanız bir powershell dizisine sığarsa çalışır, bu da [int32]::MaxValue
benim makinemden daha düşük bir değer uzunluğu sınırı var gibi görünüyor .
WriteAllLines
bir kodlama argümanı bir BOM yazar asla olmadan kendisi ama bu senin tabi mümkünse dize BOM ile başlamak oldu karakteri ( U+FEFF
üzerinde etkili UTF-8 BOM oluşturulan yazılı); örneğin: $s = [char] 0xfeff + 'hi'; [io.file]::WriteAllText((Convert-Path t.txt), $s)
( hiçbir Malzeme Listesinin yazılmadığını [char] 0xfeff +
görmek için) ' i atlayın ).
[Environment]::CurrentDirectory = $PWD.ProviderPath
veya "$(pwd)\..."
yaklaşımınıza daha genel bir alternatif olarak (daha iyi:, "$pwd\..."
daha da iyi: "$($pwd.ProviderPath)\..."
veya (Join-Path $pwd.ProviderPath ...)
), kullanın(Convert-Path BOMthetorpedoes.txt)
U+FEFF
bayt temsilidir .
BOM olmadan UTF8 almak için aşağıda kullanılabilir
$MyFile | Out-File -Encoding ASCII
ASCII
UTF-8 olmadığı doğru , ancak şu anki ANSI kod sayfası değil - siz düşünüyorsunuz Default
; ASCII
gerçekte 7 bitlik ASCII kodlamasıdır ve kod noktaları> = 128 değişmez ?
örneklere dönüştürülür .
-Encoding ASCII
Gerçekten 7-bit ASCII olduğunu doğrulamak için bunu deneyin : 'äb' | out-file ($f = [IO.Path]::GetTempFilename()) -encoding ASCII; '?b' -eq $(Get-Content $f; Remove-Item $f)
- ä
a'ya dönüştürülmüştür ?
. Aksine, -Encoding Default
("ANSI") doğru şekilde koruyacaktır.
Bu benim için çalışıyor ("UTF8" yerine "Varsayılan" kullanın):
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "Default" $MyPath
Sonuç BOM'suz ASCII olur.
Default
Ben gerektiği gibi, UTF-8 değil sistemin geçerli ANSI kod sayfası, kullanacağı kodlamayı.