Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何将OutputStream通过管道传输到StreamingDataHandler?_Java_Stream_Jax Ws - Fatal编程技术网

Java 如何将OutputStream通过管道传输到StreamingDataHandler?

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

我在JAX-WS中有一个Java web服务,它从另一个方法返回一个OutputStream。我似乎不知道如何将OutputStream流式传输到返回的DataHandler中,除了创建一个临时文件,对其进行写入,然后将其作为InputStream重新打开。下面是一个例子:

@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");
}