4

File::Temp で一時ファイルを作成しています。プログラムが正常に終了すると、一時ファイルは自動的に削除されます。私のプログラムがctrl + cで停止されたときに同じことが起こると思っていました。そうではない。

これが私の問題を示す簡単なプログラムです。

望ましい動作はこれです。どうすれば達成できますか?私はLinuxを使用しています。

  • ファイルハンドルを閉じるときに一時ファイルが削除されない (ok)
  • プログラムが正常に終了すると、一時ファイルが削除されます(OK)
  • プログラムが 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 に答える