Невозможно изменить кодировку текстовых файлов в Windows - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть несколько текстовых файлов с разными кодировками.Некоторые из них UTF-8, а некоторые другие windows-1251 в кодировке.Я попытался выполнить следующий рекурсивный сценарий для кодирования всего этого в UTF-8.

Get-ChildItem *.nfo -Recurse | ForEach-Object {
$content = $_ | Get-Content

Set-Content -PassThru $_.Fullname $content -Encoding UTF8 -Force}  

. После этого я не могу использовать файлы в своей программе Java, потому что кодировка UTF-8 также имеет неправильную кодировку, я не моглаВерни оригинальный текст.В случае файлов, закодированных в Windows-1251, я получаю пустой вывод, как в случае оригинальных файлов.Таким образом, он делает поврежденными уже файлы в кодировке UTF-8.

Я нашел другое решение, iconv, но, как я вижу, ему нужно текущее кодирование в качестве параметра.

$ iconv options -f from-encoding -t to-encoding inputfile(s) -o outputfile 

Файлы, закодированные по-разномусмешано в структуре папок, поэтому файлы должны оставаться по одному пути.

Система использует кодовую страницу 852. Существующие файлы UTF-8 не имеют спецификации.

1 Ответ

0 голосов
/ 13 ноября 2018

В Windows PowerShell вы не сможете использовать встроенные командлеты по двум причинам:

  • Исходя из того, что ваша кодовая страница OEM является 852 Я предполагаю, что ваша кодовая страница "ANSI" имеет значение Windows-1250 (оба определены в устаревшей локали системы), что не соответствует вашему Windows-1251 кодированному вводу файлы.

  • Использование Set-Content (и аналогичных) с -Encoding UTF8 неизменно создает файлы с BOM (меткой порядка байтов) , что Java и, в более общем смысле, утилиты Unix-наследия не понимают.

Примечание. PowerShell Core по умолчанию имеет значение без спецификации UTF8, а также позволяет передавать любой доступный экземпляр [System.Text.Encoding] параметру -Encoding, поэтому может решить вашу проблему с помощью встроенных командлетов, при этом прямое использование .NET Framework необходимо только для создания экземпляра кодировки.

Поэтому вы должны использовать .NET Framework напрямую:

Get-ChildItem *.nfo -Recurse | ForEach-Object {

  $file = $_.FullName

  $mustReWrite = $false
  # Try to read as UTF-8 first and throw an exception if 
  # invalid-as-UTF-8 bytes are encountered.
  try {
    [IO.File]::ReadAllText($file, [Text.Utf8Encoding]::new($false, $true))
  } catch [System.Text.DecoderFallbackException] {
    # Fall back to Windows-1251
    $content = [IO.File]::ReadAllText($file, [Text.Encoding]::GetEncoding(1251))
    $mustReWrite = $true
  } 

  # Rewrite as UTF-8 without BOM (the .NET frameworks' default)
  if ($mustReWrite) {
    Write-Verbose "Converting from 1251 to UTF-8: $file"
    [IO.File]::WriteAllText($file, $content)
  } else {
    Write-Verbose "Already UTF-8-encoded: $file"
  }

}

Примечание. Как и в вашей собственной попытке, приведенное выше решение считывает каждый файл в память целиком, но это можно изменить.

Примечание:

  • Если входной файл содержит только байты с символами диапазона ASCII (7-разрядными), он по определению также кодируется в UTF-8, поскольку UTF-8 является расширенным набором кодирования ASCII.

  • Весьма маловероятно с реальным вводом, но чисто технически файл в кодировке Windows-1251 может быть также допустимым файлом UTF-8, если битовые комбинации и байтовые последовательности оказываются действительными UTF-8 (который имеет строгие правила относительно того, какие битовые комбинации разрешены где).
    Однако такой файл не будет содержать значимого содержимого Windows-1251.

  • Нет никаких оснований для реализации резервной стратегии декодирования в Windows-1251, поскольку нет технических ограничений на то, какие битовые комбинации могут возникать и где.
    Как правило, в отсутствие внешней информации (или спецификации) не существует простого и надежного способа определить кодировку файла только из его содержимого (хотя может использоваться эвристика).

...