Тема: CMD/BAT: Перекодировка текстовых файлов
CMD/BAT: перекодировка текста dos866&↔win1251:
Есть немало консольных утилит для перекодировки текста, но многие забывают про встроенные возможности.
Ещё до создания указанной темы я думал над решением этого вопроса теми же средствами и тоже дальше построчной обработки файлов пойти не смог. А хотелось бы обработать весь файл одним махом, что-то наподобие
chcp XXX
type in.txt>out.txtНе обязательно совсем так просто: допускалась, например, необходимость нескольких вложенных вызовов CMD.EXE — главное, обойтись небольшим числом обращений к утилите CHCP.COM, а не дёргать её для каждой строки. К сожалению, мне ничего не удалось, хотя я по прежнему допускаю существование решения на этом пути.
Так что решение от 01MDM имеет полное право на существование в Коллекции, хотя и не лишено недостатков, как неустранимых (FOR /F пропускает пустые строки; есть сложности со спецсимволами вплоть до угрозы инъекции кода), так и устранимых, которые следовало бы убрать, подправив тему без создания новых сообщений (не помню, то ли не обрабатываются пробелы в начале строк, то ли непустые строки не содержащие ничего кроме пробелов). Но сейчас речь не об этом.
То что не получилось одним махом (командой TYPE) можно сделать двумя: перекодировкой исходного файла в промежуточный файл в UTF-16, а затем промежуточного — в файл в нужной кодировке. В качестве кодировок исходного и конечного файла могут быть любые однобайтные кодировки, а также UTF-8 без BOM. В основе такого решения лежит соединение вместе уже упоминавшихся мною приёмов по перекодировке файлов в/из UTF-16 с помощью команды TYPE.
Вот пример (без необходимых в полевых условиях проверок), раскрывающий эту мысль (этот код содержит непечатные знаки, не копируйте его, а берите из присоединённого файла!):
@echo off
set /p IN=Исходный файл:
set /p IN_CP=Его кодировка:
set /p OUT=Выходной файл:
set /p OUT_CP=Желаемая кодировка:
for /f "tokens=2 delims=:" %%i in ('chcp.com') do set CP=%%i
::в следующей строке выводятся байты \xFF\xFE (BOM):
set /p p= ■<nul >utf-16.tmp
(
chcp.com %IN_CP%>nul
cmd.exe /u /c type %IN%>>utf-16.tmp
chcp.com %OUT_CP%>nul
cmd.exe /c type utf-16.tmp>%OUT%
chcp.com %CP%>nul
)
del utf-16.tmp
Может возникнуть вопрос: зачем здесь несколько команд объединены круглыми скобками в одну составную?
Отвечаю: В качестве кодировки как входного так и выходного файлов могут выступать не только однобайтные кодировки, но и UTF-8 (кодовая страница 65001), а работа командных файлов при переключении на неё, по крайней мере в более ранних изданиях Windows, например в XP, имеет одну неприятную особенность — они тихо завершают работу на следующей же команде, но текущая (в том числе, составная) команда всё-таки выполняется и если в конце неё переключится обратно на однобайтную кодировку, то вылета не произойдёт. Но переключение кодировок в составной команде не влияет на входящие в неё внутренние команды обработчика, поэтому, чтобы воспользоваться её плодами, необходимо команду вызывать через новую копию CMD.EXE с ключом /C. Это одна из причин, по которой таким образом вызывается вторая TYPE, но, собственно говоря, её всё равно следовало бы вызывать таким образом, если учесть исчезающе малую возможность, что командный файл вызван из CMD.EXE, уже запущенного с ключом /U (на самом деле, для полного учёта такой возможности следовало бы добавить ещё «cmd.exe /c » в начало строки c выводом BOM).
Еще по поводу UTF-8: Если она используется во входном файле, то он не должен содержать BOM, иначе в начале выходного будет лишний символ и как его обрезать мне на ум не приходит. Если она используется для выходного файла, то он создаются без BOM, но это легко обойти тем же путем что и при создании промежуточного файла в UTF-16.
(Что-то похожее мною уже затрагивалось.)
___
2025-12-14: Предложенный пример был проверен мною в Windows XP и без изменений не будет работать в более новых выпусках Windows. Добавил к теме сообщение о причине неработоспособности и её несложном устранении.

