例如,给定一个空文件テスト.txt
,我如何制作一个名为テスト.txt.copy
的副本?
我的第一次破解设法访问该文件并创建新文件名,但副本生成テスト.txt.copy
。
这是我的第一次破解:
#!/usr/bin/env perl
use strict;
use warnings;
use English '-no_match_vars';
use File::Basename;
use Getopt::Long;
use File::Copy;
use Win32;
my (
$output_relfilepath,
) = process_command_line();
open my $fh, '>', $output_relfilepath or die $!;
binmode $fh, ':utf8';
foreach my $short_basename ( glob( '*.txt') ) {
# skip the output basename if it's in the glob
if ( $short_basename eq $output_relfilepath ) {
next;
}
my $long_basename = Win32::GetLongPathName( $short_basename );
my $new_basename = $long_basename . '.copy';
print {$fh} sprintf(
"short_basename = (%s)\n" .
" long_basename = (%s)\n" .
" new_basename = (%s)\n",
$short_basename,
$long_basename,
$new_basename,
);
copy( $short_basename, $new_basename );
}
printf(
"\n%s done! (%d seconds elapsed)\n",
basename( $0 ),
time() - $BASETIME,
);
# === subroutines ===
sub process_command_line {
# default arguments
my %args
= (
output_relfilepath => 'output.txt',
);
GetOptions(
'help' => sub { print usage(); exit },
'output_relfilepath=s' => \$args{output_relfilepath},
);
return (
$args{output_relfilepath},
);
}
sub usage {
my $script_name = basename $0;
my $usage = <<END_USAGE;
======================================================================
Test script to copy files with a UTF-8 filenames to files with
different UTF-8 filenames. This example tries to make copies of all
.txt files with versions that end in .txt.copy.
usage: ${script_name} (<options>)
options:
-output_relfilepath <s> set the output relative file path to <s>.
this file contains the short, long, and
new basenames.
(default: 'output.txt')
----------------------------------------------------------------------
examples:
${script_name}
======================================================================
END_USAGE
return $usage;
}
以下是执行后output.txt
的内容:
short_basename = (BD9A~1.TXT)
long_basename = (テスト.txt)
new_basename = (テスト.txt.copy)
我尝试用系统调用替换File::Copy的复制命令:
my $cmd = "copy \"${short_basename}\" \"${new_basename}\"";
print `$cmd`;
并使用Win32 :: CopyFile:
Win32::CopyFile( $short_basename, $new_basename, 'true' );
不幸的是,我在两种情况下得到了相同的结果(テスト.txt.copy
)。对于系统调用,打印按预期显示1 file(s) copied.
。
注意:
答案 0 :(得分:3)
使用CopyFileW中的Win32API::File功能应该可以实现这一点,这应该包含在草莓中。我自己从来没有弄乱过Unicode文件名,所以我不确定细节。您可能需要使用Encode手动将文件名转换为UTF-16LE(encode('UTF16-LE', $filename)
)。
答案 1 :(得分:2)
您使用Win32
获取长文件名,它会为您提供UTF-8编码的字符串。
但是,您使用普通copy
设置长文件名,它使用C stdlib IO功能。 stdlib函数使用默认的文件系统编码。
在现代的Linux上,通常是UTF-8,但在Windows上(遗憾的是)从来都不是,因为系统默认代码页不能设置为UTF-8。因此,您将在西欧Windows安装中将UTF-8字符串解释为代码页1252字符串,如此处所示。 (在日本的机器上,它被解释为代码页932 - 就像Shift-JIS一样 - 它会像繝�せ繝�
那样出现。)
我在Perl中没有这样做,但是我怀疑Win32::CopyFile
函数更有可能处理Win32
模块中其他位置返回的Unicode路径。< / p>
答案 2 :(得分:1)
use Encode::Locale;
use Encode;
use File::Copy;
copy( encode(locale_fs => $short_basename),
encode(locale_fs => $new_basename) ) || die $!;
答案 3 :(得分:0)
我在Windows机器上成功复制了你的问题(Win XP简体中文版),我的结论是问题是由字体引起的。选择Truetype字体而不是Raster字体,看看是否一切正常。
我的实验是:
我首先将Windows控制台的代码页从默认的936(GBK)更改为65001(UTF-8)。 输入C:&gt; chcp 65001
我写了一个包含代码的脚本:$ a =“テスト”;打印$ a;并将其保存为UTF-8。
我从控制台运行脚本,发现“テスト”变成了“テã,¹ƒƒ”,这与您在问题中描述的完全相同。
我将控制台字体从光栅字体更改为Lucida控制台,控制台屏幕给了我:“テストストトト”,这仍然不太正确,但我认为它越来越接近问题的核心。 / p>
所以虽然我不是100%肯定,但问题可能是由字体引起的。
希望这有帮助。
答案 4 :(得分:0)
请参阅https://metacpan.org/pod/Win32::Unicode
#!/usr/bin/perl --
use utf8;
use strict;
use warnings;
my @kebabs = (
"\x{45B}\x{435}\x{432}\x{430}\x{43F}.txt", ## ћевап.txt
"ra\x{17E}nji\x{107}.txt", ## ražnjić.txt
"\x{107}evap.txt", ## ćevap.txt
"\x{43A}\x{435}\x{431}\x{430}\x{43F}\x{447}\x{435}.txt", ## кебапче.txt
"kebab.txt",
);
{
use Win32::Unicode qw/ -native /;
printW "I \x{2665} Perl"; # unicode console out
mkpathW 'meat';
chdirW 'meat';
for my $kebab ( @kebabs ){
printW "kebabing the $kebab\n";
open my($fh), '>:raw', $kebab or dieW Fudge($kebab);
print $fh $kebab or dieW Fudge($kebab);
close $fh or dieW Fudge($kebab);
}
}
sub Fudge {
use Errno();
join qq/\n/,
"Error @_",
map { " $_" } int( $! ) . q/ / . $!,
int( $^E ) . q/ / . $^E,
grep( { $!{$_} } keys %! ),
q/ /;
}