Сегодня я с удивлением обнаружил, что не могу отследить какой-либо простой способ записи содержимого объекта InputStream
a OutputStream
в Java. Очевидно, что код байтового буфера не сложно написать, но я подозреваю, что мне просто не хватает чего-то, что сделало бы мою жизнь проще (и код понятнее).
Итак, учитывая an InputStream
in
и an OutputStream
out
, есть ли более простой способ написать следующее?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Ответы:
Java 9
Начиная с Java 9,
InputStream
предоставляется метод, вызываемыйtransferTo
со следующей подписью:Как указано в документации ,
transferTo
будет:Таким образом, чтобы записать содержимое Java
InputStream
вOutputStream
, вы можете написать:источник
Files.copy
как можно больше. Он реализован в собственном коде и поэтому может быть быстрее.transferTo
следует использовать, только если оба потока не являются FileInputStream / FileOutputStream.Files.copy
не обрабатывает никаких входных / выходных потоков , но он специально разработан для файловых потоков.Как упоминалось в WMR,
org.apache.commons.io.IOUtils
у Apache есть метод,copy(InputStream,OutputStream)
который выполняет именно то, что вы ищете.Так что у тебя есть:
... в вашем коде.
Есть ли причина, по которой вы избегаете
IOUtils
?источник
in
и онout
должен быть закрыт в конце кода в блоке finallyЕсли вы используете Java 7, файлы (в стандартной библиотеке) являются лучшим подходом:
Изменить: Конечно, это просто полезно, когда вы создаете один из InputStream или OutputStream из файла. Используйте,
file.toPath()
чтобы получить путь из файла.Чтобы записать в существующий файл (например, созданный с помощью
File.createTempFile()
), вам нужно будет передать параметрREPLACE_EXISTING
копирования (в противном случаеFileAlreadyExistsException
выбрасывается):источник
Files
это не доступно в Android Java 1.7. Меня задело это: stackoverflow.com/questions/24869323/…Files.copy()
который принимает два потока, и это то, что все остальныеFiles.copy()
функции ожидают, чтобы выполнить реальную работу по копированию. Тем не менее, он является закрытым (поскольку на этом этапе он фактически не включает Paths или Files) и выглядит точно так же, как код в собственном вопросе OP (плюс оператор return). Нет открытия, нет закрытия, просто цикл копирования.Я думаю, что это сработает, но не забудьте проверить это ... незначительное "улучшение", но это может быть немного дорого при удобочитаемости.
источник
while(len > 0)
вместо!= -1
, потому что последний может также вернуть 0 при использованииread(byte b[], int off, int len)
-method, который выдает исключение @out.write
InputStream
контракту это вполне законно для чтения, чтобы возвращать 0 любое количество раз. В соответствии сOutputStream
контрактом, метод write должен принимать длину 0 и генерировать исключение только в случаеlen
отрицательного значения.while
кfor
и положить одну из переменных в Близится инициализации раздел: например,for (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
. =)read()
может возвращать ноль только в том случае, если вы указали длину нуля, что было бы ошибкой программирования и глупым условием для бесконечного цикла. Иwrite()
это не исключение , если вы предоставите нулевую длину.Использование гуавы
ByteStreams.copy()
:источник
Files.copy
как можно больше. ИспользуйтеByteStreams.copy
только если оба потока не являются FileInputStream / FileOutputStream.Простая функция
Если вам это нужно только для записи
InputStream
в a,File
тогда вы можете использовать эту простую функцию:источник
close()
звонкиfinally
блокировались?Он
JDK
использует тот же код, поэтому кажется, что нет «более простого» пути без неуклюжих сторонних библиотек (которые, вероятно, в любом случае не делают ничего другого). Следующее непосредственно скопировано изjava.nio.file.Files.java
:источник
PipedInputStream
иPipedOutputStream
должен использоваться только тогда, когда у вас есть несколько потоков, как отмечено Javadoc .Также обратите внимание, что входные и выходные потоки не переносят прерывания потоков на
IOException
s ... Итак, вам следует рассмотреть возможность включения политики прерывания в ваш код:Это было бы полезным дополнением, если вы планируете использовать этот API для копирования больших объемов данных или данных из потоков, которые застревают на недопустимо долгое время.
источник
Для тех, кто использует Spring Framework, есть полезный класс StreamUtils :
Вышеуказанное не закрывает потоки. Если вы хотите, чтобы потоки были закрыты после копирования, используйте класс FileCopyUtils :
источник
Нет никакого способа сделать это намного проще с помощью методов JDK, но, как уже отмечал Apocalisp , вы не единственные с этой идеей: вы можете использовать IOUtils из Jakarta Commons IO , у него также есть много других полезных вещей, что ИМО на самом деле должна быть частью JDK ...
источник
Используя Java7 и try-with-resources , поставляется с упрощенной и читаемой версией.
источник
Вот как я делаю с простейшим для цикла.
источник
Используйте класс Util Commons Net:
источник
ИМХО более минимальный фрагмент (который также более узко ограничивает переменную длины):
В качестве примечания, я не понимаю, почему все больше людей не используют
for
цикл, вместо этого выбираяwhile
с выражением «назначить и проверить», которое некоторые считают «плохим» стилем.источник
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Это мой лучший снимок !!
И не используйте,
inputStream.transferTo(...)
потому что это слишком общий характер. Ваша производительность кода будет лучше, если вы будете контролировать свою буферную память.Я использую его с этим (улучшаемым) методом, когда заранее знаю размер потока.
источник
Я думаю, что лучше использовать большой буфер, потому что большинство файлов больше 1024 байтов. Также рекомендуется проверять количество прочитанных байтов, чтобы оно было положительным.
источник
Я использую
BufferedInputStream
иBufferedOutputStream
удалить семантику буферизации из кодаисточник
PipedInputStream и PipedOutputStream могут быть полезны, так как вы можете подключить одно к другому.
источник
Другой возможный кандидат - утилиты ввода / вывода Guava:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Я думал, что буду использовать их, так как Guava уже очень полезен в моем проекте, вместо того, чтобы добавлять еще одну библиотеку для одной функции.
источник
copy
иtoByteArray
методы в docs.guava-libraries.googlecode.com/git-history/release/javadoc/… (гуава называет потоки ввода / вывода как «байтовые потоки», а читатели / писатели - как «потоки символов»)Не очень читаемый, но эффективный, не имеет зависимостей и работает с любой версией Java
источник
!= -1
или> 0
? Эти предикаты не совсем одинаковы.источник
Попробуйте Cactoos :
Более подробная информация здесь: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
источник
Вы можете использовать этот метод
источник
catch(Exception ex){}
- это первоклассно