2016-05-17 4 views
3

をファイルに書き込めません:Files.newOutputStream(パス、CREATE_NEW、DELETE_ON_CLOSEは)私は、次のコード持っ

import java.io.IOException; 
import java.io.OutputStream; 
import java.nio.file.Files; 
import java.nio.file.Paths; 

import static java.nio.file.StandardOpenOption.CREATE_NEW; 
import static java.nio.file.StandardOpenOption.DELETE_ON_CLOSE; 

public class Test { 
    public static void main(String[] args) throws IOException { 
     try (OutputStream outputStream = Files.newOutputStream(Paths.get("test"), CREATE_NEW, DELETE_ON_CLOSE)) { 
      outputStream.write(123); 
      outputStream.flush(); 
      System.out.println("done"); 
     } 
    } 
} 

を私はSystem.out.printlnに呼び出しでブレークポイントを入れて、私の作業ディレクトリを視察しました。 testというファイルはありませんでした。出力ストリームがファイルに書き込まれないのはなぜですか?

+0

うーん...( 'Thread.sleep'代わりにブレークポイントを使用して)私のために動作します。どのOSを実行していますか? –

+0

OSX。 'DELETE_ON_CLOSE'も削除すればうまく動作します。 – Max

+0

私は、開いているファイルハンドルを持つ削除されたファイルに引き続きアクセスできるので、Unixベースのオペレーティングシステムがすぐにファイルを削除するということが起こっていると思います。しかしこれはAPIに違反しているようだ。 – Max

答えて

3

Linuxでは、ファイルが開いていてもディレクトリからファイルを削除できます(ここでは、適切な許可はここでは想定していません)。 Windowsでは不可能です。

sun.nio.fs.UnixChannelFactory

//クローズ時に削除した場合は、すぐにファイルのリンクを解除するソースから。仕様は明らかです
//
//が開かれた後に攻撃者に置き換えられたときに、実装が正しいファイルのリンクを解除することを保証できません。
場合(flags.deleteOnClose){ ...

あなたは、ファイルが開いていることを確認することができますが、すでに

# assumed that the code write to Paths.get("/tmp/test") 
lsof | grep "/tmp/test" 
... /tmp/test (deleted) 
を削除

for (int i = 0; i < 10; i++) { 
    outputStream.write(123); 
    outputStream.flush(); 
    System.out.println("flush..."); 
    Thread.sleep(10_000); 
} 

としてあなたのコードを修正した場合

アプリケーションが終了したときに一時ファイルが確実に削除されるようにするには、sn以下のippet。

import java.io.File; 
import java.io.OutputStream; 
import java.nio.file.Files; 
import static java.nio.file.StandardOpenOption.CREATE_NEW; 
public class Main { 
    public static void main(String[] args) throws Exception { 
     File file = new File("/tmp/test"); 
     file.deleteOnExit(); 
     System.out.println("tempFile = " + tempFile); 
     try (OutputStream outputStream = Files.newOutputStream(file.toPath(), 
       CREATE_NEW)) { 
      outputStream.write(123); 
      outputStream.flush(); 
      System.out.println("done"); 
     } 
     System.out.printf("%s exists: %s%n", file, file.exists()); 
    } 
} 

ファイル/tmp/testは、アプリケーションが終了した時点で削除されます。あなたは今、あなたもあなたが考えるかもしれないファイル名を気にしない場合は、コンソール

$ ls /tmp/test 
ls: cannot access '/tmp/test': No such file or directory 

にチェックすると

出力

/tmp/test exists: true 

(ファイルはまだこの時点で存在しています)ランダムに生成されたものを使用する。

File tempFile = File.createTempFile("foo_", ".tmp", new File("/tmp")); 

編集別の解決策は、可能性があります。

  1. が、それはあなたが期待するように働くだろうInputStream
  2. OutputStreamそのためにそれをやってDELETE_ON_CLOSE

とを開く開く(ランダム一時ファイル名を使用することを好む)ファイルを作成します。

以下で動作するスニペットを見つけます。

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import static java.nio.charset.StandardCharsets.UTF_8; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import static java.nio.file.StandardOpenOption.APPEND; 
import static java.nio.file.StandardOpenOption.DELETE_ON_CLOSE; 
import static java.nio.file.StandardOpenOption.READ; 

public class DeleteOnClose { 

    public static void main(String[] args) throws IOException { 
     Path path = Paths.get("/tmp/test"); 
     System.out.println("before create: " + Files.exists(path)); 
     Files.createFile(path); 
     System.out.println("after create: " + Files.exists(path)); 
     try (InputStream in = Files.newInputStream(path, READ); 
       OutputStream out = Files.newOutputStream(path, APPEND, 
         DELETE_ON_CLOSE)) { 
      out.write("Hello file!".getBytes(UTF_8)); 
      out.flush(); 

      for (int c = in.read(); c >= 0; c = in.read()) { 
       System.out.print((char) c); 
      } 
      System.out.println(); 
     } 
     System.out.println("after close: " + Files.exists(path)); 
    } 
} 

出力

before create: false 
after create: true 
Hello file! 
after close: false 
+0

これは長時間実行されているプロセス(サービス)であるため、 'deleteOnExit'は私にとっては機能しません。 'deleteOnExit'を使うと、JVMが存在する前にディスクがいっぱいになる可能性があります。 – Max

+0

@Maxこのファイルの使用方法に関する詳細情報を提供してください。現時点では、書き込み専用のファイルを作成し、閉じるときに削除します。現在のケースでは意味をなさないと思われる。そのファイルから別のプロセスやタスクを読み込んでいますか?あなたは、そのファイルからの読み方をコードスニペットでお知らせください。 – SubOptimal

+0

私は休憩サービスでアップロードとしてファイルを受け入れています。私は最終的にこのファイルをストリームとして別のサービスに渡しますが、まずアップロードされたファイルの内容を評価する必要があります。ファイルがかなり大きいので、私はそれをすべてメモリに保存したくありません。今は 'finally'ブロックでファイルを削除しています。これはうまくいきました。ちょうど 'DELETE_ON_CLOSE'がより良くフィットしていたようですが、明らかにそうではありませんでした。 – Max

関連する問題