Как я копирую файл с именем файла UTF-8 к другому имени файла UTF-8 в Perl в Windows?

Например, учитывая пустой файл テスト.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 = <)

options:

  -output_relfilepath    set the output relative file path to .
                            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. как ожидалось.

Примечания:

7
задан vlee 21 February 2010 в 00:54
поделиться

3 ответа

Это должно быть возможно с помощью функции CopyFileW из Win32API::File, которая должна быть включена в Strawberry. Я сам никогда не работал с юникодными именами файлов, поэтому не уверен в деталях. Возможно, вам потребуется использовать Encode, чтобы вручную преобразовать имя файла в UTF-16LE (encode('UTF16-LE', $filename)).

3
ответ дан 7 December 2019 в 10:00
поделиться

Вы получаете длинное имя файла, используя Win32, который дает вам строку в кодировке UTF-8.

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

В современных Linux это обычно UTF-8, но в Windows это (к сожалению) никогда не так, потому что системная кодовая страница по умолчанию не может быть установлена в UTF-8. Поэтому на западноевропейской установке Windows строка UTF-8 будет интерпретирована как строка кодовой страницы 1252, как это произошло здесь. (На японской машине она будет интерпретирована как кодовая страница 932 - например, Shift-JIS - и получится что-то вроде 무�せャ�. )

Я не делал этого в Perl, но я подозреваю, что функция Win32::CopyFile, скорее всего, будет способна обрабатывать такие пути Unicode, которые возвращаются в других модулях Win32.

2
ответ дан 7 December 2019 в 10:00
поделиться

Я успешно продублировал вашу проблему на своей машине Windows (Win XP Simplified Chinese version) и пришел к выводу, что проблема вызвана шрифтом. Выберите шрифт Truetype, а не растровые шрифты и посмотрите, все ли в порядке.

Мой эксперимент заключается в следующем:

  1. Сначала я изменил кодовую страницу моей консоли Windows Console со стандартного 936 (GBK) на 65001 (UTF-8). набрав C:>chcp 65001

  2. Я написал скрипт, который содержит код: $a= "テスト"; print $a; и сохранил его в формате UTF-8.

  3. Я запустил скрипт из консоли и обнаружил, что "テスト" превратился в "テã'¹ãƒˆ", что является точно таким же симптомом, который вы описали в своем вопросе.

  4. Я изменил шрифт консоли с Raster Fonts на Lucida Console, на экране консоли появилось следующее: "テストストトト", что все еще не совсем правильно, но я полагаю, что это приближает к сути проблемы.

Так что, хотя я и не уверен на 100%, но проблема, вероятно, вызвана шрифтом.

Надеюсь, это поможет.

0
ответ дан 7 December 2019 в 10:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: