题
今天我惊讶地发现我无法找到任何简单的方法来编写内容 InputStream
到一个 OutputStream
在爪哇。显然,字节缓冲区代码并不难编写,但我怀疑我只是错过了一些可以让我的生活更轻松(并且代码更清晰)的东西。
所以,给定一个 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);
}
解决方案
如果您使用的是 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)
其他提示
正如 WMR 提到的, org.apache.commons.io.IOUtils
Apache 有一个方法叫做 copy(InputStream,OutputStream)
这正是您正在寻找的。
所以你有了:
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
...在你的代码中。
你有什么理由回避 IOUtils
?
爪哇9
从 Java 9 开始, InputStream
提供了一个方法叫做 transferTo
带有以下签名:
public long transferTo(OutputStream out) throws IOException
作为 文档 状态, transferTo
将要:
从此输入流读取所有字节,并按照它们的读取顺序将字节写入给定的输出流。返回时,此输入流将在流的末尾。此方法不会关闭任何一个流。
此方法可能会无限期地阻止从输入流读取或写入输出流。输入和/或输出流的情况异步关闭的情况,或者在传输过程中中断的线程是高度输入和输出流的特定的,因此未指定
所以为了写一个Java的内容 InputStream
到一个 OutputStream
, , 你可以写:
input.transferTo(output);
我认为这会起作用,但一定要测试它......微小的“改进”,但这可能会降低可读性。
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
使用番石榴的 ByteStreams.copy()
:
ByteStreams.copy(inputStream, outputStream);
简单的功能
如果您只需要这个来编写 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 指出.
另请注意,输入流和输出流不会将任何线程中断包装为 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 复制大量数据或来自卡住时间过长的流中的数据,这将是一个有用的补充。
这 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;
}
使用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();
}
使用 Commons Net 的 Util 类:
import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
这是我如何使用最简单的 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);
}
}
恕我直言,更小的片段(也更缩小了长度变量的范围):
byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
out.write(buffer, 0, n);
顺便说一句,我不明白为什么更多的人不使用 for
循环,而不是选择 while
使用分配和测试表达式被一些人认为是“糟糕”的风格。
我认为最好使用大缓冲区,因为大多数文件都大于 1024 字节。检查读取字节数是否为正也是一个好习惯。
byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
out.close();
PipedInputStream 和 PipedOutputStream 可能会有一些用处,因为您可以将其中一个连接到另一个。
另一个可能的候选者是 Guava I/O 实用程序:
http://code.google.com/p/guava-libraries/wiki/IOExplained
我想我会使用这些,因为 Guava 在我的项目中已经非常有用,而不是为一个函数添加另一个库。
我用 BufferedInputStream
和 BufferedOutputStream
从代码中删除缓冲语义
try (OutputStream out = new BufferedOutputStream(...);
InputStream in = new BufferedInputStream(...))) {
int ch;
while ((ch = in.read()) != -1) {
out.write(ch);
}
}
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;
}
尝试 仙人掌:
new LengthOf(new TeeInput(input, output)).value();
更多详细信息请参见此处: http://www.yegor256.com/2017/06/22/object-orient-input-output-in-cactoos.html
你可以使用这个方法
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){}
}