482

今天我惊讶地发现我无法找到任何简单的方法来用JavaInputStream将 an的内容写入 an OutputStream。显然,字节缓冲区代码并不难编写,但我怀疑我只是遗漏了一些可以让我的生活更轻松(并且代码更清晰)的东西。

那么,给定 anInputStream 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);
}
4

24 回答 24

408

正如 WMR 所提到的,org.apache.commons.io.IOUtils来自 Apache 有一个名为的方法copy(InputStream,OutputStream),它完全符合您的要求。

所以你有了:

InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();

...在您的代码中。

你有避免的原因IOUtils吗?

于 2008-09-09T12:36:43.507 回答
336

如果您使用的是 Java 7,文件(在标准库中)是最好的方法:

/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)

编辑:当然,当您从文件创建 InputStream 或 OutputStream 之一时它很有用。用于file.toPath()从文件中获取路径。

要写入现有文件(例如使用 创建的文件File.createTempFile()),您需要传递REPLACE_EXISTING复制选项(否则FileAlreadyExistsException会被抛出):

Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
于 2013-10-05T06:03:45.433 回答
221

爪哇 9

从 Java 9 开始,提供了一个使用以下签名InputStream调用的方法:transferTo

public long transferTo(OutputStream out) throws IOException

正如文件所述,transferTo将:

从此输入流中读取所有字节,并按照读取顺序将字节写入给定的输出流。返回时,此输入流将位于流的末尾。此方法不会关闭任何一个流。

此方法可能会无限期地阻止从输入流读取或写入输出流。输入和/或输出流异步关闭或传输期间线程中断的情况的行为是高度特定于输入和输出流的,因此未指定

因此,为了将 JavaInputStream的内容写入OutputStream,您可以编写:

input.transferTo(output);
于 2016-09-11T21:44:31.193 回答
109

我认为这会起作用,但请确保对其进行测试......轻微的“改进”,但这可能会降低可读性。

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}
于 2008-09-04T03:58:20.707 回答
57

使用番石榴的ByteStreams.copy()

ByteStreams.copy(inputStream, outputStream);
于 2014-03-26T10:12:22.107 回答
30

简单功能

如果你只需要这个来写一个InputStreamFile那么你可以使用这个简单的函数:

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();
    }
}
于 2013-09-13T19:33:32.950 回答
21

使用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;
}
于 2016-10-13T11:10:11.450 回答
20

对于那些使用Spring 框架的人来说,有一个有用的StreamUtils类:

StreamUtils.copy(in, out);

以上不会关闭流。如果您希望在复制后关闭流,请改用FileCopyUtils类:

FileCopyUtils.copy(in, out);
于 2017-02-02T14:33:08.910 回答
18

PipedInputStream并且PipedOutputStream仅应在您有多个线程时使用,如Javadoc 所述

另外,请注意输入流和输出流不会用IOExceptions 包装任何线程中断...因此,您应该考虑将中断策略合并到您的代码中:

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 来复制大量数据,或者从卡住时间过长的流中复制数据,这将是一个有用的补充。

于 2009-02-12T10:37:28.557 回答
8

使用 JDK 方法无法更轻松地做到这一点,但正如 Apocalisp 已经指出的那样,你不是唯一一个有这个想法的人:你可以使用Jakarta Commons IO的IOUtils,它还有很多其他有用的东西, IMO 实际上应该是 JDK 的一部分...

于 2008-09-04T10:50:10.450 回答
7

使用 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();
}
于 2015-08-21T08:52:19.760 回答
6

下面是我如何使用最简单的 for 循环。

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);
    }
}
于 2016-08-22T01:17:50.593 回答
4

使用 Commons Net 的 Util 类:

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
于 2013-11-11T20:56:35.813 回答
4

我使用BufferedInputStreamBufferedOutputStream从代码中删除缓冲语义

try (OutputStream out = new BufferedOutputStream(...);
     InputStream in   = new BufferedInputStream(...))) {
  int ch;
  while ((ch = in.read()) != -1) {
    out.write(ch);
  }
}
于 2019-01-20T02:04:10.523 回答
3

恕我直言,更小的片段(也更窄地限定了长度变量):

byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
    out.write(buffer, 0, n);

作为旁注,我不明白为什么更多的人不使用for循环,而是选择while带有被某些人视为“差”风格的分配和测试表达式。

于 2015-12-10T00:29:32.200 回答
2

我认为最好使用大缓冲区,因为大多数文件都大于 1024 字节。此外,检查读取字节数是否为正也是一个好习惯。

byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
out.close();
于 2013-09-13T14:24:37.087 回答
2

这是我最好的镜头!!

并且不要使用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
    );
}
于 2019-07-11T00:13:01.240 回答
2

可读性不强,但有效,没有依赖关系,可以使用任何 java 版本运行

byte[] buffer=new byte[1024];
for(int n; (n=inputStream.read(buffer))!=-1; outputStream.write(buffer,0,n));
于 2020-03-21T13:13:27.747 回答
0

PipedInputStream 和 PipedOutputStream 可能会有一些用处,因为您可以将一个连接到另一个。

于 2008-09-04T04:04:07.480 回答
0

另一个可能的候选者是 Guava I/O 实用程序:

http://code.google.com/p/guava-libraries/wiki/IOExplained

我想我会使用这些,因为 Guava 在我的项目中已经非常有用,而不是为一个函数添加另一个库。

于 2012-12-11T05:42:34.057 回答
0

我用的ByteStreamKt.copyTo(src, dst, buffer.length)方法

这是我的代码

public static void replaceCurrentDb(Context context, Uri newDbUri) {
    try {
        File currentDb = context.getDatabasePath(DATABASE_NAME);
        if (currentDb.exists()) {
            InputStream src = context.getContentResolver().openInputStream(newDbUri);
            FileOutputStream dst = new FileOutputStream(currentDb);
            final byte[] buffer = new byte[8 * 1024];
            ByteStreamsKt.copyTo(src, dst, buffer.length);
            src.close();
            dst.close();
            Toast.makeText(context, "SUCCESS! Your selected file is set as current menu.", Toast.LENGTH_LONG).show();
        }
        else
            Log.e("DOWNLOAD:::: Database", " fail, database not found");
    }
    catch (IOException e) {
        Toast.makeText(context, "Data Download FAIL.", Toast.LENGTH_LONG).show();
        Log.e("DOWNLOAD FAIL!!!", "fail, reason:", e);
    }
}
于 2021-07-23T09:41:43.607 回答
-1
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;
}
于 2015-04-02T18:48:24.763 回答
-1

试试仙人掌

new LengthOf(new TeeInput(input, output)).value();

更多细节在这里:http ://www.yegor256.com/2017/06/22/object-orientated-input-output-in-cactoos.html

于 2017-09-21T16:06:09.463 回答
-6

你可以使用这个方法

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){}
 }
于 2014-03-06T11:23:20.440 回答