4

我正在使用 File::Temp 创建临时文件。当程序正常退出时,我的临时文件会自动删除。我希望当我的程序用 ctrl+c 停止时也会发生同样的情况。它不是。

这是一个演示我的问题的简单程序。

期望的行为是这样的。我怎样才能实现它?我在 Linux 上。

  • 关闭文件句柄时不会删除临时文件(确定)
  • 程序正常退出时临时文件被删除(好的)
  • 当程序使用 ctrl+c 退出时临时文件被删除(不工作)

.

#!/usr/bin/perl -l

use warnings; use strict;
use File::Temp qw(tempfile tmpfile);

my $fh = File::Temp->new;
close $fh;

-f "$fh" || die "$fh does not exist"; 
print "hit enter and the file will be deleted";
print "hit ctrl+c and it won't";
print "verify with ls $fh after program exits";
readline STDIN;

编辑 1

我测试了 tempfile 的行为。似乎确认 Linux 支持我正在寻找的内容(将文件标记为临时/取消链接打开文件)。我似乎以某种方式理想化了 File::Temp 。

# program will die because os deletes tmpfile after close
my $fh = tempfile;
close $fh;
stat $fh || die;
readline STDIN;
4

5 回答 5

3

要使 Control_C 键盘中断运行您的END块,您需要添加一个信号处理程序。比较以下行为:

perl -E 'END{say "END"};<STDIN>'

和:

perl -E '$SIG{INT}=sub{die};END{say "END"};<STDIN>'

perlmod

An END code block is executed as late as possible, that is, after perl has
finished running the program and just before the interpreter is being exited,
even if it is exiting as a result of a die() function. (But not if it's
morphing into another program via exec, or being blown out of the water by a
signal--you have to trap that yourself (if you can).) 
于 2012-11-15T21:47:45.600 回答
2

您是否尝试过将清理代码放入和 END 块中?

于 2012-11-15T20:34:35.503 回答
1

我查看了源代码。我什至检查了最新版本(写作时为 0.22)。我想用 File::Temp 做什么是设计不允许的。

创建对象时,使用数组上下文创建临时文件,如下所示:

sub new {
  ...
  # Open the file and retain file handle and file name
  my ($fh, $path) = tempfile( @template, %args );

在数组上下文中创建临时文件意味着该文件永远不会自动取消链接(即使在支持它的平台上)。该文件被标记为延迟取消链接,这意味着当程序正常退出时它将被删除。

sub tempfile { 
  ...
  _deferred_unlink($fh, $path, 0) if $options{"UNLINK"};

  # Return
  if (wantarray()) {

    if ($options{'OPEN'}) {
      return ($fh, $path);
    } else {
      return (undef, $path);
    }

  } else {

    # Unlink the file. It is up to unlink0 to decide what to do with
    # this (whether to unlink now or to defer until later)
    unlink0($fh, $path) or croak "Error unlinking file $path using unlink0";

    # Return just the filehandle.
    return $fh;
  }

如果我想继续使用 File::Temp,我需要设置一个信号处理程序以在我的程序中止时强制清理。如果对可移植性有任何顾虑,我还应该设置一个 sig 处理程序,因为在某些平台上只提供了延迟取消链接。好消息是, File::Temp 创建了一个 END 块,所以根本不需要做太多事情:

use sigtrap qw(die normal-signals error-signals);

如果可移植性不是问题并且平台支持自动文件清理,那么使用 tempfile 是可以的(在标量上下文中)。

以下评论很好地解释了这种设计背后的基本原理:

当我们打开文件时,我们必须指出临时性。一般来说,如果我们只返回文件句柄,我们只需要一个真正的临时文件 - 如果用户想要文件名,他们可能不希望文件在关闭后立即消失(如果他们想要一个子进程,这可能很重要使用文件)

于 2012-11-16T15:14:02.067 回答
0

你真的需要文件名吗?如果没有,请使用

my $fh = tempfile();
于 2012-11-15T20:02:36.117 回答
0

我一直在寻找类似的东西,我想我找到了一个相当不错的小解决方案。

它根本不是什么新东西,但可能比安装自己的END块等更简单:

use sigtrap qw(die INT); # ensures DESTROY methods are run on Ctrl-C

my $temp = File::Temp->new(UNLINK => 1);
my $filename = $temp->filename;
# When $temp goes out of scope, the file will be
# deleted, and $filename will be invalid.
# Further, a Ctrl-C will cause $temp->DESTROY to be invoked,
# which will also delete the temp file.
于 2017-11-08T06:16:27.650 回答