| Path-Class-URI documentation | Contained in the Path-Class-URI distribution. |
Path::Class::Unicode - Maps Unicode filenames to local encoding and code pages
use Path::Class::Unicode;
# Use ufile() to create Unicode objects
my $fn = "\x{55ed}.txt";
my $file = ufile("path", $fn);
my $fh = $file->open;
my $fn = "\x{55ed}.txt";
my $file = ufile("/path", $fn);
my $uri = $file->uri; # file:///path/%E5%97%AD.txt (always utf-8)
my $fh = ufile_from_uri($uri)->open;
Path::Class::Unicode is a Path::Class extension to handle Unicode file names by mapping them to local encodings when stringified. It maps to UTF-8 for all UNIX systems including Mac OS X and uses Windows code page (like cp932 for Japanese) in Win32 systems.
It's very useful if you store file paths using URI representation like file:// and uses URI escaped UTF-8 characters for non-ASCII characters. See Path::Class::URI for details.
It would be nice if we could proxy filehandles using Win32API::File.
Tatsuhiko Miyagawa <miyagawa@cpan.org>
mattn
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Path-Class-URI documentation | Contained in the Path-Class-URI distribution. |
package Path::Class::Unicode; use strict; use 5.008_001; our $VERSION = '0.04'; use Exporter::Lite; our @EXPORT = qw( ufile udir ufile_from_uri udir_from_uri ); use Encode (); use Path::Class; use URI::file; use Scalar::Util qw(blessed); sub ufile { __PACKAGE__->new(file(@_)); } sub udir { __PACKAGE__->new(dir(@_)); } sub Path::Class::File::ufile { my $file = shift; ufile(_decode_filename($file), @_); } sub Path::Class::Dir::udir { my $dir = shift; udir(_decode_filename($dir), @_); } sub ufile_from_uri { my $uri = shift; $uri = URI->new($uri) unless blessed $uri; if ($^O eq "MSWin32") { ufile(Encode::decode_utf8($uri->file('win32'))); } else { ufile(Encode::decode_utf8($uri->file('unix'))); } } sub udir_from_uri { my $uri = shift; $uri = URI->new($uri) unless blessed $uri; if ($^O eq "MSWin32") { udir(Encode::decode_utf8($uri->file('win32'))); } else { udir(Encode::decode_utf8($uri->file('unix'))); } } sub new { my($class, $path) = @_; bless { path => $path }, $class; } sub uri { my $self = shift; my $path = Encode::encode_utf8($self->{path}->stringify); $path =~ tr!\\!/! if $^O eq "MSWin32"; if ($self->is_absolute) { return URI->new("file://$path"); } else { return URI->new("file:$path"); } } our $encoding; sub init_encoding { unless ($encoding) { $encoding = 'utf-8'; if ($^O eq 'MSWin32') { eval { require Win32::API; Win32::API->Import('kernel32', 'UINT GetACP()'); $encoding = 'cp'.GetACP(); }; } } } sub stringify { my $self = shift; init_encoding(); Encode::encode($encoding, $self->{path}->stringify); } sub _decode_filename { init_encoding(); my $filename = shift; Encode::decode($encoding, "$filename"); } sub open { my $self = shift; my $class = $self->is_dir ? "IO::Dir" : "IO::File"; $class->new($self->stringify, @_); } sub next { my $self = shift; $self->{path}->{dh} = $self->open unless $self->{path}->{dh}; local *IO::Dir::read = sub { Encode::decode $encoding, readdir shift }; ufile($self->{path}->next); } sub children { my ($self, %opts) = @_; $self->{path}->{dh} = $self->open unless $self->{path}->{dh}; my @out; while (my $entry = $self->{path}->{dh}->read) { # XXX What's the right cross-platform way to do this? next if (!$opts{all} && ($entry eq '.' || $entry eq '..')); push @out, $self->file($entry); $out[-1] = $self->subdir($entry) if -d $out[-1]; } return @out; } use overload ( q[""] => 'stringify', fallback => 1, ); our $AUTOLOAD; sub AUTOLOAD { my $self = shift; (my $method = $AUTOLOAD) =~ s/.*:://; $self->{path}->$method(@_); } sub DESTROY { } 1; __END__