Out-File
tampaknya memaksa BOM saat menggunakan UTF-8:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
Bagaimana saya bisa menulis file di UTF-8 tanpa BOM menggunakan PowerShell?
encoding
powershell
utf-8
byte-order-mark
M. Dudley
sumber
sumber
Jawaban:
Menggunakan
UTF8Encoding
kelas .NET dan meneruskan$False
ke konstruktor tampaknya berfungsi:sumber
[System.IO.File]::WriteAllLines($MyPath, $MyFile)
sudah cukup.WriteAllLines
Kelebihan ini menulis persis UTF8 tanpa BOM.WriteAllLines
tampaknya$MyPath
harus mutlak.WriteAllLines
mendapatkan direktori saat ini dari[System.Environment]::CurrentDirectory
. Jika Anda membuka PowerShell dan kemudian mengubah direktori Anda saat ini (menggunakancd
atauSet-Location
), maka[System.Environment]::CurrentDirectory
tidak akan berubah dan file akan berakhir di direktori yang salah. Anda dapat mengatasi ini dengan[System.Environment]::CurrentDirectory = (Get-Location).Path
.Cara yang tepat seperti sekarang adalah menggunakan solusi yang direkomendasikan oleh @Roman Kuzmin dalam komentar ke @M. Dudley menjawab :
(Saya juga telah mempersingkatnya sedikit dengan menghapus
System
klarifikasi namespace yang tidak perlu - itu akan diganti secara otomatis secara default.)sumber
[IO.File]::WriteAllLines(($filename | Resolve-Path), $content)
Saya pikir ini bukan UTF, tapi saya baru saja menemukan solusi yang cukup sederhana yang sepertinya berfungsi ...
Bagi saya ini menghasilkan utf-8 tanpa file bom terlepas dari format sumbernya.
sumber
-encoding utf8
untuk kebutuhan saya.-Encoding ASCII
hindari masalah BOM, tetapi Anda jelas hanya mendapatkan karakter ASCII 7-bit . Karena ASCII adalah bagian dari UTF-8, file yang dihasilkan secara teknis juga merupakan file UTF-8 yang valid, tetapi semua karakter non-ASCII dalam input Anda akan dikonversi ke?
karakter literal .-encoding utf8
masih menampilkan UTF-8 dengan BOM. :(Catatan: Jawaban ini berlaku untuk Windows PowerShell ; Sebaliknya, dalam PowerShell Core edisi lintas platform (v6 +), UTF-8 tanpa BOM adalah penyandian default , di semua cmdlet.
Dengan kata lain: Jika Anda menggunakan PowerShell [Core] versi 6 atau lebih tinggi , Anda mendapatkan file UTF-8 BOM-kurang secara default (yang Anda juga dapat secara eksplisit meminta dengan
-Encoding utf8
/-Encoding utf8NoBOM
, sedangkan Anda mendapatkan dengan -BOM encoding dengan-utf8BOM
).Untuk melengkapi jawaban M. Dudley yang sederhana dan pragmatis (dan reformulasi ForNeVeR yang lebih ringkas ):
Untuk kenyamanan, inilah fungsi lanjutan
Out-FileUtf8NoBom
, alternatif berbasis pipa yang meniruOut-File
, yang berarti:Out-File
dalam pipa.Out-File
.Contoh:
Perhatikan bagaimana
(Get-Content $MyPath)
terlampir(...)
, yang memastikan bahwa seluruh file dibuka, dibaca secara penuh, dan ditutup sebelum mengirim hasilnya melalui pipa. Ini diperlukan untuk dapat menulis kembali ke file yang sama (perbarui di tempat ).Namun, secara umum, teknik ini tidak dianjurkan karena 2 alasan: (a) seluruh file harus sesuai dengan memori dan (b) jika perintah terputus, data akan hilang.
Catatan tentang penggunaan memori :
Kode sumber
Out-FileUtf8NoBom
(juga tersedia sebagai Inti berlisensi MIT ):sumber
Mulai dari versi 6 PowerShell mendukung
UTF8NoBOM
encoding baik untuk set-content dan out-file dan bahkan menggunakan ini sebagai encoding default.Jadi dalam contoh di atas seharusnya menjadi seperti ini:
sumber
$PSVersionTable.PSVersion
Saat menggunakan
Set-Content
alih-alihOut-File
, Anda dapat menentukan pengkodeanByte
, yang dapat digunakan untuk menulis array byte ke file. Ini dikombinasikan dengan pengkodean UTF8 khusus yang tidak memancarkan BOM memberikan hasil yang diinginkan:Perbedaan menggunakan
[IO.File]::WriteAllLines()
atau serupa adalah bahwa itu harus berfungsi dengan baik dengan semua jenis item dan jalur, tidak hanya jalur file yang sebenarnya.sumber
Skrip ini akan mengonversi, menjadi UTF-8 tanpa BOM, semua file .txt dalam DIRECTORY1 dan menghasilkannya menjadi DIRECTORY2
sumber
Sumber Cara menghapus UTF8 Byte Order Mark (BOM) dari file menggunakan PowerShell
sumber
Jika Anda ingin menggunakan
[System.IO.File]::WriteAllLines()
, Anda harus memberikan parameter kedua keString[]
(jika tipe$MyFile
isObject[]
), dan juga menentukan path absolut dengan$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
, seperti:Jika Anda ingin menggunakan
[System.IO.File]::WriteAllText()
, kadang-kadang Anda harus memasukkan parameter kedua ke dalam| Out-String |
untuk menambahkan CRLF ke akhir setiap baris secara eksplisit (Terutama ketika Anda menggunakannyaConvertTo-Csv
):Atau Anda dapat menggunakan
[Text.Encoding]::UTF8.GetBytes()
denganSet-Content -Encoding Byte
:lihat: Cara menulis hasil ConvertTo-Csv ke file di UTF-8 tanpa BOM
sumber
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
adalahConvert-Path $MyPath
; jika Anda ingin memastikan CRLF tertinggal, cukup gunakan[System.IO.File]::WriteAllLines()
bahkan dengan string input tunggal (tidak perlu untukOut-String
).Salah satu teknik yang saya gunakan adalah untuk mengarahkan output ke file ASCII menggunakan cmdlet Out-File .
Sebagai contoh, saya sering menjalankan skrip SQL yang membuat skrip SQL lain untuk dieksekusi di Oracle. Dengan pengalihan sederhana (">"), output akan berada di UTF-16 yang tidak dikenali oleh SQLPlus. Untuk mengatasi ini:
Script yang dihasilkan kemudian dapat dieksekusi melalui sesi SQLPlus lain tanpa kekhawatiran Unicode:
sumber
-Encoding ASCII
hindari masalah BOM, tetapi Anda jelas hanya mendapatkan dukungan untuk karakter ASCII 7-bit . Karena ASCII adalah bagian dari UTF-8, file yang dihasilkan secara teknis juga merupakan file UTF-8 yang valid, tetapi semua karakter non-ASCII dalam input Anda akan dikonversi ke?
karakter literal .Ubah beberapa file dengan ekstensi menjadi UTF-8 tanpa BOM:
sumber
Untuk alasan apa pun,
WriteAllLines
telepon masih menghasilkan BOM untuk saya, denganUTF8Encoding
argumen BOMless dan tanpa itu. Tetapi yang berikut ini berhasil untuk saya:Saya harus membuat path file mutlak untuk berfungsi. Kalau tidak, ia menulis file ke Desktop saya. Juga, saya kira ini hanya berfungsi jika Anda tahu BOM Anda adalah 3 byte. Saya tidak tahu seberapa dapat diandalkan untuk mengharapkan format BOM yang diberikan / panjang berdasarkan pengkodean.
Juga, seperti yang ditulis, ini mungkin hanya berfungsi jika file Anda cocok dengan array powershell, yang tampaknya memiliki batas panjang beberapa nilai lebih rendah daripada
[int32]::MaxValue
di komputer saya.sumber
WriteAllLines
tanpa argumen penyandian tidak pernah menulis BOM itu sendiri , tetapi mungkin string Anda dimulai dengan BOM karakter (U+FEFF
), yang pada penulisan secara efektif membuat BOM UTF-8; misalnya:$s = [char] 0xfeff + 'hi'; [io.file]::WriteAllText((Convert-Path t.txt), $s)
(hilangkan[char] 0xfeff +
untuk melihat bahwa tidak ada BOM yang ditulis).[Environment]::CurrentDirectory = $PWD.ProviderPath
, atau, sebagai alternatif yang lebih umum untuk"$(pwd)\..."
pendekatan Anda (lebih baik:,"$pwd\..."
bahkan lebih baik:"$($pwd.ProviderPath)\..."
atau(Join-Path $pwd.ProviderPath ...)
), gunakan(Convert-Path BOMthetorpedoes.txt)
U+FEFF
abstrak tunggal .Dapat menggunakan di bawah ini untuk mendapatkan UTF8 tanpa BOM
sumber
ASCII
bukan UTF-8, tetapi itu bukan codepage ANSI saat ini - Anda sedang memikirkanDefault
;ASCII
benar-benar adalah pengkodean ASCII 7-bit, dengan codepoints = = 128 yang dikonversi ke?
instance literal .-Encoding ASCII
memang hanya ASCII 7-bit:'äb' | out-file ($f = [IO.Path]::GetTempFilename()) -encoding ASCII; '?b' -eq $(Get-Content $f; Remove-Item $f)
-ä
telah ditransliterasikan ke a?
. Sebaliknya,-Encoding Default
("ANSI") akan melestarikannya dengan benar.Ini berfungsi untuk saya (gunakan "Default" dan bukan "UTF8"):
Hasilnya adalah ASCII tanpa BOM.
sumber
Default
pengkodean akan menggunakan halaman kode ANSI sistem saat ini, yang bukan UTF-8, seperti yang saya perlukan.