Легкий способ записи содержимого Java InputStream в OutputStream
Я с удивлением обнаружил сегодня, что не смог найти простой способ записать содержимое InputStream
в OutputStream
в Java. Очевидно, что буферный код байта не сложно записать, но я подозреваю, что у меня просто отсутствует что-то, что облегчит мне жизнь (и код станет понятным).
Итак, учитывая InputStream
in
и OutputStream
out
, существует ли более простой способ написать следующее?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Ответы
Ответ 1
Если вы используете Java 7, Files (в стандартной библиотеке) - лучший подход:
/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)
Edit: Конечно, это полезно, когда вы создаете один из InputStream или OutputStream из файла. Используйте file.toPath()
, чтобы получить путь от файла.
Чтобы записать в существующий файл (например, созданный с помощью File.createTempFile()
), вам нужно передать опцию REPLACE_EXISTING
copy (иначе FileAlreadyExistsException
):
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
Ответ 2
Как упоминалось в WMR, org.apache.commons.io.IOUtils
из Apache имеет метод copy(InputStream,OutputStream)
, который делает именно то, что вы ищете.
Итак, у вас есть:
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
... в вашем коде.
Есть ли причина, по которой вы избегаете IOUtils
?
Ответ 3
Java 9
Начиная с Java 9, InputStream
предоставляет метод, называемый transferTo
со следующей подписью:
public long transferTo(OutputStream out) throws IOException
Как указано в документации, transferTo
будет:
Считывает все байты из этого входного потока и записывает байты в данный выходной поток в том порядке, в котором они считываются. По возвращении этот входной поток будет в конце потока. Этот метод не закрывает ни один поток.
Этот метод может блокировать бесконечное чтение из входного потока или записывать в выходной поток. Поведение для случая, когда входной и/или выходной поток асинхронно закрыт, или поток, прерываемый во время передачи, очень специфичен для ввода и вывода, и поэтому не указан
Поэтому, чтобы написать содержимое Java InputStream
для OutputStream
, вы можете написать:
input.transferTo(output);
Ответ 4
Я думаю, что это сработает, но не забудьте проверить его... незначительное "улучшение", но это может быть немного дорогостоящим для читаемости.
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
Ответ 5
Использование Guava ByteStreams.copy()
:
ByteStreams.copy(inputStream, outputStream);
Ответ 6
Простая функция
Если вам это нужно только для записи InputStream
в File
, вы можете использовать эту простую функцию:
private void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Ответ 7
PipedInputStream
и PipedOutputStream
следует использовать только при наличии нескольких потоков, а отмеченных Javadoc.
Также обратите внимание, что потоки ввода и выходные потоки не переносят прерывания потоков с помощью IOException
s... Итак, вам следует рассмотреть возможность включения политики прерывания в ваш код:
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
Это было бы полезным дополнением, если вы планируете использовать этот API для копирования больших объемов данных или данных из потоков, которые застряли в невыносимо долгое время.
Ответ 8
JDK
использует тот же код, поэтому кажется, что нет "более простого" способа без неуклюжих сторонних библиотек (которые, вероятно, вообще не делают ничего другого). Прямо скопировано из java.nio.file.Files.java
:
// buffer size used for reading and writing
private static final int BUFFER_SIZE = 8192;
/**
* Reads all bytes from an input stream and writes them to an output stream.
*/
private static long copy(InputStream source, OutputStream sink)
throws IOException
{
long nread = 0L;
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = source.read(buf)) > 0) {
sink.write(buf, 0, n);
nread += n;
}
return nread;
}
Ответ 9
Для тех, кто использует Spring framework, есть полезный класс StreamUtils:
StreamUtils.copy(in, out);
Вышеупомянутое не закрывает потоки. Если вы хотите, чтобы потоки были закрыты после копии, вместо этого используйте класс FileCopyUtils:
FileCopyUtils.copy(in, out);
Ответ 10
Нет никакого способа сделать это намного проще с помощью методов JDK, но, как уже отмечал Apocalisp, вы не единственный, у кого есть эта идея: вы можете использовать IOUtils из Jakarta Commons IO, у него также есть много других полезных вещей, что ИМО должна фактически быть частью JDK...
Ответ 11
Используя Java7 и try-with-resources, поставляется с упрощенной и читаемой версией.
try(InputStream inputStream = new FileInputStream("C:\\mov.mp4");
OutputStream outputStream = new FileOutputStream("D:\\mov.mp4")){
byte[] buffer = new byte[10*1024];
for (int length; (length = inputStream.read(buffer)) != -1; ){
outputStream.write(buffer, 0, length);
}
}catch (FileNotFoundException exception){
exception.printStackTrace();
}catch (IOException ioException){
ioException.printStackTrace();
}
Ответ 12
Использовать класс сообщества Net Util:
import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
Ответ 13
Вот как я делаю с простейшим для цикла.
private void copy(final InputStream in, final OutputStream out)
throws IOException {
final byte[] b = new byte[8192];
for (int r; (r = in.read(b)) != -1;) {
out.write(b, 0, r);
}
}
Ответ 14
ИМХО более минимальный фрагмент (который также более узко охватывает переменную длины):
byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
out.write(buffer, 0, n);
В качестве побочного примечания я не понимаю, почему больше людей не используют цикл for
, вместо этого предпочитая while
с выражением назначать и тестировать, которое некоторые считают "бедным", стиль.
Ответ 15
Я думаю, что лучше использовать большой буфер, потому что большинство файлов больше 1024 байта. Также неплохо проверить количество положительных байтов чтения.
byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
out.close();
Ответ 16
PipedInputStream и PipedOutputStream могут быть полезны, поскольку вы можете подключить их к другому.
Ответ 17
Другим возможным кандидатом являются утилиты ввода-вывода Guava:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Я думал, что буду использовать их, поскольку Guava уже очень полезен в моем проекте, а не добавляет еще одну библиотеку для одной функции.
Ответ 18
Я использую BufferedInputStream
и BufferedOutputStream
чтобы удалить семантику буферизации из кода
try (OutputStream out = new BufferedOutputStream(...);
InputStream in = new BufferedInputStream(...))) {
int ch;
while ((ch = in.read()) != -1) {
out.write(ch);
}
}
Ответ 19
Это мой лучший снимок !!
И не используйте inputStream.transferTo(...)
потому что он слишком общий. Ваша производительность кода будет лучше, если вы будете контролировать свою буферную память.
public static void transfer(InputStream in, OutputStream out, int buffer) throws IOException {
byte[] read = new byte[buffer]; // Your buffer size.
while (0 < (buffer = in.read(read)))
out.write(read, 0, buffer);
}
Я использую его с этим (улучшаемым) методом, когда заранее знаю размер потока.
public static void transfer(int size, InputStream in, OutputStream out) throws IOException {
transfer(in, out,
size > 0xFFFF ? 0xFFFF // 16bits 65,536
: size > 0xFFF ? 0xFFF// 12bits 4096
: size < 0xFF ? 0xFF // 8bits 256
: size
);
}
Ответ 20
public static boolean copyFile(InputStream inputStream, OutputStream out) {
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try {
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
long endTime=System.currentTimeMillis()-startTime;
Log.v("","Time taken to transfer all bytes is : "+endTime);
out.close();
inputStream.close();
} catch (IOException e) {
return false;
}
return true;
}
Ответ 21
Попробуйте Cactoos:
new LengthOf(new TeeInput(input, output)).value();
Подробнее здесь: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
Ответ 22
вы можете использовать этот метод
public static void copyStream(InputStream is, OutputStream os)
{
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}