#delphi #archive #delphi_xe8
Хочу разархивировать файл(*.zip). В нем содержатся файлы имена которых на русском.
Вот такая конструкция
procedure TWorkThread.ExctractZip(aArchFile: string; aPath: string);
var
zZip: TZipFile;
begin
zZip := TZipFile.Create;
try
zZip.ExtractZipFile(aArchFile, aPath);
finally
FreeAndNil(zZip);
end;
end;
В итоге после разархивации имена этих файлов превращаются в кракозябру Çéè«¡Γα«½∞
αÑßΓ«αá¡δ.pdf
Как это побороть?
Ответы
Ответ 1
К сожалению, формат ZIP не слишком строго стандартизирован (к примеру, Unicode был
официально стандартизирован в только в 2007 году - в спецификации PKWARE 6.3.2). Проблема
даже не только в стандарте, сколько в бесчисленном количестве программ, которые сохраняют
имена как им вздумается - что, в общем-то, не удивительно при такой спецификации.
В частности, существует несколько вариантов хранения имён файлов с символами, выходящими
за рамки ASCII:
ANSI
OEM
CP437 (DOS Latin US)
UTF-8
UTF-8 с флагом
Дополнительное (extra) поле $7075 - стандарт PKWARE/Info-ZIP
Дополнительное (extra) поле - я забыл числовой код, от другой программы
Ужасная мешанина. Что хуже всего - часто нет никакого способа определить метод хранения
имён, кроме ручного указания человеком (первые четыре способа из списка выше программно
неразличимы).
Поиграйтесь с флагом UTF8Support: если поможет - хорошо, если нет - надо или искать
другой распаковщик, или другой упаковщик.
Ответ 2
Нужно изменить стандартный модуль zip.pas.
Проверено на Delphi 10.2.
function TZipFile.TBytesToString(B: TBytes): string;
var
E: TEncoding;
begin
if CyrillicSupport then //условие, нужна ли поддержка кириллицы, можно убрать
E := TEncoding.GetEncoding(866)
else
if FUTF8Support then
E := TEncoding.GetEncoding(65001)
else
E := TEncoding.GetEncoding(437);
try
Result := E.GetString(B);
finally
E.Free;
end;
end;
function TZipFile.StringToTBytes(S: string): TBytes;
var
E: TEncoding;
begin
if CyrillicSupport then //условие, нужна ли поддержка кириллицы, можно убрать
E := TEncoding.GetEncoding(866)
else
if FUTF8Support then
E := TEncoding.GetEncoding(65001)
else
E := TEncoding.GetEncoding(437);
try
Result := E.GetBytes(S);
finally
E.Free;
end;
end;
Ответ 3
Я не специалист по дельфи, но вы можете попробовать стандартные decode-encode с разными
кодировками. Составляете заранее словарик из русских букв и в каждой попытке определить
кодировку побуквенно прогоняете полученное название через словарик. Как только нашли
совпадение - вуаля. Это если проблемы с названием. Также, например, в питоне есть библиотека
chardet, которая определяет кодировку самого файла, а не его названия.