2016-05-17 100 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'而不是斷點)。你在運行什麼操作系統? –

+0

OSX。如果我刪除'DELETE_ON_CLOSE',它對我也有用。 – Max

+0

我認爲發生的事情是基於Unix的操作系統立即刪除該文件,因爲具有打開文件句柄的已刪除文件仍然可以被訪問。雖然這似乎違反了API。 – Max

回答

3

原因是,在Linux上,即使文件已打開,也可以從目錄中刪除文件(適當的權限在此默默承擔)。在Windows下,這是不可能的。

sun.nio.fs.UnixChannelFactory

//源立即斷開鏈接文件,如果在關閉刪除。該規範明確指出:
//當攻擊者打開後,攻擊者可以用
代替執行程序。
如果(flags.deleteOnClose){ ...

如果你作爲

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

你都能夠看到該文件是開放的,但已經刪除

# assumed that the code write to Paths.get("/tmp/test") 
lsof | grep "/tmp/test" 
... /tmp/test (deleted) 
修改代碼

編輯如果您只想確保在應用程序退出時刪除臨時文件,請查看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將在應用程序完成時被刪除。

輸出(文件此時仍然存在)

/tmp/test exists: true 

,如果你現在的控制檯

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

對檢查如果你甚至不關心你可能會考慮的文件名使用隨機生成的一個。

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

編輯另一種解決辦法是。

  1. 創建文件(喜歡使用一個隨機的臨時文件名)
  2. 打開InputStream
  3. 打開OutputStreamDELETE_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'不適用於我,因爲這是一個長期運行的過程(服務)。在JVM存在之前,使用'deleteOnExit'可能會導致磁盤變滿。 – Max

+0

@Max您能否提供有關如何使用此文件的更多信息。由於目前您只能創建一個「只寫」文件,因此要在關閉時刪除。在目前的情況下似乎沒有任何意義。是否有另一個從該文件讀取的進程/任務?你能否提供一個代碼片段,你想從那個文件中讀取。 – SubOptimal

+0

當然。我接受一個文件作爲休息服務中的上傳文件。我最終會將該文件作爲流傳遞給另一個服務,但我需要先評估上傳文件的內容。鑑於該文件相當大,我不想將它全部存儲在內存中。現在我只是在'finally'塊中刪除文件。這是好的,它只是看起來像'DELETE_ON_CLOSE'會是一個更好的貼合,但顯然不是。 – Max

相關問題