提问人:Matt Sheppard 提问时间:9/4/2008 最后编辑:SledMatt Sheppard 更新时间:10/31/2021 访问量:494339
将 Java InputStream 的内容写入 OutputStream 的简单方法
Easy way to write contents of a Java InputStream to an OutputStream
问:
今天我惊讶地发现,我无法找到任何简单的方法来在 Java 中将 an to an 的内容写入。显然,字节缓冲区代码并不难写,但我怀疑我只是缺少一些可以让我的生活更轻松(并且代码更清晰)的东西。InputStream
OutputStream
那么,给定 an 和 an ,有没有更简单的方法来写以下内容呢?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);
}
答:
我认为这会起作用,但请务必对其进行测试......轻微的“改进”,但在可读性方面可能会有点成本。
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
评论
while(len > 0)
!= -1
read(byte b[], int off, int len)
out.write
InputStream
OutputStream
len
while
for
for (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
read()
write()
PipedInputStream 和 PipedOutputStream 可能有一些用处,因为您可以将一个连接到另一个。
评论
使用 JDK 方法没有办法更容易做到这一点,但正如 Apocalisp 已经指出的那样,您不是唯一一个有这个想法的人:您可以使用 Jakarta Commons IO 的 IOUtils,它还有很多其他有用的东西,IMO 实际上应该成为 JDK 的一部分......
正如 WMR 所提到的,Apache 有一个名为 copy(InputStream,OutputStream) 的方法,
它完全可以满足您的需求。org.apache.commons.io.IOUtils
所以,你有:
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
...在您的代码中。
你回避是有原因的吗?IOUtils
评论
PipedInputStream
并且应该仅在有多个线程时使用,如 Javadoc 所述。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 来复制大量数据,或者从卡住很长时间的流中复制数据,这将是一个有用的补充。
另一个可能的候选者是 Guava I/O 实用程序:
http://code.google.com/p/guava-libraries/wiki/IOExplained
我想我会使用这些,因为 Guava 在我的项目中已经非常有用,而不是为一个函数添加另一个库。
评论
copy
toByteArray
我认为最好使用大缓冲区,因为大多数文件都大于 1024 字节。此外,最好检查读取字节数为正数。
byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
out.close();
评论
功能简单
如果你只需要这个来写一个,那么你可以使用这个简单的函数: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();
}
}
评论
close()
finally
如果您使用的是 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()
要写入现有文件(例如,使用 创建的文件),您需要传递 copy 选项(否则会抛出):File.createTempFile()
REPLACE_EXISTING
FileAlreadyExistsException
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
评论
Files
Files.copy()
Files.copy()
使用 Commons Net 的 Util 类:
import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
您可以使用此方法
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){}
}
评论
catch(Exception ex){}
— 这是一流的
使用 Guava 的 ByteStreams.copy():
ByteStreams.copy(inputStream, outputStream);
评论
Files.copy
ByteStreams.copy
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;
}
评论
使用 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();
}
评论
恕我直言,一个更小的片段(也更狭窄地限定了长度变量的范围):
byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
out.write(buffer, 0, n);
顺便说一句,我不明白为什么越来越多的人不使用循环,而是选择带有赋值和测试表达式的表达式,这被一些人认为是“糟糕”的风格。for
while
评论
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
这是我如何使用最简单的 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);
}
}
Java 9 (英语)
从 Java 9 开始,提供了一个使用以下签名调用的方法:InputStream
transferTo
public long transferTo(OutputStream out) throws IOException
如文档所述,将:transferTo
从此输入流中读取所有字节,并将这些字节写入 按读取顺序给定输出流。返回时,这 输入流将位于流的末尾。此方法不会关闭 任一流。
此方法可能会无限期地阻止从 输入流,或写入输出流。的行为 输入和/或输出流异步关闭的情况,或 在传输过程中中断的线程,是高度输入和输出的 特定于流,因此未指定
因此,为了将 Java 的内容写入 ,您可以编写:InputStream
OutputStream
input.transferTo(output);
评论
Files.copy
transferTo
Files.copy
transferTo
Files.copy(in, out)
它使用相同的代码,因此如果没有笨拙的第三方库(无论如何,它们可能不会做任何不同的事情),似乎没有“更简单”的方法。以下内容直接复制自: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;
}
评论
对于那些使用 Spring 框架的人来说,有一个有用的 StreamUtils 类:
StreamUtils.copy(in, out);
以上内容不会关闭流。如果要在复制后关闭流,请改用 FileCopyUtils 类:
FileCopyUtils.copy(in, out);
试试 Cactoos:
new LengthOf(new TeeInput(input, output)).value();
更多详情请见:http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
我使用 和 从代码中删除缓冲语义BufferedInputStream
BufferedOutputStream
try (OutputStream out = new BufferedOutputStream(...);
InputStream in = new BufferedInputStream(...))) {
int ch;
while ((ch = in.read()) != -1) {
out.write(ch);
}
}
评论
这是我最好的镜头!!
并且不要使用 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
);
}
评论
InputStream.transferTo(OutputStream)
transferTo
可读性不是很强,但很有效,没有依赖关系,可以与任何 java 版本一起运行
byte[] buffer=new byte[1024];
for(int n; (n=inputStream.read(buffer))!=-1; outputStream.write(buffer,0,n));
评论
!= -1
或?这些谓词并不完全相同。> 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);
}
}
上一个:被 python 文件模式“w+”[重复] 弄糊涂了
下一个:计算方法的执行时间
评论