Я написал программу на perl, которая манипулирует (создавать, удалять, открывать, закрывать, читать, записывать, копировать и т. Д. c.) Файлами и каталогами. Это очень хорошо работает при работе на Linux (Ubuntu), а также на macOS. Но он должен выполнять ту же работу и под windows, и там у меня проблемы с кодировкой имен файлов, которые содержат символы, отличные от ASCII (например, немецкие умлауты, но также и любые другие символы, не входящие в ASCII).
Поскольку моя оригинальная программа слишком велика, я создал более короткую программу для тестирования.
Это сокращенный эквивалент моей первой наивной версии моей perl программы (сам файл программы кодируется как UTF- 8):
#!/usr/bin/perl -w
use strict;
use warnings;
my $filename = 'FäöüßÄÖÜẞçàéâœ.txt';
my $text = 'TäöüßÄÖÜẞçàéâœ';
my $dirname = 'DäöüßÄÖÜẞçàéâœ';
# list all files in the parent directory before any action -------------
listDirectory('.');
# create file and write into file --------------------------------------
print "Going to open file $filename for writing ... ";
if (open(my $fileHandle, '>', $filename)) {
print "done successfully\n";
print "Going to write text '$text' into file $filename ... ";
if (print $fileHandle $text."\n") {
print "done successfully\n";
} else {
errorExit("failed to write into file", __LINE__);
}
close($fileHandle);
} else {
errorExit("failed to open file for writing", __LINE__);
}
# create a new directory -----------------------------------------------
print "Going to create directory $dirname ... ";
if (mkdir($dirname)) {
print "done successfully\n";
} else {
errorExit("failed to create directory", __LINE__);
}
# list all files in the parent directory again -------------------------
listDirectory('.');
# read file ------------------------------------------------------------
print "Going to open file $filename for reading ... ";
if (open(my $fileHandle, '<', $filename)) {
print "done successfully\n";
print "Going to list content of file $filename:\n";
print "--- begin of content ---\n";
while (my $row = <$fileHandle>) {
chomp $row;
print "$row\n";
}
print "--- end of content ---\n\n";
close($fileHandle);
} else {
errorExit("failed to open file for reading", __LINE__);
}
# list all files in the newly created directory ------------------------
listDirectory($dirname);
# end ------------------------------------------------------------------
print "normal end of execution\n";
exit(0);
# subroutines ==========================================================
# list all files in a directory ----------------------------------------
sub listDirectory {
my $dir = shift;
my $dirname = $dir eq '.' ? 'parent directory' : $dir;
print "Content of $dirname\n";
if (opendir (my $dirHandle, $dir)) {
print "--- begin of content of $dirname ---\n";
while (my $file = readdir($dirHandle)) {
print "$file\n";
}
print "--- end of content of $dirname ---\n\n";
closedir($dirHandle);
} else {
errorExit("failed to open $dirname", __LINE__);
}
}
# Error exit -----------------------------------------------------------
sub errorExit {
my $message = shift;
my $line = shift;
print "Error before line $line:\n";
print "program message: $message\n";
print "system message: $!\n";
print "premature end of execution\n";
exit(0);
}
Вывод моей программы в macOS и в Linux (Ubuntu):
Content of parent directory
--- begin of content of parent directory ---
.
..
testUmlaut.pl
--- end of content of parent directory ---
Going to open file FäöüßÄÖÜẞçàéâœ.txt for writing ... done successfully
Going to write text 'TäöüßÄÖÜẞçàéâœ' into file FäöüßÄÖÜẞçàéâœ.txt ... done successfully
Going to create directory DäöüßÄÖÜẞçàé✠... done successfully
Content of parent directory
--- begin of content of parent directory ---
.
..
testUmlaut.pl
FäöüßÄÖÜẞçàéâœ.txt
DäöüßÄÖÜẞçàéâœ
--- end of content of parent directory ---
Going to open file FäöüßÄÖÜẞçàéâœ.txt for reading ... done successfully
Going to list content of file FäöüßÄÖÜẞçàéâœ.txt:
--- begin of content ---
TäöüßÄÖÜẞçàéâœ
--- end of content ---
Content of DäöüßÄÖÜẞçàéâœ
--- begin of content of DäöüßÄÖÜẞçàé✠---
.
..
--- end of content of DäöüßÄÖÜẞçàé✠---
normal end of execution
Это ожидаемый вывод.
Но я получите это, когда я выполню эту программу на windows машине:
Content of parent directory
--- begin of content of parent directory ---
.
..
testUmlaut.pl
--- end of content of parent directory ---
Going to open file F├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô.txt for writing ... done successfully
Going to write text 'T├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô' into file F├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô.txt ... done successfully
Going to create directory D├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô ... done successfully
Content of parent directory
--- begin of content of parent directory ---
.
..
testUmlaut.pl
F├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô.txt
D├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô
--- end of content of parent directory ---
Going to open file F├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô.txt for reading ... done successfully
Going to list content of file F├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô.txt:
--- begin of content ---
T├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô
--- end of content ---
Content of D├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô
--- begin of content of D├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô ---
.
..
--- end of content of D├ñ├Â├╝├ƒ├ä├û├£ß║×├º├á├®├ó┼ô ---
normal end of execution
Итак, все имена файлов написаны с неправильной кодировкой. Также в проводнике вы видите неправильно закодированные имена файлов для нового файла и каталога. Но хотя текстовый файл содержит правильное содержимое, моя программа отображает его неправильно.
Итак, я возился с моей программой, пока не получил версию, которая выдает правильный вывод (идентичный выводу первого наивного). версия под macOS и Linux)).
Но в файловой системе имена файлов по-прежнему неверны:
13.01.2020 17:36 <DIR> .
10.01.2020 14:46 <DIR> ..
13.01.2020 18:23 2 970 testUmlaut.pl
13.01.2020 18:23 30 FäöüßÄÖÜẞçà éâœ.txt
13.01.2020 18:23 <DIR> DäöüßÄÖÜẞçà éâœ
Вот код новой версии моей программы:
#!/usr/bin/perl -w
use strict;
use warnings;
use utf8;
use Encode;
if ($^O eq 'MSWin32') {
require Win32::Console;
Win32::Console::OutputCP(65001);
}
binmode STDOUT, ":utf8";
my $filename = 'FäöüßÄÖÜẞçàéâœ.txt';
my $text = 'TäöüßÄÖÜẞçàéâœ';
my $dirname = 'DäöüßÄÖÜẞçàéâœ';
# list all files in the parent directory before any action -------------
listDirectory('.');
# create file and write into file --------------------------------------
print "Going to open file $filename for writing ... ";
if (open(my $fileHandle, '>:encoding(UTF-8)', $filename)) {
print "done successfully\n";
print "Going to write text '$text' into file $filename ... ";
if (print $fileHandle $text."\n") {
print "done successfully\n";
} else {
errorExit("failed to write into file", __LINE__);
}
close($fileHandle);
} else {
errorExit("failed to open file for writing", __LINE__);
}
# create a new directory -----------------------------------------------
print "Going to create directory $dirname ... ";
if (mkdir($dirname)) {
print "done successfully\n";
} else {
errorExit("failed to create directory", __LINE__);
}
# list all files in the parent directory again -------------------------
listDirectory('.');
# read file ------------------------------------------------------------
print "Going to open file $filename for reading ... ";
if (open(my $fileHandle, '<:encoding(UTF-8)', $filename)) {
print "done successfully\n";
print "Going to list content of file $filename:\n";
print "--- begin of content ---\n";
while (my $row = <$fileHandle>) {
chomp $row;
print "$row\n";
}
print "--- end of content ---\n\n";
close($fileHandle);
} else {
errorExit("failed to open file for reading", __LINE__);
}
# list all files in the newly created directory ------------------------
listDirectory($dirname);
# end ------------------------------------------------------------------
print "normal end of execution\n";
exit(0);
# subroutines ==========================================================
# list all files in a directory ----------------------------------------
sub listDirectory {
my $dir = shift;
my $dirname = $dir eq '.' ? 'parent directory' : $dir;
print "Content of $dirname\n";
if (opendir (my $dirHandle, $dir)) {
print "--- begin of content of $dirname ---\n";
while (my $file = decode_utf8(readdir($dirHandle))) {
print "$file\n";
}
print "--- end of content of $dirname ---\n\n";
closedir($dirHandle);
} else {
errorExit("failed to open $dirname", __LINE__);
}
}
# Error exit -----------------------------------------------------------
sub errorExit {
my $message = shift;
my $line = shift;
print "Error before line $line:\n";
print "program message: $message\n";
print "system message: $!\n";
print "premature end of execution\n";
exit(0);
}
Эта новая версия по-прежнему работает хорошо при работе в Linux или macOS. Но все еще есть проблема с именами файлов в Windows.
Как я могу это исправить?