简单的方法将Java InputStream的内容写入OutputStream
今天我惊讶地发现,我无法find任何简单的方法来将InputStream
的内容写入到Java中的OutputStream
中。 显然,字节缓冲区的代码不难写,但是我怀疑我只是错过了一些能让我的生活更轻松(而且代码更清晰)的东西。
所以,给一个InputStream
和一个OutputStream
,有没有更简单的方法来编写以下内容?
byte[] buffer = new byte[1024]; int len = in.read(buffer); while (len != -1) { out.write(buffer, 0, len); len = in.read(buffer); }
正如WMR提到的,来自Apache的org.apache.commons.io.IOUtils
有一个叫做copy(InputStream,OutputStream)
,它正是你所要找的。
所以,你有:
InputStream in; OutputStream out; IOUtils.copy(in,out); in.close(); out.close();
…在你的代码。
你有避免IOUtils
的原因吗?
如果您使用Java 7,则文件 (在标准库中)是最好的方法:
/* You can get Path from file also: file.toPath() */ Files.copy(InputStream in, Path target) Files.copy(Path source, OutputStream out)
编辑:当然,从文件中创buildInputStream或OutputStream时,它是很有用的。 使用file.toPath()
从文件中获取path。
要写入现有文件(例如使用File.createTempFile()
创build的文件),您需要传递REPLACE_EXISTING
复制选项(否则引发FileAlreadyExistsException
):
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
我认为这将起作用,但是要确保testing它…小的“改进”,但是在可读性方面可能会有一点成本。
byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); }
Java 9
从Java 9开始, InputStream
提供了一个名为transferTo
的方法,其签名如下:
public long transferTo(OutputStream out) throws IOException
正如文档所述, transferTo
将:
从该inputstream中读取所有字节,并按照读取的顺序将字节写入给定的输出stream。 返回时,这个inputstream将在stream的末尾。 此方法不closures任何stream。
这种方法可能会无限期地从inputstream中读取数据,或者写入输出数据stream。 input和/或输出streamasynchronousclosures或者在传输过程中线程中断的情况下的行为是高度input和输出stream特定的,因此没有指定
所以为了将Java InputStream
内容写入到OutputStream
,可以这样写:
input.transferTo(output);
使用番石榴的ByteStreams.copy()
:
ByteStreams.copy(inputStream, outputStream);
简单的function
如果你只需要将这个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(); } }
PipedInputStream
和PipedOutputStream
应该只在有多个线程时使用,如Javadoc所述 。
另外,请注意inputstream和输出stream不会用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来复制大量的数据,或者来自数据stream的数据难以忍受,那么这将是一个有用的补充。
使用JDK方法没有办法做到这一点,但是正如Apocalisp已经指出的那样,您不是唯一有这个想法的人:您可以使用来自Jakarta Commons IO的 IOUtils ,它还有很多其他有用的东西,国际海事组织实际上应该是JDK的一部分
使用Java7并尝试与资源 ,来与一个简化和可读的版本。
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(); }
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; }
使用Commons Net的Util类:
import org.apache.commons.net.io.Util; ... Util.copyStream(in, out);
我认为最好使用一个大的缓冲区,因为大部分文件大于1024字节。 此外,检查读取字节数是肯定的是一个好习惯。
byte[] buffer = new byte[4096]; int n; while ((n = in.read(buffer)) > 0) { out.write(buffer, 0, n); } out.close();
这里是我如何做最简单的循环。
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); } }
对于那些使用Spring框架的人来说,有一个有用的StreamUtils类:
StreamUtils.copy(in, out);
以上不closuresstream。 如果您想在复制之后closuresstream,请改用FileCopyUtils类:
FileCopyUtils.copy(in, out);
PipedInputStream和PipedOutputStream可能有一些用处,因为你可以将一个连接到另一个。
另一个可能的候选者是番石榴I / O公用事业:
http://code.google.com/p/guava-libraries/wiki/IOExplained
我以为我会使用这些,因为番石榴在我的项目中已经非常有用,而不是增加另一个函数库。
一个恕我直言更多最小的片段(也更狭窄范围的长度variables):
byte[] buffer = new byte[2048]; for (int n = in.read(buffer); n >= 0; n = in.read(buffer)) out.write(buffer, 0, n);
作为一个侧面说明,我不明白为什么更多的人不使用for
循环,而是select一个被认为是“穷人”风格的分配和testingexpression式。
尝试Cactoos :
new LengthOf(new TeeInput(input, output)).value();
更多细节在这里: http : //www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
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; }
你可以使用这个方法
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){} }