首页 文章

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

提问于
浏览
392

我很惊讶今天发现我无法找到将 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);
}

21 回答

  • 14

    试试Cactoos

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

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

  • 95

    如果您使用的是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)
    
  • 11

    正如WMR所提到的,来自Apache的 org.apache.commons.io.IOUtils 有一个名为copy(InputStream,OutputStream)的方法,它可以完全满足您的需求 .

    所以你有了:

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

    ...在你的代码中 .

    你有没有理由避免 IOUtils

  • -2

    Java 9

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

    public long transferTo(OutputStream out) throws IOException
    

    正如documentation所述, transferTo 将:

    读取此输入流中的所有字节,并按读取顺序将字节写入给定的输出流 . 返回时,此输入流将位于流的末尾 . 此方法不会关闭任一流 . 此方法可能会无限期地阻止从输入流中读取或写入输出流 . 输入和/或输出流异步关闭或传输过程中线程中断的情况下的行为是高度输入和输出流特定的,因此未指定

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

    input.transferTo(output);
    
  • 6

    我认为这样可行,但一定要测试它......轻微的“改进”,但可读性可能有点费用 .

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

    使用Guava的ByteStreams.copy()

    ByteStreams.copy(inputStream, outputStream);
    
  • 4

    你可以使用这种方法

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

    简单功能

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

    只有在有多个线程时才应使用 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来复制大量数据,或者将数据从流中陷入无法忍受的长时间,这将是一个有用的补充 .

  • 2

    JDK 使用相同的代码,所以看起来没有"easier"方式没有笨重的第三方库(可能不会做任何不同的事情) . 以下内容直接从 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

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

    StreamUtils.copy(in, out);
    

    以上并没有关闭流 . 如果您希望在复制后关闭流,请使用FileCopyUtils class:

    FileCopyUtils.copy(in, out);
    
  • 25

    有's no way to do this a lot easier with JDK methods, but as Apocalisp has already noted, you'并不是唯一一个有这个想法的人:你可以使用Jakarta Commons IO来自Jakarta Commons IO,它还有很多其他有用的东西,IMO实际上应该是JDK的一部分......

  • -5

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

    使用Commons Net的Util类:

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

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

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

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

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

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

    作为旁注,我不要使用 for 循环,而是选择带有assign-and-test表达式的 while ,该表达式被某些人视为"poor"样式 .

  • -2

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

  • 112

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

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

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

  • 303

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

    try (OutputStream out = new BufferedOutputStream(...);
         InputStream in   = new BufferedInputStream(...))) {
      int ch;
      while ((ch = in.read()) != -1) {
        out.write(ch);
      }
    }
    
  • 0
    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;
    }
    

相关问题