[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. Java ArrayList的不同排序方法

    本文由 ImportNew - 温布利往事 翻译自 dzone.欢迎加入翻译小组.转载请见文末要求. 由于其功能性和灵活性,ArrayList是 Java 集合框架中使用最为普遍的集合类之一.Arra ...

  2. GameObject.DestroyImmediate(go, true)会使磁盘资源数据丢失,导致不可用

    GameObject.DestroyImmediate(go, true)会使磁盘资源数据丢失,导致不可用 第二个参数true表示 allowDestroyingAssets,表示允许销毁资源. 实测 ...

  3. 【302】C# TreeView 控件使用说明

    参考:C# 中treeview 树节点图标的动态加载,及选中时图标改变 参考:C# TreeView 控件的综合使用方法 参考:TreeView 类 参考:TreeNode 类 1. 添加根和子级 通 ...

  4. ubuntu 安装 rtpengine

    摘要 RtpEngine推荐使用Debian系统,可以看出Debian系统的安装是最简单的.我是基于ubuntu18.04安装的.需要注意的是如果你的Ubuntu系统版本太低,安装时会遇到各种的版本太 ...

  5. mysql 查询某字段值全是数字

    select * from x_ziyuan where zy_zhanghu regexp '^[0-9]+$'

  6. php获取远程图片模拟post,file上传到指定服务器

    1.获取远程图片 /** $path保存图片的地址 $url要获取的远程图片地址 **/ function getimg($path,$url){ $aext = explode('.', $url) ...

  7. 数组和集合(三):Set集合的使用总结

    一.概述 · 继承collection接口 · 无序(不记录添加顺序).不允许元素重复.只允许存在一个null元素 二.实现类 1. HashSet · 底层其实是包装了一个HashMap实现的 · ...

  8. java 蓝桥杯算法提高 _2最大最小公倍数

    解题思路: 1. n是奇数,那就最大的三个数相乘2. n是偶数,得分两种情况了, ①如果n不是3的倍数,那就s=n*(n-1)*(n-3)---n与n-2同为偶数,故排除一个n-2: ②n是3的倍数, ...

  9. len=in.read(b,0,len)和len=in.read(b)的区别

    byte[] byte = new byte[1024]; int len =0 ; while((len=in.read(b))!=-1){ out.write(b,0,len); } read函数 ...

  10. SpringMVC单元测试-MockMvc

    一 简介 MockMvc实现对Http请求的模拟,可以方便对Controller进行测试,使得测试速度快.不依赖网络环境,而且提供验证的工具,使得请求的验证统一而且很方便.   二 常见使用方式 1  ...