请注意 - 我不是在寻找打开/读取文件的"正确"方式,也不是每次都打开/读取文件的方式.我只是想知道大多数人使用的方式,并且可能同时学习一些新方法:)*
我的Perl程序中一个非常常见的代码块是打开一个文件并读取或写入它.我已经看到了很多这样做的方法,多年来我执行这项任务的风格发生了变化.我只是想知道什么是最好的(如果有最好的方法)方法是这样做的?
我以前打开这样的文件:
my $input_file = "/path/to/my/file";
open INPUT_FILE, "<$input_file" || die "Can't open $input_file: $!\n";
Run Code Online (Sandbox Code Playgroud)
但我认为错误捕获存在问题.
添加括号似乎可以修复错误捕获:
open (INPUT_FILE, "<$input_file") || die "Can't open $input_file: $!\n";
Run Code Online (Sandbox Code Playgroud)
我知道你也可以给一个变量分配一个文件句柄,所以不像我上面那样使用"INPUT_FILE",我可以使用$ input_filehandle - 这样更好吗?
对于读取文件,如果它很小,那么globbing有什么问题吗?
my @array = <INPUT_FILE>;
Run Code Online (Sandbox Code Playgroud)
要么
my $file_contents = join( "\n", <INPUT_FILE> );
Run Code Online (Sandbox Code Playgroud)
或者你应该总是循环,像这样:
my @array;
while (<INPUT_FILE>) {
push(@array, $_);
}
Run Code Online (Sandbox Code Playgroud)
我知道有很多方法可以在perl中完成任务,我只是想知道在文件中是否有打开和读取的首选/标准方法?
我宁愿一个XS初学者,我期待到改变其采用了15+岁的底层C库大量现有的XS模块(其实模块基本上是粘合到该库).问题是我希望能够使用PerlIO字符串技巧:
open($fh, '<', \$string);
Run Code Online (Sandbox Code Playgroud)
然后传递$fh到库所期望的XS胶水FILE.问题是XS有:
int
_parse (entry_ref, filename, file, preserve=FALSE)
SV * entry_ref;
char * filename;
FILE * file;
boolean preserve;
Run Code Online (Sandbox Code Playgroud)
我认为它需要是:
PerlIO * file;
Run Code Online (Sandbox Code Playgroud)
这当然不起作用,因为它必须有更多.当我查看_parse库中的代码时,它最终会出现:
AST * bt_parse_entry (FILE * infile,
char * filename,
btshort options,
boolean * status)
{
AST * entry_ast = NULL;
static int * err_counts = NULL;
static FILE * prev_file = NULL;
Run Code Online (Sandbox Code Playgroud)
FILE再次与类型.现在我必须要开始的基本问题是 - 这是否可以在不改变库的情况下实现; 也就是说,我可以通过更改XS从字符串PerlIO行为中获取伪文件句柄吗?
我想将die消息重定向到一个单独的文件,以便我可以稍后比较该文件以确定出错的地方.
但是这段代码给了我错误:
$ cat test.pl
use strict;
use warnings;
my $log = "msglog.log";
die $log "DEAD$!";
$ perl test.pl
Missing comma after first argument to die function at test.pl line 5, near ""DEAD$!";"
Execution of test.pl aborted due to compilation errors.
$
Run Code Online (Sandbox Code Playgroud)
我不想2>从来电者那里做一个.有没有办法从脚本中重定向它们?
我试图从Perl中的管道读取unbufferd数据.例如,在下面的程序中:
open FILE,"-|","iostat -dx 10 5";
$old=select FILE;
$|=1;
select $old;
$|=1;
foreach $i (<FILE>) {
print "GOT: $i\n";
}
Run Code Online (Sandbox Code Playgroud)
iostat每隔10秒(5次)吐出数据.你会期望这个程序也这样做.然而,相反它似乎挂起50秒(即10x5),之后它会吐出所有数据.
我怎样才能返回任何可用的数据(以无缓冲的方式),而无需等待所有EOF?
PS我在Windows下看到了很多对此的引用 - 我在Linux下这样做.
看起来main中的符号'_<-'(没有引号)与其他看起来像是可以处理的东西相同:'_</usr/perl/lib/Carp.pm'例如.
有没有办法使用它?
或者,如果我希望阅读输入源,我是否必须使用源过滤器?
回复mob:我不知道Debug会在哪里打开.转出基表后,%INC的转储显示:
$VAR1 = {
'warnings/register.pm' => 'C:/strawberry/perl/lib/warnings/register.pm',
'XSLoader.pm' => 'C:/strawberry/perl/lib/XSLoader.pm',
'English.pm' => 'C:/strawberry/perl/lib/English.pm',
'Tie/Hash/NamedCapture.pm' => 'C:/strawberry/perl/lib/Tie/Hash/NamedCapture.pm',
'unicore/lib/Perl/_PerlIDS.pl' => 'C:/strawberry/perl/lib/unicore/lib/Perl/_PerlIDS.pl',
'unicore/Heavy.pl' => 'C:/strawberry/perl/lib/unicore/Heavy.pl',
'warnings.pm' => 'C:/strawberry/perl/lib/warnings.pm',
'utf8.pm' => 'C:/strawberry/perl/lib/utf8.pm',
'Config.pm' => 'C:/strawberry/perl/lib/Config.pm',
'overloading.pm' => 'C:/strawberry/perl/lib/overloading.pm',
'Symbol.pm' => 'C:/strawberry/perl/lib/Symbol.pm',
'Carp.pm' => 'C:/strawberry/perl/lib/Carp.pm',
'bytes.pm' => 'C:/strawberry/perl/lib/bytes.pm',
'Exporter/Heavy.pm' => 'C:/strawberry/perl/lib/Exporter/Heavy.pm',
'utf8_heavy.pl' => 'C:/strawberry/perl/lib/utf8_heavy.pl',
'strict.pm' => 'C:/strawberry/perl/lib/strict.pm',
'Exporter.pm' => 'C:/strawberry/perl/lib/Exporter.pm',
'vars.pm' => 'C:/strawberry/perl/lib/vars.pm',
'constant.pm' => 'C:/strawberry/perl/lib/constant.pm',
'Errno.pm' => 'C:/strawberry/perl/lib/Errno.pm',
'overload.pm' => 'C:/strawberry/perl/lib/overload.pm',
'Data/Dumper.pm' => 'C:/strawberry/perl/lib/Data/Dumper.pm'
};
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一些XS代码,它将一个库公开给Perl代码作为可以写入的流接口.get_stream下面的
函数应该是一个准备和返回PerlIO对象的构造函数.我想我只需要
Write和Close方法,所以我把所有其他功能插槽留空了.
typedef struct {
struct _PerlIO base;
mylib_context* ctx;
} PerlIOmylib;
/* [...] */
PERLIO_FUNCS_DECL(PerlIO_mylib_funcs) = {
.fsize = sizeof(PerlIO_funcs),
.name = "mylib",
.size = sizeof(PerlIOmylib,
.Write = mylib_write,
.Close = mylib_close,
};
/* XS below */
PerlIO*
get_stream (SV* context_obj)
CODE:
mylib_context* ctx = (mylib_context*) SvIV (SvRV (context_obj));
PerlIO* f = PerlIO_allocate (aTHX);
f = PerlIO_push (aTHX, f, PERLIO_FUNCS_CAST(&PerlIO_mylib_funcs), "a", NULL);
PerlIOSelf(f, PerlIOmylib)->ctx = ctx;
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
RETVAL = f;
OUTPUT: …Run Code Online (Sandbox Code Playgroud) 与直接使用perl的内置IO函数相比,IO :: File,IO :: Socket :: INET模块具有一些优势,例如使用显式语法来刷新句柄.
但是,它们似乎比内置IO功能有一些缺点.例如,据我所知,他们无法与autodie模块结合使用来引发故障异常,因此我发现自己必须编写更多的样板代码来处理故障,而不是使用内置函数.
有没有办法将两个或其他具有组合功能的模块组合在一起?我注意到一些有限用途的IO模块,比如File :: Slurp,允许更灵活的错误处理.
我正在编写模块代码,理想情况下,解决方案应该一直回到perl 5.10.0.
几个小时了,我正在打击Perl程序中的一个错误.我不确定我是做错了还是解释器做了什么,但代码是非确定性的,而它应该是确定性的,IMO.此外,它在古代Debian Lenny(Perl 5.10.0)和刚刚升级到Debian Wheezy(Perl 5.14.2)的服务器上表现出相同的行为.它归结为这段Perl代码:
#!/usr/bin/perl
use warnings;
use strict;
use utf8;
binmode STDOUT, ":utf8";
binmode STDERR, ":utf8";
my $c = "";
open C, ">:utf8", \$c;
print C "š";
close C;
die "Does not happen\n" if utf8::is_utf8($c);
print utf8::decode($c) ? "Decoded\n" : "Undecoded\n";
Run Code Online (Sandbox Code Playgroud)
它在严格模式下初始化Perl 5解释器并启用警告,使用字符串(而不是字节字符串)和以UTF8编码的命名标准流(UTF-8的内部概念,但非常接近;更改为完整的UTF-8没有区别).然后它打开一个"内存文件"(标量变量)的文件句柄,在其中打印一个双字节UTF-8字符,并在关闭时检查该变量.
标量变量现在总是将UTF8位翻转掉.但是它有时包含一个字节字符串(转换为字符串via utf8::decode()),有时还需要一个只需要翻转其UTF8位(Encode::_utf8_on())的字符串.
当我重复执行我的代码(1000次,通过Bash)时,它打印Undecoded并Decoded具有大致相同的频率.当我更改我写入"文件"的字符串时,例如在其末尾添加换行符,Undecoded消失.当utf8::decode成功,我尝试了在一个循环中相同的原始字符串,它不断在翻译的同一个实例成功; 但是,如果它失败了,它会一直失败.
对观察到的行为有什么解释?如何将文件句柄与字符串一起用于标量变量?
巴什游乐场:
for i in {1..1000}; do perl -we 'use strict; use utf8; binmode STDOUT, ":utf8"; binmode STDERR, ":utf8"; my …Run Code Online (Sandbox Code Playgroud) 我有一个访问PostgreSQL数据库的应用程序,需要根据一些需要的处理从中读取一些大的二进制数据.这可能是数百MB甚至数GB的数据.请不要讨论使用文件系统等等,它就像现在这样.
该数据只是各种类型的文件,例如它可能是Zip容器或其他类型的存档.一些需要的处理是列出Zip的内容,甚至可以提取一些成员进行进一步处理,也可以散列存储的数据......最后,数据被多次读取,但只写入一次以存储它.
我使用的所有Perl库都可以使用文件句柄,有些用于IO::Handle,有些用于IO::String或者IO::Scalar,其他一些只有低级文件句柄.所以我所做的就是创建的子类IO::Handle和IO::Seekable它就像周边的相应方法的包装DBD::Pg.在CTOR中,我创建了一个与数据库的连接,打开一些提供的LOID用于读取并存储Postgres在实例中提供的句柄.然后我自己的句柄对象被转发给能够使用这种文件句柄的人,并且可以直接在Postgres提供的blob中读取和搜索.
问题是使用低级文件句柄或低级文件句柄操作的库IO::Handle.Digest::MD5似乎是Archive::Zip另一个.Digest::MD5 croak并且告诉我没有提供句柄,Archive::Zip另一方面尝试从我的创建一个新的,自己的句柄,IO::Handle::fdopen在我的情况下调用和失败.
sub fdopen {
@_ == 3 or croak 'usage: $io->fdopen(FD, MODE)';
my ($io, $fd, $mode) = @_;
local(*GLOB);
if (ref($fd) && "".$fd =~ /GLOB\(/o) {
# It's a glob reference; Alias it as we cannot get name of anon GLOBs
my $n = qualify(*GLOB);
*GLOB = *{*$fd};
$fd = $n;
} …Run Code Online (Sandbox Code Playgroud) 我必须杀死我正在通过的程序
$pid = open(FH, "program|")
或者
$pid = or open(FH, "-|", "program")
但是,该程序(具体来说是 mosquittto_sub)仍然在后台徘徊,因为open返回的sh是 perl 用来运行该程序的 PID ,所以我只是杀死了sh包装器而不是实际程序。
有没有办法让程序真正的PID?获取shPID 的意义何在?
perl ×10
perl-io ×10
xs ×2
autodie ×1
die ×1
exception ×1
file ×1
filehandle ×1
io ×1
linux ×1
perl-ipc-run ×1
perl5 ×1
postgresql ×1
utf-8 ×1