Java 如何将OutputStream通过管道传输到StreamingDataHandler?
我在JAX-WS中有一个Java web服务,它从另一个方法返回一个OutputStream。我似乎不知道如何将OutputStream流式传输到返回的DataHandler中,除了创建一个临时文件,对其进行写入,然后将其作为InputStream重新打开。下面是一个例子:Java 如何将OutputStream通过管道传输到StreamingDataHandler?,java,stream,jax-ws,Java,Stream,Jax Ws,我在JAX-WS中有一个Java web服务,它从另一个方法返回一个OutputStream。我似乎不知道如何将OutputStream流式传输到返回的DataHandler中,除了创建一个临时文件,对其进行写入,然后将其作为InputStream重新打开。下面是一个例子: @MTOM @WebService class Example { @WebMethod public @XmlMimeType("application/octet-stream") DataHandler
@MTOM
@WebService
class Example {
@WebMethod
public @XmlMimeType("application/octet-stream") DataHandler service() {
// Create a temporary file to write to
File fTemp = File.createTempFile("my", "tmp");
OutputStream out = new FileOutputStream(fTemp);
// Method takes an output stream and writes to it
writeToOut(out);
out.close();
// Create a data source and data handler based on that temporary file
DataSource ds = new FileDataSource(fTemp);
DataHandler dh = new DataHandler(ds);
return dh;
}
}
主要问题是writeToOut()方法返回的数据可能远远大于计算机的内存。这就是为什么该方法首先使用MTOM来流化数据。我似乎不知道如何直接从OutputStream流式传输数据,我需要将数据流式传输给返回的DataHandler(最终是接收StreamingDataHandler的客户端)
我尝试过使用PipedInputStream和PipedOutputStream,但它们似乎不是我所需要的,因为在将PipedOutputStream写入之后,需要返回DataHandler
有什么想法吗?包装模式?:-)
定制javax.activation.DataSource实现(只有4种方法)能够做到这一点吗
return new DataHandler(new DataSource() {
// implement getOutputStream to return the stream used inside writeToOut()
...
});
我没有可用的IDE来测试这个,所以我只是做一个建议。我还需要写出总体布局:-) 对不起,我只为C#而不是java做了这件事,但我认为您的方法应该启动一个线程来运行parralel中的“writeToOut(out);”。您需要创建一个特殊的流,并将其传递给新线程,该线程将该流写入。启动线程后,将该流对象返回给调用者 如果只有一个方法写入流并随后返回,而另一个方法使用流并随后返回,那么就没有其他方法了 当然,棘手的部分是获得这样一个多线程安全流:如果内部缓冲区太满,它将阻止每一方
不知道Java管道流是否适用于此。我按照Christian所说的思路(创建一个新线程来执行writeOut())找到了答案:
由于
final
变量,它有点复杂,但据我所知,这是正确的。当线程启动时,它会在第一次尝试调用out.write()时阻塞;同时,输入流返回给客户机,客户机通过读取数据来解除写操作。(我以前的解决方案实现的问题是,我没有正确关闭流,因此出现了错误。)在我的应用程序中,我使用InputStreamDataSource实现,它将InputStream作为构造函数参数,而不是FileDataSource中的文件。到目前为止,它是有效的
public class InputStreamDataSource implements DataSource {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final String name;
public InputStreamDataSource(InputStream inputStream, String name) {
this.name = name;
try {
int nRead;
byte[] data = new byte[16384];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getContentType() {
return new MimetypesFileTypeMap().getContentType(name);
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(buffer.toByteArray());
}
@Override
public String getName() {
return name;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("Read-only data");
}
}+1-这个想法是正确的,我感谢你让我走上正确的道路,但我的答案是真正的Java解决方案,我希望未来的人们在遇到同样的问题时能够首先找到。我对此真的不太了解,但请确保管道*流是线程安全的或使用“同步的”我不熟悉的关键字。请注意,InputStream
是在构造时完全读取到内存的。在处理大型文件时,这可能会导致OutOfMemoryError
。可以在中找到工作实现。另请参阅
public class InputStreamDataSource implements DataSource {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private final String name;
public InputStreamDataSource(InputStream inputStream, String name) {
this.name = name;
try {
int nRead;
byte[] data = new byte[16384];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getContentType() {
return new MimetypesFileTypeMap().getContentType(name);
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(buffer.toByteArray());
}
@Override
public String getName() {
return name;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("Read-only data");
}