Обработка исключений ввода-вывода в Java - PullRequest
13 голосов
/ 06 июня 2011

Обычно я хочу открыть файл, прочитать несколько байтов, а затем закрыть файл. Вот что я придумал:

try
{
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    try
    {
        // ...
        inputStream.read(buffer);
        // ...
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {
        try
        {
            inputStream.close();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
catch (FileNotFoundException e)
{
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Может быть, я избалован RAII, но должен быть лучший способ сделать это на Java, верно?

Ответы [ 9 ]

11 голосов
/ 06 июня 2011

Если у вас есть один и тот же код обработки исключений для IOException и FileNotFoundException, вы можете переписать ваш пример более компактным способом только с одним предложением catch:

try {
    InputStream input = new BufferedInputStream(new FileInputStream(file));
    try {
        // ...
        input.read(buffer);
        // ...
    }
    finally {
        input.close();
    }
}
catch (IOException e) {
    e.printStackTrace();
}

Вы можете дажеизбавьтесь от внешнего try-catch, если вы можете распространить исключение, которое, вероятно, имеет больше смысла, чем ручная печать трассировки стека.Если вы не поймете какое-то исключение в своей программе, вы автоматически получите для себя трассировку стека.

Также необходимость в том, чтобы вручную закрыть поток, будет решена в Java 7 с автоматическим управлением ресурсами .

При автоматическом управлении ресурсами и распространении исключений код сводится к следующему:

try (InputStream input = new BufferedInputStream(new FileInputStream(file))) {
    // ...
    input.read(buffer);
    // ...
}
2 голосов
/ 06 июня 2011

Обычно эти методы упакованы в библиотеки.Если вы не хотите писать на этом уровне, лучше создать свои собственные вспомогательные методы или использовать существующие, например FileUtils .

String fileAsString = Fileutils.readFileToString(filename);
// OR
for(String line: FileUtils.readLines(filename)) {
    // do something with each line.
}
1 голос
/ 06 июня 2011

Мое мнение об этом без использования утилит будет:

InputStream inputStream = null;
try {
    inputStream = new BufferedInputStream(new FileInputStream(file));
    // ...
    inputStream.read(buffer);
    // ...
} catch (IOException e) {
    e.printStackTrace();
    throw e; // Rethrow if you cannot handle the exception
} finally {
    if (inputStream != null) {
        inputStream.close();
    }
}

Не однострочный, но не очень плохой.Используя, скажем, Apache Commons IO, это будет:

//...
buffer = FileUtils.readFileToByteArray(file);
//...

Помните, что в стандартной Java нет многих из этих маленьких утилит и простых в использовании интерфейсов, которые нужны всем, поэтому вы должны полагаться на некоторыеподдерживать библиотеки, такие как Apache Commons , Google Guava , ... в ваших проектах (или реализовывать собственные служебные классы).

1 голос
/ 06 июня 2011

Иногда вы можете уменьшить код до следующего:

public void foo(String name) throws IOException {
    InputStream in = null;
    try {
        in = new FileInputStream(name);
        in.read();
        // whatever
    } finally {
        if(in != null) {
            in.close();
        }
    }
}

Конечно, это означает, что вызывающий foo должен обрабатывать IOException, но это должно быть в большинстве случаев,В конце концов, вы не сильно уменьшаете сложность, но код становится намного более читабельным благодаря менее вложенным обработчикам исключений.

1 голос
/ 06 июня 2011

Если вы хотите сделать это на простом Java, опубликованный вами код выглядит хорошо.

Вы можете использовать сторонние библиотеки, такие как Commons IO, в которых вам нужно будет писать гораздо меньше кода. например,

Ознакомьтесь с IO Commons по адресу:

http://commons.apache.org/io/description.html

1 голос
/ 06 июня 2011

Я не знаю, правильный ли это путь, но вы можете разместить весь свой код в одном и том же блоке try, а затем располагать различные блоки catch сразу друг за другом.

try {
  ...
}
catch (SomeException e) {
  ...
}
catch (OtherException e) {
  ...
}
0 голосов
/ 06 июня 2011

Google guava попытался решить эту проблему, введя Closeables .

В противном случае вам придется подождать, пока AutoCloseable из JDK 7 не выйдет, поскольку он решает некоторые случаи, когда выбрасывается IOException.

0 голосов
/ 06 июня 2011

Попробуйте следующее:

try
{
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    byte[] buffer = new byte[1024];
    try
    {
        // ...
        int bytesRead = 0;
        while ((bytesRead = inputStream.read(buffer)) != -1) {                
           //Process the chunk of bytes read
        }
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {           
        inputStream.close();
    }
}
catch (FileNotFoundException e)
{
    // TODO Auto-generated catch block
    e.printStackTrace();
}
0 голосов
/ 06 июня 2011

Используйте org.apache.commons.io.FileUtils.readFileToByteArray(File) или что-то подобное из этого пакета.Он по-прежнему выдает IOException, но имеет дело с очисткой для вас.

...