将Java InputStream的内容写入OutputStream的简便方法

时间:2008-09-04 03:46:16

标签: java io stream

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

所以,鉴于InputStream inOutputStream out,是否有更简单的方法来编写以下内容?

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
}

24 个答案:

答案 0 :(得分:382)

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

所以,你有:

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

...在您的代码中。

您是否有理由避免IOUtils

答案 1 :(得分:313)

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

/* 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)

答案 2 :(得分:122)

Java 9

自Java 9起,InputStream提供了一个名为transferTo的方法,其签名如下:

public long transferTo(OutputStream out) throws IOException

documentation州,transferTo将:

  

从此输入流中读取所有字节并将字节写入   按照读取的顺序给出输出流。回来后,这个   输入流将在流的末尾。此方法不会关闭   要么流。

     

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

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

input.transferTo(output);

答案 3 :(得分:96)

我认为这样可行,但请务必对其进行测试......轻微的“改进”,但可读性可能会有点费用。

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}

答案 4 :(得分:47)

使用Guava' ByteStreams.copy()

ByteStreams.copy(inputStream, outputStream);

答案 5 :(得分:25)

简单功能

如果您只需要将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();
    }
}

答案 6 :(得分:15)

PipedInputStreamPipedOutputStream只应在有多个主题时使用noted by the Javadoc

另请注意,输入流和输出流不会使用IOException包装任何线程中断...因此,您应该考虑在代码中加入中断策略:

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来复制大量数据,或者来自流量过长的数据,这将是一个非常有用的补充。

答案 7 :(得分:14)

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;
    }

答案 8 :(得分:11)

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

StreamUtils.copy(in, out);

上面没有关闭流。如果您希望在复制后关闭流,请改为使用FileCopyUtils类:

FileCopyUtils.copy(in, out);

答案 9 :(得分:8)

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

答案 10 :(得分:6)

使用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();
    }

答案 11 :(得分:4)

使用Commons Net的Util类:

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);

答案 12 :(得分:4)

这就是我如何使用最简单的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);
    }
}

答案 13 :(得分:3)

一个恕我直言的更小的片段(也更窄范围长度变量):

    <form id="genderform" action="" >
        What percentage of musicians do you think are men?<br />
        <input type="text" id="men" /><br /><br />
        What percentage of musicians do you think are women?<br />
        <input type="text" id="women" /><br /><br />
        <input type="submit" value="submit" />
    </form>
<p id="text">Results:</p>
<p id="div" style="background-color: #ff0000; height:50px; width: 1px;"></p>

<script type="text/javascript">
    document.getElementById("genderform").onsubmit=function() {
    men = document.getElementById("men").value;
    women = document.getElementById("women").value;
    document.getElementById("text").innerHTML = "Results: <br>" + "Men: " + men + "%<br>Women: " + women + "%";
            document.getElementById("div").style.width = women + "%";
    return false;
    }
</script>

作为旁注,我不明白为什么更多人不使用byte[] buffer = new byte[2048]; for (int n = in.read(buffer); n >= 0; n = in.read(buffer)) out.write(buffer, 0, n); 循环,而是选择for带有一个被一些人认为的赋值和测试表达式作为“穷人”的风格。

答案 14 :(得分:2)

我认为最好使用大缓冲区,因为大多数文件大于1024字节。另外,最好将读取的字节数检查为正数。

byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
out.close();

答案 15 :(得分:0)

PipedInputStream和PipedOutputStream可能会有用,因为你可以将它们连接到另一个。

答案 16 :(得分:0)

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

try (OutputStream out = new BufferedOutputStream(...);
     InputStream in   = new BufferedInputStream(...))) {
  int ch;
  while ((ch = in.read()) != -1) {
    out.write(ch);
  }
}

答案 17 :(得分:0)

这是我最好的镜头!

也不要使用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
    );
}

答案 18 :(得分:0)

不是很可读,但是有效,没有依赖关系,并且可以在任何Java版本上运行

byte[] buffer = new byte[1024];
for (int n; (n = inputStream.read(buffer)) != -1; outputStream.write(buffer, 0, n));

答案 19 :(得分: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);
    }
}

答案 20 :(得分:0)

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

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

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

答案 21 :(得分:-2)

尝试Cactoos

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

此处有更多详情:http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html

答案 22 :(得分:-2)

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;
}

答案 23 :(得分:-5)

你可以使用这种方法

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){}
 }