2015-12-02 7 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'? –

+0

@RC. да, но использование этого означает, что файл будет удален при завершении работы JVM. В идеале моя JVM не должна закрываться (я разрабатываю REST API). – link

+1

Не пробовал, но что-то похожее на 'try (InputStream in = Files.newInputStream (tempFile, StandardOpenOption.DELETE_ON_CLOSE))' мог бы сработать для вас. Работает с потоками, поэтому, вероятно, это не так удобно, как на основе файлов. – zapl

ответ

3

Try-with-resource просто вызывает метод close для классов, реализующих интерфейсы, реализующие java.lang.AutoCloseable. Ничто не мешает вам создать реализацию Файла, которая реализует AutoCloseable и удаляет себя, когда вызывается функция close().

Вы также можете позвонить в файл deleteOnExit(), чтобы удалить JVM при его завершении. Это подходит только в том случае, если вы в порядке, ожидая, пока JVM не будет завершена, чтобы удалить ваш временный файл. Вероятно, это не будет хорошей идеей для долгого JVM, как Java Webapp.

+0

Спасибо за ваше предложение. Я уже знал о «AutoCloseable», но я надеялся, что что-то подобное уже было реализовано. Поскольку это не так, я сделаю это сам. На всякий случай, я подожду еще немного, прежде чем принимать ваш ответ. – link

+0

@link Я чувствую вашу боль. Удачи, если вы найдете что-то, что делает это конкретно :) Try-with-resource является относительно новым. Если вы создаете класс, который удаляет себя, я бы загрузил его в Git или что-то еще и связал бы его здесь. Я уверен, что другие люди могут его использовать. – Jazzepi

+0

спасибо! Посмотрите мое обновление для очень быстрого решения :) дайте мне знать, если у вас есть предложения! – link

1

Files.createTempFile позволяет создать временный файл в временном каталоге по умолчанию JVM. Это не означает, что файл автоматически удаляется или помечен для удаления с использованием File.deleteOnExit(). Разработчик отвечает за управление жизненным циклом временных файлов.

Имя файла является вектором уязвимостей безопасности. Используйте только имя для отображения в пользовательском интерфейсе для проверки и обратной связи. Не используйте ненадежный пользовательский ввод для имен файлов.

Невозможно управлять жизненным циклом файла с помощью ресурсов try-with-ресурсами, используя java.io.File или java.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's пытается использовать ресурсы, но это не то, что мне интересно делать здесь :) Тем не менее, комментарий об уязвимости безопасности кажется интересным. Я знаю, что это не связано строго, но не могли бы вы рассказать немного больше? – 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 через lambdas

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

Спасибо! Это похоже на мое решение, но я полагаю, что сохранение ссылки на «Путь», как вам может быть лучше, чем сохранение ссылки на «Файл». Я немного поправлю свое решение. – 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); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^