簡體   English   中英

如何將OutputStream傳遞給StreamingDataHandler?

[英]How can you pipe an OutputStream to a StreamingDataHandler?

我在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。

有任何想法嗎?

我找到了答案,就像Christian所說的那樣(創建一個執行writeToOut()的新線程):

@MTOM
@WebService
class Example {
    @WebMethod
    public @XmlMimeType("application/octet-stream") DataHandler service() {
        // Create piped output stream, wrap it in a final array so that the
        // OutputStream doesn't need to be finalized before sending to new Thread.
        PipedOutputStream out = new PipedOutputStream();
        InputStream in = new PipedInputStream(out);
        final Object[] args = { out };

        // Create a new thread which writes to out.
        new Thread(
            new Runnable(){
                public void run() {
                    writeToOut(args);
                    ((OutputStream)args[0]).close();
                }
            }
        ).start();

        // Return the InputStream to the client.
        DataSource ds = new ByteArrayDataSource(in, "application/octet-stream");
        DataHandler dh = new DataHandler(ds);
        return dh;
    }
}

由於final變量,它有點復雜,但據我所知,這是正確的。 線程啟動時,它會在第一次嘗試調用out.write()時阻塞。 同時,輸入流返回給客戶端,客戶端通過讀取數據來解鎖寫入。 (我之前實現此解決方案的問題是我沒有正確關閉流,因此遇到錯誤。)

對不起,我只為C#而不是java做過這個,但我認為你的方法應該啟動一個線程來運行“writeToOut(out);” 在parralel。 您需要創建一個特殊的流並將其傳遞給新線程,該線程將該流提供給writeToOut。 啟動線程后,將該stream-object返回給調用者。

如果您只有一個寫入流並且之后返回的方法以及另一個使用流並且之后返回的方法,則沒有其他方法。

然而,棘手的部分是獲得這樣一個多線程安全流:如果內部緩沖區太滿,它將阻塞每一方。

不知道Java管道流是否適用於此。

包裝圖案? :-)。

自定義javax.activation.DataSource實現(只有4種方法)能夠做到這一點嗎?

return new DataHandler(new DataSource() { 
  // implement getOutputStream to return the stream used inside writeToOut() 
  ... 
});   

我沒有可用的IDE來測試這個,所以我只是在做一個建議。 我還需要writeToOut總體布局:-)。

在我的應用程序中,我使用InputStreamDataSource實現,它將InputStream作為構造函數參數而不是FileDataSource中的File。 它到目前為止工作。

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM