[Perl]Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略
[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 文件名操作(新建、重命名、枚举、复制)全攻略的更多相关文章
- Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略
常见的那些文件操作函数都不支持,于是为了达到目的,需要各种方法配合,应该是不如其他语言方便.我只是想看看Perl到底是否适合做这件事,于是折腾了一回. 文件的建立: 模块:Win32 Code: [全 ...
- delphi 文件的操作:重命名、复制、移动、删除
Delphi 文件的操作:重命名.复制.移动.删除第一种方法: RenameFile('Oldname', 'Newname'); CopyFile(PChar('Oldname'), PChar(' ...
- linux下的文件操作——批量重命名
概述:在日常工作中,我们经常需要对一批文件进行重命名操作,例如将所有的jpg文件改成bnp,将名字中的1改成one,等等.文本主要为你讲解如何实现这些操作 1.删除所有的 .bak 后缀: renam ...
- Windows系统,文件和文件夹命名规则:
不能包含:< > / \ | : * ? windows中,文件名(包括扩展名)可高达 个字符.文件名可以包含除 ? “ ”/ \ < > * | : 之外的大多数字符:保留文 ...
- 【转】Perl Unicode全攻略
Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...
- Perl Unicode全攻略
Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...
- 2.3《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——重命名,复制,删除
最常用的文件操作除了将文件列出来外,就应该是重命名,复制,删除了.正如将文件列出来一样,大多数现代操作系统为这些任务提供了用户图形界面,但是在许多场景中,用命令行还是会更方便. 使用mv命令重命名一个 ...
- linux 下文件重命名/移动/复制命令(转)
linux 下文件重命名/移动/复制命令(转) linux下重命名文件:使用mv命令就可以了, 例:要把名为:abc 重命名为:123 可以这样操作: 重命名:MV命令 1.进入你的文件目录,运行 ...
- Windows Socket五种I/O模型——代码全攻略(转)
Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模式.可以通过多线程技术进行处理. 非阻塞模式:执行I/O操 ...
随机推荐
- Java ArrayList的不同排序方法
本文由 ImportNew - 温布利往事 翻译自 dzone.欢迎加入翻译小组.转载请见文末要求. 由于其功能性和灵活性,ArrayList是 Java 集合框架中使用最为普遍的集合类之一.Arra ...
- GameObject.DestroyImmediate(go, true)会使磁盘资源数据丢失,导致不可用
GameObject.DestroyImmediate(go, true)会使磁盘资源数据丢失,导致不可用 第二个参数true表示 allowDestroyingAssets,表示允许销毁资源. 实测 ...
- 【302】C# TreeView 控件使用说明
参考:C# 中treeview 树节点图标的动态加载,及选中时图标改变 参考:C# TreeView 控件的综合使用方法 参考:TreeView 类 参考:TreeNode 类 1. 添加根和子级 通 ...
- ubuntu 安装 rtpengine
摘要 RtpEngine推荐使用Debian系统,可以看出Debian系统的安装是最简单的.我是基于ubuntu18.04安装的.需要注意的是如果你的Ubuntu系统版本太低,安装时会遇到各种的版本太 ...
- mysql 查询某字段值全是数字
select * from x_ziyuan where zy_zhanghu regexp '^[0-9]+$'
- php获取远程图片模拟post,file上传到指定服务器
1.获取远程图片 /** $path保存图片的地址 $url要获取的远程图片地址 **/ function getimg($path,$url){ $aext = explode('.', $url) ...
- 数组和集合(三):Set集合的使用总结
一.概述 · 继承collection接口 · 无序(不记录添加顺序).不允许元素重复.只允许存在一个null元素 二.实现类 1. HashSet · 底层其实是包装了一个HashMap实现的 · ...
- java 蓝桥杯算法提高 _2最大最小公倍数
解题思路: 1. n是奇数,那就最大的三个数相乘2. n是偶数,得分两种情况了, ①如果n不是3的倍数,那就s=n*(n-1)*(n-3)---n与n-2同为偶数,故排除一个n-2: ②n是3的倍数, ...
- 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函数 ...
- SpringMVC单元测试-MockMvc
一 简介 MockMvc实现对Http请求的模拟,可以方便对Controller进行测试,使得测试速度快.不依赖网络环境,而且提供验证的工具,使得请求的验证统一而且很方便. 二 常见使用方式 1 ...