Есть ли способ проверить кодировку файлов с помощью сценария установки или пакета?

Есть ли способ с помощью сценария установки / пакета Windows / PowerShell, чтобы я мог проверить, является ли файл UTF-8, прежде чем передавать его для преобразования?

В качестве фона я в настоящее время работаю над устаревшим (японским) программным обеспечением Windows, разработанным с помощью Visual Studio 2005 (обновленного до Visual Studio 2017) на C ++.

Я имею дело с требованием, чтобы графический интерфейс мог отображать и вводить китайские символы. Таким образом было принято решение использовать UNICODE для кодирования проекта / решения.

Поскольку изначально в проекте использовался многобайтовый формат, для обеспечения обратной совместимости с UNICODE я решил закодировать файлы конфигурации (ini, dat, save файлы) в UTF-8, поскольку на эти файлы также ссылается веб-приложение.

Основные части программного обеспечения теперь готовы и работают, и у меня осталась одна последняя проблема - развертывание установщика более высокой версии.

В этом установщике (с помощью сценария установки) мне необходимо обновить файлы сохранения (ранее закодированные в SHIFT-JIS, поскольку эти файлы сохранения содержат текст на японском языке) до UTF-8.

Я уже создал командный файл в следующих строках, который преобразует SHIFT-JIS в UTF-8, который вызывается в последней части установщика и удаляется после преобразования.

@echo off
:: Shift_JIS -> UTF-8
setlocal enabledelayedexpansion
for %%f in ("%~dp0\savedfiles\*.sav") do (
    echo %%~ff| findstr /l /e /i ".sav"
      if !ERRORLEVEL! equ 0 (
        powershell -nop -c "&{[IO.File]::WriteAllText($args[1], [IO.File]::ReadAllText($args[0], [Text.Encoding]::GetEncoding(932)))}" \"%%~ff"  \"%%~ff" 
      )
)

Однако проблема заключается в том, что когда пользователь (1) обновляет, (2) удаляет (файлы .sav намеренно оставляются) и (3) повторно устанавливает программное обеспечение, файлы сохранения дважды перекодируются, что приводит к сбой программного обеспечения. (Японские символы UTF-8, обновленные во время (1) обновления, становятся символами мусора после (3) повторной установки.)


person Wolf    schedule 28.09.2020    source источник
comment
Нет ничего особенного в наборе байтов, который должен представлять текст, указывающий, какую кодировку он использует. Вы должны отслеживать это каким-то другим способом.   -  person Sam Varshavchik    schedule 28.09.2020
comment
Чтобы получить ответ, я рекомендую посмотреть A: Как определить UTF-8 на простом C?, в частности ту часть, которая предлагает добавить идентификатор начала файлов. В вашем случае вам нужно будет выбрать что-то, что обычно не запускает ваши файлы .sav. Если вы думаете наперед, вы можете выбрать последовательность байтов, в которой говорится, что у этого файла есть заголовок, за которым следует байтовая или байтовая последовательность, в которой говорится, что я UTF-8, потому что будущие изменения могут потребовать дополнительных идентификаторов. (Может ли это быть дубликатом? Знание, что альтернатива - японский, может вызвать другие ответы.)   -  person JaMiT    schedule 28.09.2020
comment
Спасибо @JaMiT, я обновил вопрос. На самом деле я изначально создал аналогичный простой файл .exe, который проверяет спецификацию UTF-8 и возвращает простое значение true или false, но, к сожалению, спецификация вызывает проблемы с отображением в части веб-приложения. Я подумал, что причиной была эта статья: w3.org/International /questions/qa-utf8-bom.en.html. Я изучу другие решения в этой ветке, это очень помогает.   -  person Wolf    schedule 28.09.2020
comment
@Wolf Да, вам также придется обновить код приложения, которое считывает данные, чтобы учесть заголовок.   -  person JaMiT    schedule 28.09.2020
comment
Некоторые подсказки не по теме: %~dp0 заменяется на путь к папке, всегда заканчивающийся обратной косой чертой. По этой причине никогда не объединяйте %~dp0 с дополнительным \ с именем файла / папки или шаблоном подстановки, так как это приводит к двум обратным косым чертам в полной строке аргумента, которые Windows должна исправить позже. Не используйте f в качестве переменной цикла, хотя это возможно, особенно при использовании модификатора типа ~f. Есть достаточно других символов, которые не являются модификаторами, доступных для использования в качестве переменной цикла. Отложенное расширение не требуется при использовании if not errorlevel 1 вместо if !ERRORLEVEL! equ 0.   -  person Mofi    schedule 28.09.2020
comment
Таким образом, командная строка setlocal enabledelayedexpansion может быть заменена на setlocal EnableExtensions DisableDelayedExpansion с использованием if not errorlevel 1 внутри цикла for, что приводит к тому, что полные имена файлов, содержащие где-либо один или несколько !, обрабатываются также правильно, что не относится к включенному отложенному расширению только из-за условия if не используя рекомендуемый синтаксис, как описано в выводе команды IF при запуске if /? в окне командной строки. Кстати: if not errorlevel 1 означает ЕСЛИ УРОВЕНЬ ОШИБКИ МЕНЬШЕ 1, что в общем случае ЕСЛИ УРОВЕНЬ ОШИБКИ РАВНО 0.   -  person Mofi    schedule 28.09.2020
comment
почему спецификация вызывает проблемы с отображением в части веб-приложения? Любой веб-браузер или веб-движок должен без проблем обрабатывать спецификацию   -  person phuclv    schedule 28.09.2020
comment
проверьте это - github.com/npocmaka/batch.scripts/blob / master / fileUtils /   -  person npocmaka    schedule 28.09.2020


Ответы (1)


Если вы обновляетесь, все текущие файлы должны быть в Shift-JIS. Даже если в некоторых ситуациях одновременно остаются файлы Shift-JIS и UTF-8, вам нужно обработать только 2 типа кодировок. Поэтому вы можете обойти это, проверив, является ли файл недопустимым UTF-8, а затем Shift-JIS. Конечно, в некоторых редких случаях это все равно будет неправильно обнаруживаться, но в противном случае это может быть полезно для вашего варианта использования.

По умолчанию при чтении текстовых файлов лучше всего -fit используется резервный или замещающий резервный обработчик. Мы можем перейти на резервное исключение, поэтому будет выдано исключение, если файл Shift-JIS открыт как UTF-8

try {
    $t = [IO.File]::ReadAllText($f, [Text.Encoding]::GetEncoding(65001, `
         (New-Object Text.EncoderExceptionFallback), `
         (New-Object Text.DecoderExceptionFallback)))
} catch {
    # File is not UTF-8, reopen as Shift-JIS
    $t = [IO.File]::ReadAllText($f, [Text.Encoding]::GetEncoding(932))
}

# Write the file as UTF-8
[IO.File]::WriteAllText($f, $t)

Лучше просмотреть файлы и преобразовать их в PowerShell. Если вам действительно нужно использовать пакетный файл, оберните все в файл * .ps1 и вызовите его из пакетного файла.

person phuclv    schedule 28.09.2020
comment
Различие между ASCII и UTF-8 искусственно. ASCII является допустимым UTF-8. - person IInspectable; 28.09.2020
comment
@Inspectable Я знаю. Я имею в виду, что в Shift-JIS может существовать какая-то последовательность, которая также действительна в UTF-8, но я не могу подтвердить, так как не знаю, как Shift-JIS кодирует значения. - person phuclv; 28.09.2020