• ベストアンサー

unlinkしたファイルを元に戻す方法?

UNIX系OSでは(Windowsとかでもできるのでしょうか?) プログラム中で使う一時ファイルを、 プログラムが途中で異常終了したりした場合でも 確実に消えてなくなるように、 int fd = open( "temp.dat", O_RDWR|O_CREAT ) ; unlink( "temp.dat" ) ; というように、一時ファイルを作った直後にunlink、という手段が よく使われますが・・・ この、unlinkしてしまって、ファイルディスクリプタだけになったファイルを、 別のファイルに自力で書き写す以外に、 再びファイルとして残すことってできないのでしょうか? 要するに・・・ プログラムが途中で異常終了したりしたときは、 確実に消えてほしいけれど、 必要な場合は残したい、でも、残す処理が途中で中断したりして、 半端なファイルが残ってほしくない、 ・・・というような要件なのですが。。

noname#43437
noname#43437

質問者が選んだベストアンサー

  • ベストアンサー
  • chirubou
  • ベストアンサー率37% (189/502)
回答No.6

なるほど、確かにそういうのって欲しいですよね。よーく分かります。 でも Linux ではできないこともないのですが、普通の Unix だと、fd だけになってしまうと、そこからディレクトリを辿ることはできませんので、fd からファイル(名)を復活させることは、残念ながら、できません。 私だったら、(いい加減なコードですが)以下のように fork() してしまうでしょうね(wait() の引数やマクロは特にいい加減です。スイマセン)。要は親プロセスで処理の正常終了を見張るというものです。ただし、SIGKILL がくるとファイルは消せませんし、シグナルをちゃんと考える必要があるとすると結構面倒です。 fd = open(); if( ( pid = fork() ) = 0 ) [ 処理 } else if( pid > 0 ) { int status; if( wait(&status) == pid ) { if( WIFEXITED(st) && EXITSTATUS(st) == 0 ) exit( 0 ); unlink(...); exit( 1 ); } else { fork エラー }

noname#43437
質問者

お礼

遅くなりましたが、大変参考になる意見ありがとうございました!

その他の回答 (5)

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.5

書き写す以外に標準的な方法はないでしょうねぇ^^; それに、「open() と unlink() の間で以上終了したら、どうするんだ?」というのもありますしね。 一時ファイルがたくさんあって、少しでもタイピングを減らしたいなら、atexit() を使えば少しは減るかもしれませんね。 === #include <unistd.h> #include <stdlib.h> #include <stdio.h> struct fileLink { int fdes; const char *fnam; struct fileLink *next; }; struct fileLink *flptr = NULL; void finally(void) { while (flptr != NULL) { char buf[BUFSIZ]; ssize_t sz; int fd = open(flptr->fnam, ...); lseek(flptr->fdes, 0, SEEK_SET); while ((sz = read(flptr->fdes, buf, BUFSIZ)) > 0) write(fd, buf, sz); close(fd); flptr = flptr.next; } } void create_tmp(void) { const char fn[] = "hogehoge"; static struct fileLink fl; fl.fnam = fn; fl.fdes = open(fn, ...); fl.next = flptr; flptr = &fl; unlink(fn); /* ... */ } int main(void) { atexit(&finally); /* ... */ create_tmp(); /* ... */ return 0; } === でも、わたしなら、atexit()を使わず、まじめに書き写しますけど(笑)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★一時ファイルの扱いは次の関数に任せるのはどうですか。 ・http://www.bohyoh.com/CandCPP/C/Library/tmpfile.html→『tmpfile』  http://www.bohyoh.com/CandCPP/C/Library/tmpnam.html→『tmpnam』  その他にも  http://www1.cts.ne.jp/~clab/hsample/File/File07.html→『ユニークなファイル名で開く』  を参照して下さい。 ・あと一時ファイルは『テンポラリ・フォルダ』に作成するようにします。  そうすればプログラムが途中で異常終了して一時ファイルが残ったとしても  『テンポラリ・フォルダ』のファイルは削除しても良いと考え放置しても問題はない。 ・また必要な場合で残すときは『テンポラリ・フォルダ』に作成したファイルをリネーム付きで  残したいフォルダに移動すれば可能です。移動はパス名の変更だけですので一瞬です。  異常終了しなかった場合はプログラムの終了時に一時ファイルを削除するようにします。  よって  (1)プログラム起動時に一時ファイル名を取得(テンポラリ・フォルダ名も取得)  (2)一時ファイルはテンポラリ・フォルダ名+一時ファイル名で作成/出力  (3)必要な場合は一時ファイル名を残したいフォルダへリネーム付きで移動  (4)プログラム終了時に一時ファイルを削除  という手順でどうですか。  テンポラリ・フォルダの意味を有効に使って下さい。 ・以上。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

>プログラムの処理中に電源断やOSフリーズなどというのも >考慮しなくてはいけないので・・・ 考え方を変えて、一時ファイルが残っても、問題ないような設計をされては、いかがでしょうか。一時ファイルが残ったときに、なにがまずいのかが、具体的に判りませんので、的はずれかも知れませんが・・・ 例として、以下のような方法が、あります。(OSはUNIXとします) 1.一時ファイルは、必ず、所定の専用のディレクトリ下につくる。 2.当該プロセス起動時に、所定のディレクトリ下のファイルを全て削除する。(一時ファイルの残骸を全て削除) 3.その後、一時ファイルを作り、使用する。 尚、一時ファイルはOSにファイル名を作成させる方法もありますが、プロセスが、重複しないファイル名を作ることも可能です。 例として、"TEMP"+時間をファイル名にします。 時間は、現在時刻=「年月日時分秒+マイクロ秒」とします。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.2

>プログラムの処理中に電源断やOSフリーズ その状況でも消すとするとunlinkですかね。しかし、unlinkしちゃったものは事実上消しちゃったファイルと同じですから。取り消すことは不可能だと思います。 そう言えば、ファイルを残したい場合はどんな場合でしょうか?デバッグ用でしょうか?いつでも残した場合もあるとしたらログを残したりするほうが賢明ですが。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.1

自分自身のプロセスでは簡単には管理しようがないと思います。 方法としては、 (1)プログラムをスレッド化して、親となるプログラムで残す/消すを監視する。 (2)ファイルの残す/消すの管理自体を別プロセスを起動して、そちらに任せる。 (3)シェル・スクリプトで残す/消すの処理を行う。終了コードを元に判断する。 (4)異常終了をすべて自分で刈り取り(sigactionなど)、その時点でunlinkする。 ぐらいですかね。

noname#43437
質問者

お礼

なるほど、 ファイルの削除などの処理を外部に任せる方法、ですね。 ただ、最悪の場合、 プログラムの処理中に電源断やOSフリーズなどというのも 考慮しなくてはいけないので・・・ 悩んでおります。

関連するQ&A

  • DATファイル

    このサイトに初めて投稿します。よろしくお願いします。 DATファイルがWindows&nbsp;の中のtempにDATファイル(不明なアプリケーション)という開けない一時ファイルがありますがどんな内容のファイルでしょうか。又削除したいのですが「ほかの人またはプログラムによって使用されています。ファイルを使用している可能性のあるプログラムをすべて閉じてからやりなおして下さい」というエラーが出て削除できません。プログラムも使用もしていません。セ-フモードでは削除できますがBOOTすると作成されています。ファイルの内容と削除についてご教授お願いします。 Windows&nbsp;XP Professional(Service Pack2)

  • 特定のフォルダー内の全てのファイルを削除するには

    お世話になります。 Perlで特定のファイルをunlinkで削除することは、したことがあるのですが、特定のフォルダ例えばCGIプログラムのあるフォルダ配下の「./temp」フォルダー内の全てのファイルを削除するプログラムは、どのように記述すればよいのですか?よろしくお願いします。

    • ベストアンサー
    • Perl
  • DBファイルが0644になってしまう

    Linuxで perl5.005_03 + AnyDBM_FileでDBを作ろうとしているのですが、 作成された DBのファイルパーミッションが「0644」になってしまいます。 「0444」だと意味はありませんが正しく設定されます。 「0777」だと「0744」になりました。 以下のようにやっているのですが、何が間違えているのでしょう。 それとも操作に関しての権限が「0666」になるだけで、実際のファイル パーミッションは後から変更しないといけないのでしょうか? ---------------------------------- use Fcntl; use Config; use AnyDBM_File; $flags = O_CREAT | O_RDWR | &BINARY; tie( %HASH, AnyDBM_File, dbmfile, $flags,0666 ) || die "Can't open DB\n"; ~処理~ untie( %HASH ); sub BINARY{ return O_BINARY if $Config{osname} =~ /^(MS)?Win/; }

    • ベストアンサー
    • Perl
  • windows\temp\フォルダー内の一時ファイル

    windows\temp\フォルダー内の一時ファイルで "rds5133.TMP"等のように、"rds"で始まる一時ファイルが 沢山(時には100個以上)残ります。 一時ファイルなので、見附次第、削除していますが、 このファイルはどのソフトウエアが作って使用しているのでしょうか? そのプログラムの終了時に作った一時ファイルを消去して終了するように 設定できるのでしょうか?

  • 一時ファイル

    vistaを使っていて、ディスクのクリーンアップをしてみたのですが その後に削除の候補がリストアップされ「一時ファイル」というのが あったのですがこれは消してもかまわないものなのでしょうか? 説明文には 「プログラムはTEMPフォルダに一時的な情報を格納することがあります。普通はプログラムを終了する前にこの情報は削除されます」 一週間以上変更されてない一時ファイルは削除しても安全です。 っと書かれているので消してもいいと思っているのですが、どうなのでしょうか? なんかやたら要領を取っていたようなのですが。

  • データー削除で(Tempファイル)

    Tempファイル(一時フォルダ)を削除し、Cドライブの容量を空けたい と思い、Tempファイル内のデータをゴミ箱に移そうとしましたが、 「Perflib_Perfdata_3c0.dat」と言うファイルだけはどうしてもゴミ箱に移ってくれません。 「他の人が使用してるか、開いてる為、削除できません」と出ます、 再起動を試みましたが、同じでした、このファイルを消すにはどうすればいいのでしょいうか? 35Gの使用量が10Gに減ったんですが、気になって投稿しました。 宜しく。

  • 低水準ファイル入出力

    openを用いてファイル:"test.dat"を開き、そのファイルにbuffに示すような適当なデータを書き込みたいのですが、 下記の様に記述してコンパイル、実行した結果"test.dat"内には何も記述されていませんでした。 自分でも調べてみたのですがどうしても上手くいかず、この場で質問させて頂きます。 ご指摘の程宜しくお願いします<(_ _)> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> int main(void) {  char buff[]={"test123456789"};  int fd;  fd=open("test.dat",O_CREAT,S_IREAD|S_IWRITE);  if(fd==-1)   {    close(fd);    fd=open("test.dat",O_WRONLY);    if(fd == -1)    {      printf("open error <file>");      return 1;    }   }  write(fd,buff,sizeof(buff));  close(fd);  return 1; } ---- 私の環境 ---- Vine Linux 2.6r4

  • ファイルが削除できないんですけど。。

    削除できないファイルがあり困ってます。 TEMPファオルダの中にあるファイルなのですが「Perflib_Perfdata_×××.dat」という名前です。 ×××のところは任意の英数字で都度変化します。 試した事 (1)インターネットオプションからも削除できません。 (2)直接削除もできません。その際、「Perflib_Perfdata_×××.datを削除できません。ほかの人またはプログラムによって使用されています。ファイルを使用している可能性があるプログラムを全て閉じてから、やり直してください。」と表示されます。 (3)メモ帳を起動し、同じ名前にして上書きしようとしましたができません。 (4)再起動しても消えません。 (5)セーフモードで立ち上げるとファイルが見当たりません。 (6)「naoDeleteFilesOnRebootV102」というソフトを使いましたが削除できません。 以上のことを試したのですが削除できませんでした。どなたか対処法をご指導いただけないでしょうか? よろしくお願いします。

  • このファイルは開けません、とは??

    パソコンについてまったくの初心者ですので、 困っています。 パソコンを起動すると、 このファイルを開けません。 ・Webサービスを使用して適切なプログラムを探す。 ・一覧からプログラムを選択する。 という文章が出ます。 テンポラリーファイルのようなのですが… 何に関連したファイルなのかもわかりませんし、毎回起動するたびに 出てくるので困っています。 ためしに、WindowsのTempというところのファイルを全部消してみましたが、 それでも出てきます。 インターネットの一時ファイルも消しました。 どうしたらこの表示を出ないようにできますか? WindowsのVistaです。よろしくお願いします。

  • 中間ファイルを使わずに処理させる方法

    cmd1.exe は、標準入力でデータを読み込み、 結果を標準出力するようなプログラムです。 $ cmd1.exe < test.txt d090206 p314159 r214142 $ このcmd1.exeをperlスクリプト内で呼び出し、その結果を求めるやり方として、 従来、次のようなやりかた・・・ open(OUT,">temp.txt") || die "$!"; foreach(・・・){ 中略 print OUT "$_\n"; } close(OUT); my @answer = `cmd1.exe < temp.txt`; foreach(@answer){ : 略 } unlink("temp.txt"); のようなことをしています。 今は、中間ファイルを書き出しては、最後にファイル削除して、ということをやっているのですが、 このような中間ファイルを使わずに、パイプ(?)という仕組みを使って、同じように処理させるには、 どのようにコーディングすれば良いですか? 試してみたこととして、 open(PIPE,"|cmd1.exe"); foreach(・・・){ 中略 print PIPE "$_\n"; } close(PIPE); のようにすれば、exeの呼び出しそのものは出来たのですが、 その標準出力の結果を上手く内部で受け取れません。 よろしくお願い致します。

    • ベストアンサー
    • Perl

専門家に質問してみよう