我惊奇地发现,今天我找不到任何简单的方法来用Java将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);
}
正如Javadoc所指出的那样,PipedInputStream和PipedOutputStream只能在有多个线程时使用。
另外,请注意输入流和输出流不会用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复制大量数据,或者从流中复制长时间无法忍受的数据,那么这将是一个有用的补充。
如果你正在使用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)
Java 9
自Java 9以来,InputStream提供了一个名为transferTo的方法,具有以下签名:
public long transferTo(OutputStream out) throws IOException
如文档所述,transferTo将:
Reads all bytes from this input stream and writes the bytes to the
given output stream in the order that they are read. On return, this
input stream will be at end of stream. This method does not close
either stream.
This method may block indefinitely reading from the
input stream, or writing to the output stream. The behavior for the
case where the input and/or output stream is asynchronously closed, or
the thread interrupted during the transfer, is highly input and output
stream specific, and therefore not specified
因此,为了将Java InputStream的内容写入到OutputStream,你可以这样写:
input.transferTo(output);
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;
}
这是我最好的机会!!
不要使用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
);
}
我使用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);
}
}