2015-12-02 81 views
3

對於我的應用程序,我必須編寫一個方法,它將InputStream作爲參數,將內容寫入臨時文件,執行一些操作並最終刪除臨時文件。在資源嘗試中處理臨時文件

這是我到目前爲止有:

public void myMethod(InputStream in, String name) { 
    //... 
    Path path = Paths.get("./tmp/benchmarks/" + name + ".zip") 

    try { 
     Files.copy(in, path); 
     //operations... 
    } catch (IOException e) { 
     //error handling for copy... 
    } finally { 
     try { 
      Files.delete(path)); 
     } catch (IOException e) { 
      //error handling for delete... 
     } 
    } 
    //... 
} 

它的工作,但它也看起來非常難看。我想知道是否有某種方式可以使用try-with-resources來更好地處理這個問題。 它可能以某種方式?

更新:我在十分鐘內寫了一個即時解決方案。它看起來像這樣:

public class TemporaryFileHandler implements AutoCloseable { 

    private File file; 

    public TemporaryFileHandler(final InputStream in, final Path path) throws IOException { 
     Files.copy(in, path); 
     this.file = new File(path.toString()); 
    } 

    public File getFile() { return file; } 

    @Override 
    public void close() throws IOException { 
     Files.delete(file.toPath()); 
    } 
} 

我相信這不是最好的,但它現在做的工作。如果任何人有任何建議,以任何方式改善這一點,建議是非常值得歡迎的。

+0

你知道'Files.createTempFile'嗎? – 2015-12-02 17:40:51

+0

@RC。是的,但使用它意味着該文件將在JVM關閉時被刪除。理想情況下,我的JVM不應該關閉(我正在開發一個REST API)。 – link

+1

沒有嘗試,但類似'try(InputStream in = Files.newInputStream(tempFile,StandardOpenOption.DELETE_ON_CLOSE))'可以爲你工作。適用於流,因此可能不如基於文件的方便。 – zapl

回答

3

Try-with-resource只是在執行實現java.lang.AutoCloseable的接口的類上調用close方法。沒有什麼能夠阻止你創建一個實現AutoCloseable的File實現,並且在調用close()時會自行刪除它。

您也可以在文件上調用deleteOnExit()讓JVM在退出時將其刪除。這隻適用於在等待JVM完成刪除臨時文件的情況下可以使用。對於像Java Web應用程序這樣的長時間運行的JVM,這可能不是一個好主意。

+0

謝謝你的建議。我已經知道'AutoCloseable',但我希望類似的東西已經實現。由於它似乎並非如此,我會自己做。爲了以防萬一,我會在接受你的答案之前多等一會兒。 – link

+0

@link我感到你的痛苦。祝你好運,如果你發現這樣做具體:)嘗試與資源是相對較新的。如果你創建了一個刪除自己的類,我會把它上傳到Git或其他東西,並從這裏鏈接它。我相信其他人可以使用它。 – Jazzepi

+0

謝謝!查看我的更新,獲取非常快速的解決方案:)如果您有任何建議,請告訴我! – link

1

Files.createTempFile允許您在JVM的默認臨時目錄中創建一個臨時文件。這並不意味着文件被自動刪除或使用File.deleteOnExit()標記爲刪除。開發人員負責管理臨時文件的生命週期。

該文件的名稱是安全漏洞的向量。只需在界面中使用該名稱進行驗證和反饋即可。不要將不可信用戶輸入用於文件名稱。

無法通過使用java.io.Filejava.nio.file.Path來嘗試資源管理文件的生命週期。 InputStream可以用try-with-resources進行管理。

public void myMethod(InputStream in) { 
    Path path = null; 

    try (InputStream stream = in) { 
     path = Files.createTempFile(null, ".zip"); 
     Files.copy(stream, path); 
    } catch (IOException e) { 
     //error handling for copy... 
    } finally { 
     if (path != null) { 
      try { 
       Files.delete(path)); 
      } catch (IOException e) { 
       //error handling for delete... 
      } 
     } 
    } 
} 
+0

謝謝你的代碼,我知道我可以處理' InputStream在嘗試使用資源時,但這不是我在這裏做的感興趣:)然而,關於安全漏洞的評論聽起來很有趣。我知道這不是嚴格相關的,但你可以詳細說明一點嗎? – link

+0

該文件的名稱可能包含對〜/和../等目錄的引用。這將改變臨時文件寫入的目錄。 – Aaron

+0

我根本沒想過這個。謝謝你的建議:) – link

3

我覺得跟喜歡

public class AutoDeletingTempFile implements AutoCloseable { 

    private final Path file; 

    public AutoDeletingTempFile() throws IOException { 
     file = Files.createTempFile(null, null); 
    } 

    public Path getFile() { 
     return file; 
    } 

    @Override 
    public void close() throws IOException { 
     Files.deleteIfExists(file); 
    } 
} 

一個小幫手/封裝程序被關閉,並刪除它包裝你得到一個很好的和短的語法文件:

public void myMethod(InputStream in, String name) { 
    try (AutoDeletingTempFile wrapper = new AutoDeletingTempFile()) { 
     //Files.copy(in, wrapper.getFile()); 
     //operations... 
    } catch (IOException e) { 
     //error handling for copy... 
     // + temp file creation 
    } 
} 

或一個整潔的小Closable via lambdas

public void myMethod(InputStream in, Path existingFile, String name) { 
    try (Closeable closable =() -> Files.deleteIfExists(existingFile)) { 
     // ... 
    } catch (IOException e) { 
     // 
    } 
} 
+0

謝謝!這與我的解決方案類似,但我想像你這樣存儲對'Path'的引用可能比存儲對'File'的引用更好。我會稍微修改一下我的解決方案。 – link

0

我有一個類似的問題,臨時ZIP文件沒有被刪除。我的假設是,在代碼試圖刪除臨時文件之前,輸出流未被關閉。

我的解決方案,使用嵌套的嘗試,不是很優雅,但它應該保證預先關閉流。

以前

File out = // get file; 

try(
    FileOutputStream fos = new FileOutputStream(out); 
    ZipOutputStream zos = new ZipOutputStream(fos); 
){ 
    // Create ZIP file and deliver to client using HTTPServletResponse 
} 
finally{ 
    if (out != null){ 
     out.delete(); 
    } 
} 

File out = // get file; 

try{ 
    try(
     FileOutputStream fos = new FileOutputStream(out); 
     ZipOutputStream zos = new ZipOutputStream(fos); 
    ){ 
     // Create ZIP file and deliver to client using HTTPServletResponse 
    } 
} 
finally{ 
    if (out != null){ 
     out.delete(); 
    } 
} 
0

你可以做這樣的事情在Java 8:

Path path = Files.createTempFile("temp-", ".tmp"); 
try (Closeable onClose =() -> Files.delete(path)) { 
    ... 
} 

但這的確是一樣的:

Path path = Files.createTempFile("temp-", ".tmp"); 
try { 
    ... 
} finally { 
    Files.delete(path); 
}