Java 将输入流连接到输出流
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1574837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Connecting an input stream to an outputstream
提问by jbu
update in java9: https://docs.oracle.com/javase/9/docs/api/java/io/InputStream.html#transferTo-java.io.OutputStream-
java9 中的更新:https://docs.oracle.com/javase/9/docs/api/java/io/InputStream.html#transferTo-java.io.OutputStream-
I saw some similar, but not-quite-what-i-need threads.
我看到了一些类似但不是我需要的线程。
I have a server, which will basically take input from a client, client A, and forward it, byte for byte, to another client, client B.
我有一个服务器,它基本上会从客户端客户端 A 获取输入,并将其逐字节转发到另一个客户端客户端 B。
I'd like to connect my inputstream of client A with my output stream of client B. Is that possible? What are ways to do that?
我想将客户端 A 的输入流与客户端 B 的输出流连接起来。这可能吗?有什么方法可以做到这一点?
Also, these clients are sending each other messages, which are somewhat time sensitive, so buffering won't do. I do not want a buffer of say 500 and a client sends 499 bytes and then my server holds off on forwarding the 500 bytes because it hasn't received the last byte to fill the buffer.
此外,这些客户端正在相互发送消息,这些消息对时间敏感,因此缓冲不起作用。我不想要一个 500 的缓冲区,客户端发送 499 个字节,然后我的服务器推迟转发 500 个字节,因为它没有收到填充缓冲区的最后一个字节。
Right now, I am parsing each message to find its length, then reading length bytes, then forwarding them. I figured (and tested) this would be better than reading a byte and forwarding a byte over and over because that would be very slow. I also did not want to use a buffer or a timer for the reason I stated in my last paragraph — I do not want messages waiting a really long time to get through simply because the buffer isn't full.
现在,我正在解析每条消息以找到它的长度,然后读取长度字节,然后转发它们。我认为(并测试)这比读取一个字节并一遍又一遍地转发一个字节要好,因为那会非常慢。我也不想使用缓冲区或计时器,原因是我在上一段中所述——我不希望消息等待很长时间才能通过,因为缓冲区未满。
What's a good way to do this?
有什么好方法可以做到这一点?
回答by Jon Skeet
Just because you use a buffer doesn't mean the stream has to fillthat buffer. In other words, this should be okay:
仅仅因为您使用缓冲区并不意味着流必须填充该缓冲区。换句话说,这应该没问题:
public static void copyStream(InputStream input, OutputStream output)
throws IOException
{
byte[] buffer = new byte[1024]; // Adjust if you want
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1)
{
output.write(buffer, 0, bytesRead);
}
}
That should work fine - basically the read
call will block until there's somedata available, but it won't wait until it's allavailable to fill the buffer. (I suppose it could, and I believe FileInputStream
usually willfill the buffer, but a stream attached to a socket is more likely to give you the data immediately.)
这应该可以正常工作 - 基本上read
调用会阻塞,直到有一些数据可用,但它不会等到所有数据都可用来填充缓冲区。(我想它可以,而且我相信FileInputStream
通常会填充缓冲区,但是附加到套接字的流更有可能立即为您提供数据。)
I think it's worth at least trying this simple solution first.
我认为至少值得先尝试这个简单的解决方案。
回答by Stephan
You can use a circular buffer :
您可以使用循环缓冲区:
Code
代码
// buffer all data in a circular buffer of infinite size
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
class1.putDataOnOutputStream(cbb.getOutputStream());
class2.processDataFromInputStream(cbb.getInputStream());
Maven dependency
Maven 依赖
<dependency>
<groupId>org.ostermiller</groupId>
<artifactId>utils</artifactId>
<version>1.07.00</version>
</dependency>
Mode details
模式详情
回答by Dean Hiller
How about just using
只用怎么样
void feedInputToOutput(InputStream in, OutputStream out) {
IOUtils.copy(in, out);
}
and be done with it?
并完成它?
from jakarta apache commons i/o library which is used by a huge amount of projects already so you probably already have the jar in your classpath already.
来自 jakarta apache commons i/o 库,该库已经被大量项目使用,因此您可能已经在类路径中拥有该 jar。
回答by Daniel De León
Asynchronous way to achieve it.
异步方式来实现它。
void inputStreamToOutputStream(final InputStream inputStream, final OutputStream out) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
int d;
while ((d = inputStream.read()) != -1) {
out.write(d);
}
} catch (IOException ex) {
//TODO make a callback on exception.
}
}
});
t.setDaemon(true);
t.start();
}
回答by George Pligoropoulos
In case you are into functional this is a function written in Scala showing how you could copy an input stream to an output stream using only vals (and not vars).
如果您喜欢函数式,这是一个用 Scala 编写的函数,它展示了如何仅使用 vals(而不是 vars)将输入流复制到输出流。
def copyInputToOutputFunctional(inputStream: InputStream, outputStream: OutputStream,bufferSize: Int) {
val buffer = new Array[Byte](bufferSize);
def recurse() {
val len = inputStream.read(buffer);
if (len > 0) {
outputStream.write(buffer.take(len));
recurse();
}
}
recurse();
}
Note that this is not recommended to use in a java application with little memory available because with a recursive function you could easily get a stack overflow exception error
请注意,不建议在可用内存很少的 Java 应用程序中使用此方法,因为使用递归函数很容易出现堆栈溢出异常错误
回答by JesusFreke
For completeness, guavaalso has a handy utilityfor this
ByteStreams.copy(input, output);
回答by Leandro Latorre
BUFFER_SIZE is the size of chucks to read in. Should be > 1kb and < 10MB.
BUFFER_SIZE 是要读入的卡盘大小。应该大于 1kb 且小于 10MB。
private static final int BUFFER_SIZE = 2 * 1024 * 1024;
private void copy(InputStream input, OutputStream output) throws IOException {
try {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = input.read(buffer);
while (bytesRead != -1) {
output.write(buffer, 0, bytesRead);
bytesRead = input.read(buffer);
}
//If needed, close streams.
} finally {
input.close();
output.close();
}
}
回答by pathikrit
This is a Scala version that is clean and fast (no stackoverflow):
这是一个干净且快速的 Scala 版本(没有 stackoverflow):
import scala.annotation.tailrec
import java.io._
implicit class InputStreamOps(in: InputStream) {
def >(out: OutputStream): Unit = pipeTo(out)
def pipeTo(out: OutputStream, bufferSize: Int = 1<<10): Unit = pipeTo(out, Array.ofDim[Byte](bufferSize))
@tailrec final def pipeTo(out: OutputStream, buffer: Array[Byte]): Unit = in.read(buffer) match {
case n if n > 0 =>
out.write(buffer, 0, n)
pipeTo(out, buffer)
case _ =>
in.close()
out.close()
}
}
This enables to use >
symbol e.g. inputstream > outputstream
and also pass in custom buffers/sizes.
这允许使用>
符号 eginputstream > outputstream
并传入自定义缓冲区/大小。
回答by Warren M. Nocos
JDK 9has added InputStream#transferTo(OutputStream out)
for this functionality.
回答by Adam111p
Use org.apache.commons.io.IOUtils
使用 org.apache.commons.io.IOUtils
InputStream inStream = new ...
OutputStream outStream = new ...
IOUtils.copy(inStream, outStream);
or copyLargefor size >2GB
或copyLarge大小 >2GB