Разве закрытие FileOutPutStream ничего не записывает в файл? - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть функция, которая записывает заданный входной поток в заданный выходной поток.Код ниже.

static void copyStream(InputStream is, OutputStream os) throws IOException {
    byte[] buffer = new byte[4096];
    int len;
    try {
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
    }
}    

Вышеупомянутая функция вызывается из этой функции

public static void copyFile(File srcFile, File destFile) throws IOException {
    FileInputStream fis = new FileInputStream(srcFile);
    try {
        FileOutputStream fos = new FileOutputStream(destFile);
        try {
            **copyStream**(fis, fos);
        } finally {
            if (fos != null)
                fos.close();
        }
    } finally {
        if (fis != null)
            fis.close();
    }
}

В этой функции я пишу 4 МБ за раз.Я использую эту функцию для копирования изображений.Иногда я вижу, что целевой файл не создается, из-за чего возникает исключение при попытке прочитать этот файл для дальнейшей обработки.Я предполагаю, что виновник не закрывает ресурсы.Хороша ли моя гипотеза?Каковы причины, по которым моя функция может не работать?Пожалуйста, помогите

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Да, вы обязательно должны закрыть файл назначения, чтобы гарантировать, что все кэши от JVM до ОС очищены и файл готов для чтения читателем.

Копирование больших файлов так, как выделать в коде сжато, но неэффективно в работе.Рассмотрите возможность обновления вашего кода для использования более эффективных методов NIO, документированных здесь в сообщении в блоге.В случае, если этот блог исчезает, вот код:

Класс утилит:

public final class ChannelTools {
  public static void fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
    final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
    while (src.read(buffer) != -1) {
      // prepare the buffer to be drained
      buffer.flip();
      // write to the channel, may block
      dest.write(buffer);
      // If partial transfer, shift remainder down
      // If buffer is empty, same as doing clear()
      buffer.compact();
    }
    // EOF will leave buffer in fill state
    buffer.flip();
    // make sure the buffer is fully drained.
    while (buffer.hasRemaining()) {
      dest.write(buffer);
    }
  }
}

Пример использования с вашими InputStream и OutputStream:

// allocate the stream ... only for example
final InputStream input = new FileInputStream(inputFile);
final OutputStream output = new FileOutputStream(outputFile);
// get an channel from the stream
final ReadableByteChannel inputChannel = Channels.newChannel(input);
final WriteableByteChannel outputChannel = Channels.newChannel(output);
// copy the channels
ChannelTools.fastChannelCopy(inputChannel, outputChannel);
// closing the channels
inputChannel.close();
outputChannel.close()

Тамэто также более краткий метод, описанный в Wikipedia , который достигает того же самого с меньшим количеством кода:

// Getting file channels
FileChannel in = new FileInputStream(source).getChannel();
FileChannel out = new FileOutputStream(target).getChannel();

// JavaVM does its best to do this as native I/O operations.
in.transferTo(0, in.size(), out);

// Closing file channels will close corresponding stream objects as well.
out.close();
in.close();
0 голосов
/ 23 ноября 2018

Я считаю, что данные InputStream и OutputStream установлены правильно.Добавьте os.flush(); в конце.Конечно, оба потока также должны быть закрыты в вызывающей стороне.

В качестве альтернативы вы можете использовать Apache IO utils org.apache.commons.io.IOUtils.copy(InputStream input, OutputStream output).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...