Out-File
кажется, заставляет спецификацию при использовании UTF-8:
$MyFile = Get-Content $MyPath
$MyFile | Out-File -Encoding "UTF8" $MyPath
Как я могу написать файл в UTF-8 без спецификации, используя PowerShell?
encoding
powershell
utf-8
byte-order-mark
М. Дадли
источник
источник
Ответы:
Использование
UTF8Encoding
класса .NET и передача$False
в конструктор, кажется, работает:источник
[System.IO.File]::WriteAllLines($MyPath, $MyFile)
достаточно. ЭтаWriteAllLines
перегрузка пишет именно UTF8 без спецификации.WriteAllLines
кажется, требуется$MyPath
быть абсолютным.WriteAllLines
получает текущий каталог от[System.Environment]::CurrentDirectory
. Если вы откроете PowerShell, а затем измените свой текущий каталог (используяcd
илиSet-Location
),[System.Environment]::CurrentDirectory
это не изменится, и файл окажется в неправильном каталоге. Вы можете обойти это путем[System.Environment]::CurrentDirectory = (Get-Location).Path
.На данный момент правильным способом является использование решения, рекомендованного @Roman Kuzmin в комментариях к @M. Дадли ответ :
(Я также немного сократил это, удалив ненужное
System
уточнение пространства имен - оно будет заменено автоматически по умолчанию.)источник
[IO.File]::WriteAllLines(($filename | Resolve-Path), $content)
Я подумал, что это не будет UTF, но я нашел довольно простое решение, которое, кажется, работает ...
Для меня это приводит к UTF-8 без файла BOM независимо от исходного формата.
источник
-encoding utf8
для моего требования.-Encoding ASCII
избегает проблемы спецификации, но вы, очевидно, получаете только 7-битные символы ASCII . Учитывая, что ASCII является подмножеством UTF-8, результирующий файл технически также является допустимым файлом UTF-8, но все не входящие в ASCII символы в вашем вводе будут преобразованы в литеральные?
символы .-encoding utf8
все равно выдает UTF-8 с спецификацией. :(Примечание. Этот ответ относится к Windows PowerShell ; напротив, в кроссплатформенном выпуске PowerShell Core (v6 +) UTF-8 без спецификации является кодировкой по умолчанию для всех командлетов.
Другими словами: если вы используете PowerShell [Core] версии 6 или выше , по умолчанию вы получаете файлы без BOM UTF-8 (которые вы также можете явно запрашивать с помощью
-Encoding utf8
/-Encoding utf8NoBOM
, тогда как вы получаете с -BOM с кодировкой-utf8BOM
).В дополнение к простому и прагматичному ответу М. Дадли (и более краткой переформулировке ForNeVeR ):
Для удобства, вот расширенная функция
Out-FileUtf8NoBom
, альтернатива на основе конвейера, которая имитируетOut-File
, что означает:Out-File
в конвейере.Out-File
.Пример:
Обратите внимание на то, как
(Get-Content $MyPath)
это включено(...)
, что гарантирует, что весь файл будет открыт, прочитан полностью и закрыт перед отправкой результата по конвейеру. Это необходимо для возможности обратной записи в тот же файл (обновить его на месте ).Однако, как правило, этот метод не рекомендуется по двум причинам: (а) весь файл должен уместиться в памяти и (б) если команда прервана, данные будут потеряны.
Примечание об использовании памяти :
Исходный код
Out-FileUtf8NoBom
(также доступный как Mist-лицензированный Gist ):источник
Начиная с версии 6 powershell поддерживает
UTF8NoBOM
кодировку как для set-content, так и out-file, и даже использует ее в качестве кодировки по умолчанию.Так что в приведенном выше примере это должно быть просто так:
источник
$PSVersionTable.PSVersion
При использовании
Set-Content
вместоOut-File
вы можете указать кодировкуByte
, которую можно использовать для записи байтового массива в файл. Это в сочетании с пользовательской кодировкой UTF8, которая не излучает спецификацию, дает желаемый результат:Отличие от использования
[IO.File]::WriteAllLines()
или аналогичного заключается в том, что он должен хорошо работать с любым типом элемента и пути, а не только с реальными путями к файлам.источник
Этот скрипт преобразует в UTF-8 без спецификации все TXT-файлы в DIRECTORY1 и выводит их в DIRECTORY2.
источник
Источник Как удалить UTF8 Byte Order Mark (BOM) из файла с помощью PowerShell
источник
Если вы хотите использовать
[System.IO.File]::WriteAllLines()
, вы должны привести второй параметр кString[]
(если тип$MyFile
isObject[]
), а также указать абсолютный путь с помощью$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
, например:Если вы хотите использовать
[System.IO.File]::WriteAllText()
, иногда вам следует| Out-String |
передать второй параметр, чтобы явно добавить CRLF в конец каждой строки (особенно, когда вы используете их сConvertTo-Csv
):Или вы можете использовать
[Text.Encoding]::UTF8.GetBytes()
сSet-Content -Encoding Byte
:см .: Как записать результат ConvertTo-Csv в файл в UTF-8 без спецификации
источник
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($MyPath)
являетсяConvert-Path $MyPath
; если вы хотите обеспечить конечный CRLF, просто используйте[System.IO.File]::WriteAllLines()
даже с одной входной строкой (без необходимостиOut-String
).Я использую одну технику, чтобы перенаправить вывод в файл ASCII с помощью командлета Out-File .
Например, я часто запускаю сценарии SQL, которые создают другой сценарий SQL для выполнения в Oracle. С простым перенаправлением (">") вывод будет в UTF-16, который не распознается SQLPlus. Чтобы обойти это:
Сгенерированный сценарий затем может быть выполнен через другой сеанс SQLPlus без каких-либо проблем с Юникодом:
источник
-Encoding ASCII
позволяет избежать проблемы спецификации, но вы, очевидно, получаете поддержку только 7-битных символов ASCII . Учитывая, что ASCII является подмножеством UTF-8, результирующий файл технически также является допустимым файлом UTF-8, но все не входящие в ASCII символы в вашем вводе будут преобразованы в литеральные?
символы .Измените несколько файлов по расширению на UTF-8 без спецификации:
источник
По какой-то причине,
WriteAllLines
звонки все еще производили BOM для меня, сUTF8Encoding
аргументом BOMless и без него. Но у меня сработало следующее:Я должен был сделать путь к файлу абсолютным, чтобы он работал. В противном случае он записал файл на мой рабочий стол. Кроме того, я полагаю, это работает, только если вы знаете, что ваша спецификация составляет 3 байта. Я понятия не имею, насколько надежно ожидать заданный формат / длину спецификации на основе кодирования.
Кроме того, как написано, это, вероятно, работает, только если ваш файл помещается в массив powershell, который, кажется, имеет ограничение длины на некоторое значение ниже, чем
[int32]::MaxValue
на моем компьютере.источник
WriteAllLines
без аргумента кодирования никогда не записывается сама спецификация , но вполне возможно, что ваша строка начиналась с символа BOM (U+FEFF
), который при записи эффективно создавал спецификацию UTF-8; например:$s = [char] 0xfeff + 'hi'; [io.file]::WriteAllText((Convert-Path t.txt), $s)
(опускаем ,[char] 0xfeff +
чтобы увидеть , что нет BOM не написано).[Environment]::CurrentDirectory = $PWD.ProviderPath
, либо, в качестве более общей альтернативы вашему"$(pwd)\..."
подходу (лучше:,"$pwd\..."
даже лучше:"$($pwd.ProviderPath)\..."
или(Join-Path $pwd.ProviderPath ...)
), использовать(Convert-Path BOMthetorpedoes.txt)
U+FEFF
.Можно использовать ниже, чтобы получить UTF8 без спецификации
источник
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»):
Результат ASCII без спецификации.
источник
Default
кодировку, будет использоваться текущая кодовая страница ANSI системы, которая не является UTF-8, как мне требовалось.