[Perl] Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略

环境 XP/WIN7 Perl v5.16

编辑整理:PerlMonk、523066680

常见的那些文件操作函数都不支持,于是为了达到目的,需要各种方法配合,应该是不如其他语言方便。

我只是想看看Perl到底是否适合做这件事,于是折腾了一回。

文件的建立:

模块:Win32
Code: [全选] [展开/收缩] [Download] (example.pl)
use Win32;
use utf8;
use Encode; #接受unicode传参
Win32::CreateFile("W32CreateFile・测试");
特性: 成功返回true,但不返回文件句柄
Creates the FILE and returns a true value on success.
Check $^E on failure for extended error information. 模块:Win32API::File
函数:$hObject= CreateFileW( $swPath, $uAccess, $uShare, $pSecAttr, $uCreate, $uFlags, $hModel )
$hObject可以返回文件对象句柄
注意事项: 传入的文件路径的编码格式为:UTF16-LE ,必须以\x00结尾,示例(代码保存为utf8格式):
Code: [全选] [展开/收缩] [Download] (example.pl)
use Win32API::File qw(:ALL);
use utf8;
use Encode;
$str="文tes・t.txt\x00";
$hobject=CreateFileW(encode('UTF16-LE', $str), GENERIC_WRITE, 0, [], OPEN_ALWAYS,0,0);

目录的建立

模块:Win32
Code: [全选] [展开/收缩] [Download] (example.pl)
use Win32;
use utf8; Win32::CreateDirectory("Dir・测试");

文件的枚举

在遇到unicode字符的时候,File::Find模块 以及 IO::Dir 模块都只能输出文件短名。
暂时用CMD /U Dir 的方法输出文件列表(郁闷吧,暂时没找到能完美操作的内置模块)
参考文章
http://www.perlmonks.org/?node_id=536223
how to read unicode filename

复制某个文件夹内的文件(文件名含unicode字符)

模块:Win32API::File
如果先获取文件的短名,然后再复制,但是目标文件名也会变成短名。
于是暂时用cmd /U 模式获取文件列表,然后CopyFileW进行复制:
Code: [全选] [展开/收缩] [Download] (example.pl)
use Win32API::File qw':ALL';
use Encode;
use utf8; my $src=encode('gbk','.\\测试目录');
my $dst='.\\Target'; #该目录只有一层,/s开关是为了列出完整的路径
my $all=`cmd /U /C dir /s /b \"$src\"`;
my $fn; foreach (split(/\x0d\x00\x0a\x00/, $all)) {
$fn = encode('gbk', decode('utf16-le',$_))."\n";
@xrr=split(/\x5c\x00/, $_);
CopyFileW(
$_ ."\x00",
encode('utf-16le', decode('utf8', "$dst\\")).$xrr[$#xrr]."\x00",
1
);
print "$^E\n" if ($^E);
}
<STDIN>;
细节一、
正确地使用 split $all 截断utf-16le字符段落,分隔符为0d 00 0a 00
参考枚举脚本 细节二、
如果用basename()分割路径,同样会遇到00被忽略的问题,'\\' 的U16LE
编码是5C 00,但是basename 只按5C截断,剩下的00造成了处理乱码。 测试basename的第二个参数设置为 "\x5c\x00" 并不能解决这个问题
解决方法一、
手工去掉开头处00
方法二、
先转为GBK,再获取basename,再转utf-16le
2014-12-12 备注这种方法在LongPath的情况下,会丢失unicode字符
可以考虑转为UTF-8,不管怎么说都有点绕
方法三、
自己用正则表达式获取
/\x5C\x00([^\x5c]+)$/;
$1
方法四、
@xrr=split(/\x5c\x00/, $_);
$xrr[$#xrr] 细节三、
CopyFileW复制文件时,要在末尾加\x00作为字符串终止符
否则各种问题=_=

判断文件是否存在:

方法一:先转为短名再判断,不做赘述
方法二:渣方法,用CreateFileW测试建立同名文件,看是否有冲突

重命名:

模块:Win32API::File
Code: [全选] [展开/收缩] [Download] (example.pl)
MoveFileW(
encode('utf-16le', decode('utf8',$F))."\x00",
encode('utf-16le', decode('utf8',$newname))."\x00"
);

获取文件的日期信息:

普通文件名的情况
http://stackoverflow.com/questions/1839877/
how-can-i-get-a-files-modification-date-in-ddmmyy-format-in-perl 含有Unicode字符的文件名的情况
http://www.perlmonks.org/?node_id=741797
How to stat a file with a Unicode (UTF16-LE) filename in Windows?
其中的方法是通过createfileW 获取文件句柄,然后用OsFHandleOpen获取通用的文件句柄对象,并传入state
(感觉特别绕) 另一种就是先转为短名再获取日期,但是这种方法在处理文件量大的时候,效率非常低。前面perlmonks中的方法
效率要高得多
Code: [全选] [展开/收缩] [Download] (example.pl)
use utf8;
use Encode;
use Win32; $filename='D:\测试目录\董贞 ・ 01.剑如虹.[贞江湖].mp3';
$filename=Win32::GetShortPathName($filename); my $mtime = (stat $filename)[9];
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($mtime);
$year+=1900;
$mon+=1;
print "$year-$mon-$mday\n";
<STDIN>;

=补充=====

tigerpower 推荐了 Win32::Unicode

我以前执着于用自带的模块做文件系统的事情,现在想想真没必要,应该怎么方便怎么来。

这里重新补充

http://bbs.bathome.net/redirect.php?goto=findpost&ptid=34881&pid=168889&fromuid=3337

代码: 全选

use Win32::Unicode;

use utf8;

my $dirname="CreateDir・测试";

my $dirname_long="CreateDir・测试1/CreateDir・测试2/CreateDir・测试3";

my $dirname_new="CreateDir・测试・新";

my $filename="CreateFile・测试";

mkdirW $dirname;

chdirW $dirname;

mkpathW $dirname_long;

$fh = Win32::Unicode::File->new('>', $filename);

$fh->close;

chdirW $dirname_long;

touchW $filename.'1';

chdirW '../../../..';

cptreeW $dirname.'/',$dirname_new;

[Perl]Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略的更多相关文章

  1. Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略

    常见的那些文件操作函数都不支持,于是为了达到目的,需要各种方法配合,应该是不如其他语言方便.我只是想看看Perl到底是否适合做这件事,于是折腾了一回. 文件的建立: 模块:Win32 Code: [全 ...

  2. delphi 文件的操作:重命名、复制、移动、删除

    Delphi 文件的操作:重命名.复制.移动.删除第一种方法: RenameFile('Oldname', 'Newname'); CopyFile(PChar('Oldname'), PChar(' ...

  3. linux下的文件操作——批量重命名

    概述:在日常工作中,我们经常需要对一批文件进行重命名操作,例如将所有的jpg文件改成bnp,将名字中的1改成one,等等.文本主要为你讲解如何实现这些操作 1.删除所有的 .bak 后缀: renam ...

  4. Windows系统,文件和文件夹命名规则:

    不能包含:< > / \ | : * ? windows中,文件名(包括扩展名)可高达 个字符.文件名可以包含除 ? “ ”/ \ < > * | : 之外的大多数字符:保留文 ...

  5. 【转】Perl Unicode全攻略

    Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...

  6. Perl Unicode全攻略

    Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...

  7. 2.3《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——重命名,复制,删除

    最常用的文件操作除了将文件列出来外,就应该是重命名,复制,删除了.正如将文件列出来一样,大多数现代操作系统为这些任务提供了用户图形界面,但是在许多场景中,用命令行还是会更方便. 使用mv命令重命名一个 ...

  8. linux 下文件重命名/移动/复制命令(转)

    linux 下文件重命名/移动/复制命令(转) linux下重命名文件:使用mv命令就可以了, 例:要把名为:abc   重命名为:123 可以这样操作: 重命名:MV命令 1.进入你的文件目录,运行 ...

  9. Windows Socket五种I/O模型——代码全攻略(转)

    Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模式.可以通过多线程技术进行处理. 非阻塞模式:执行I/O操 ...

随机推荐

  1. nginx实现多个域名共享80端口

    server { listen 80; server_name server8085.duchong.cn; location / { proxy_pass http://127.0.0.1:8085 ...

  2. hibernate相关方法

    uniqueResult() 当确定返回的实例只有一个或者null时 用uniqueResult()方法 代码示例: Session session = factory.openSession(); ...

  3. <转>杜绝 Defunct进程 僵尸进程

    http://hanover.iteye.com/blog/881972 在测试基于 DirectFB+Gstreamer 的视频联播系统的一个 Demo 的时候,其中大量使用 system 调用的语 ...

  4. java动态规划取硬币问题

    最近一直在研究动态规划的问题.今天遇到了取硬币问题. 其实动态规划还是,我从底部向顶部,依次求出每个状态的最小值,然后就可以标记上. 这道题目就是,假如有1,5,7,10这四种币值的硬币,我取14元, ...

  5. zabbix主机自动注册

    一.主机自动注册的流程 zabbix agent指定server active主动自己的信息提供给zabbix_server,zabbix_server根据提供的信息自动添加主机,方便. 二. lin ...

  6. 无法访问windows安装服务。发生这种情况的可能是您在安全模式下运行windows,或是没有正确安装windows安装,。请与技术支持人员联系以获得帮助。

    解决办法: 1.命令提示符下输入:msiexec/regserver 2.在“管理工具”→“服务”中启动windows Installer 程序员的基础教程:菜鸟程序员

  7. scala的隐式转换

    摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码.   使用方式: 1. ...

  8. 以二进制的形式查看文件 Linux之od命令详解

    od命令 以二进制的形式查看文件 od -t x1 /usr/local/FT/config/hsm_create.utf8.sql ef bb bf 4c 5f 0d 0a 5f 4e 4e 4f ...

  9. poj 2007 Scrambled Polygon

    #include<stdio.h> #include<algorithm> using namespace std; #define Max 60 struct Point { ...

  10. 不设置环境变量 直接启动tomcat

    window: 设置 startup.bat set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_144set JRE_HOME=C:\Program Files ...