【问题标题】:How can I copy files with special characters in their names with Perl's File::Copy?如何使用 Perl 的 File::Copy 复制名称中带有特殊字符的文件?
【发布时间】:2010-09-21 16:10:24
【问题描述】:

我正在尝试将一个位置的所有文件复制到另一个位置,并使用 File::Copy 模块和 copy 来自该位置的命令,但现在我面临的问题是我有一个名称为 @987654326 的文件@ 其 ascii 值为 &#253 但在 unix 文件系统中它存储为 ? 所以我的问题是 copy or move command 在复制或移动到另一个位置时是否会考虑这些带有特殊字符的文件, 如果现在,那么可能的解决方法是什么?

注意: 我无法在 unix 中创建带有特殊字符的文件,因为特殊字符被替换为 ?,而在 Windows 中我不能这样做,因为在 Windows 上,特殊字符被替换为编码值,如我的&#253 案例?

my $folderpath = 'the_path';
open my $IN, '<', 'path/to/infile';
my $total;
while (<$IN>) {
    chomp;
    my $size = -s "$folderpath/$_";
    print "$_ => $size\n";
    $total += $size;
}
print "Total => $total\n";

礼貌:RickFAnswer

任何建议将不胜感激。

参考问题Perl File Handling Question

【问题讨论】:

  • 您是从 Unix 复制到 Windows 吗?如果是这样,您还需要处理在 Unix 上合法但在 Windows 上不合法的字符。举个极端的例子,“\n”是 Unix 文件名中的合法字符。
  • 是的。我正在从 unix 复制到 windows。
  • @Ether:我无法获取带有特殊字符的文件大小。
  • 投反对票通常是有理由的,请提供理由以便我改进问题。
  • 您能否使用“?”访问该文件而不是转义码或特殊字符?

标签: perl file special-characters


【解决方案1】:

作为解决方法,我可以建议将所有不受支持的字符转换为受支持的字符。这可以通过多种方式完成。例如你可以使用URI::Escape:

use URI::Escape;
my $new_file_name = uri_escape($weird_file_name);

更新:

这是我如何通过 uft-8 名称复制文件的方法。我在 Windows 上。我使用Win32::GetANSIPathName 来获取短文件名。然后它被很好地复制了:

use File::Copy;
use URI::Escape;
use Win32;

use utf8; ## tell perl that source code is in utf-9
use strict;
use warnings;

my $test_file = "IBMýSoftware.txt";
my $from_file = Win32::GetANSIPathName($test_file); ## get "short" name of file
my $to_file   = uri_escape($test_file); ## name with special characters escaped

printf("copy [%s] -> [%s]\n", $from_file, $to_file);
copy($from_file, $to_file);

在 Windows 上将所有文件复制为新名称后,您将能够在 linux 上毫无问题地使用它们。

以下是一些关于打开 utf-8 文件的提示:

【讨论】:

  • 我尝试在我的脚本中使用它,但是当我运行我的脚本时,它只是排除了具有非常奇怪的特殊字符的文件,有什么想法吗?
  • @Rachel 我猜脚本无法使用转换后的名称创建文件。你能举一个uri_escape函数调用后文件名失败的例子吗?
  • 63551_106640_63551 IBMýSoftware Delivery&amp;Fulfillment(Div-61) Data IPS 08-20-2010 v3.xlsm
  • @Ivan:你能解释一下printf and copy相关的命令语句以及它是如何工作的,因为我很难理解程序流程。
  • 我已更改变量名称以获得更清晰的代码。 printf 仅用于调试目的。主要思想是文件的“短”名称(使用Win32::GetANSIPathName)可以毫无问题地用于复制/打开具有utf-8名称的文件。但它是 Windows 唯一的解决方案。接下来我建议你生成没有特殊字符的新名称(使用uri_escape)。将文件复制到新名称后,您可以毫无问题地对其进行操作。
【解决方案2】:

字符 253 是ý。我猜想在你的 Unix 系统上 locale 没有设置,或者只有最原始的后备语言环境有效,这就是你看到替换字符的原因。如果我猜对了,解决方案是简单地设置语言环境,最好设置为 UTF-8 语言环境,因为它可以处理所有字符,而 Perl 甚至不应该出现问题。

> cat 3761218.pl
use utf8;
use strict;
use warnings FATAL => 'all';
use autodie qw(:all);

my $file_name = '63551_106640_63551 IBMýSoftware Delivery&Fulfillment(Div-61) Data IPS 08-20-2010 v3.xlsm';
open my $h, '>', $file_name;

> perl 3761218.pl
> ls 6*
63551_106640_63551 IBMýSoftware Delivery&Fulfillment(Div-61) Data IPS 08-20-2010 v3.xlsm
> LANG=C ls 6* # temporarily cripple locale so that the problem in the question is exhibited
63551_106640_63551 IBM??Software Delivery&Fulfillment(Div-61) Data IPS 08-20-2010 v3.xlsm
> locale | head -1 # show which locale I have set
LANG=de_DE.UTF-8

【讨论】:

  • 您能否详细说明一下,尤其是您为什么使用两个 perl 文件以及如何在 Unix 中设置语言环境?
  • 我只使用一个 Perl 文件。 – 我不知道您使用的是哪个 Unix,所以我无法给出一个好的答案。但是,您可以自己轻松获得答案。搜索 Serverfault archives 或使用任何通用 Web 搜索引擎(例如 Google)来查找您需要的文档。
  • 我无法理解 LANG=C ls 6*locale | head -1 LANG=de_DE.UTF-8 中发生的事情,您能否在代码中提供一些 cmets 来解释这种情况,因为它有助于我学习和学习从中得到更好的理解。
  • 好的,我添加了一些 cmets。使用变量赋值为普通命令添加前缀没什么特别的,这是 shell 编程基础。阅读更多教程或书籍:oreilly.com/catalog/9780596009656
  • 嗯...感谢 Daxim 的更新,所以基本上只有通过将语言环境设置为 UTF-8 才能解决问题,我的脚本将能够使用特殊字符获取文件的大小它无法这样做。
【解决方案3】:

以下脚本按预期工作:

#!/usr/bin/perl

use strict; use warnings;
use autodie;

use File::Copy qw( copy );
use File::Spec::Functions qw( catfile );

my $fname = chr 0xfd;

open my $out, '>', catfile($ENV{TEMP}, $fname);
close $out;

copy catfile($ENV{TEMP}, $fname) => catfile($ENV{HOME}, $fname);

【讨论】:

  • 我无法理解该脚本,如果您在其中添加一些 cmets 将不胜感激。
  • @Rachel 该脚本创建一个文件,其名称仅由字符代码为 253 的单个字符组成。然后,将该文件从我的临时目录复制到我的主目录。
  • 问题中提到的脚本打印所有文件的大小,但如果文件有一些特殊字符,它会忽略它们,令我惊讶的是,#,@,$ 被脚本占用,它确实给了我大小但不考虑ý,我很难理解为什么会这样,想知道您对此的看法,或者您是否可以指导我进行一些适当的阅读,我将不胜感激。
  • Unur:我试图理解指令流,如果可能的话,如果你能在代码本身中添加更多的 cmets 那就太好了,这样我就可以更好地理解它是如何工作的,这会有所帮助我。
猜你喜欢
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-04-17
  • 2018-11-09
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
相关资源
最近更新 更多