2010-05-13 323 views
19

我正在研究一個java web應用程序,其中的文件將存儲在數據庫中。本來我們在數據庫中已恢復的文件通過簡單地調用getBytes我們的結果集:使用明顯的構造如何將InputStream轉換爲DataHandler?

byte[] bytes = resultSet.getBytes(1); 
... 

這個字節數組,然後轉換成DataHandler

dataHandler=new DataHandler(bytes,"application/octet-stream"); 

,直到我們工作很大開始嘗試存儲和檢索較大的文件。將整個文件內容轉儲到一個字節數組中,然後構建一個DataHandler,這隻需要太多的內存。

我的直接想法是用getBinaryStream檢索數據庫中的數據流,並以某種方式將InputStream轉換爲DataHandler以有效的內存方式。不幸的是,似乎沒有直接的方法將InputStream轉換爲DataHandler。我一直在玩的另一個想法是從InputStream讀取大塊數據,並將它們寫入DataHandlerOutputStream。但是...我找不到創建「空」DataHandler的方法,當我撥打getOutputStream時返回非空OutputStream ...

有沒有人做過這個?我會很感激任何幫助,你可以給我或帶領正確的方向。

回答

14

我的方法是編寫一個實現DataSource的自定義類,它包裝您的InputStream。然後創建DataHandler,爲其創建DataSource

+0

啊,那是一個偉大的想法。當我有機會的時候我會嘗試。 – pcorey 2010-05-13 21:58:48

+0

我以爲是一樣的。但要小心,那麼必須使用DataHandler(使用它的輸入),「在循環中」,而ResultSet處於打開狀態。例如,你不可能將DataHandler對象傳遞給上層。 – leonbloy 2010-05-13 22:02:02

+0

@leonbloy聲明的目標是處理數據而不從結果集中複製數據。這意味着無論你如何做,結果集必須全部打開。 – 2010-05-13 23:04:02

16

我也遇到過這個問題。如果您的源數據是byte[] Axis已經有一個包裝InputStream並創建DataHandler對象的類。下面是代碼

//this constructor takes byte[] as input 
ByteArrayDataSource rawData= new ByteArrayDataSource(resultSet.getBytes(1)); 
DataHandler data= new DataHandler(rawData); 
yourObject.setData(data); 

相關進口

import javax.activation.DataHandler; 
import org.apache.axiom.attachments.ByteArrayDataSource; 

希望它能幫助!

+3

由於它將所有數據加載到內存,因此在管理大量數據時會造成問題。 – 2013-12-02 14:41:12

3

請注意,DataSource的getInputStream必須每次調用時返回一個新的InputStream。這意味着,你需要在第一個地方複製。 欲瞭解更多信息,請參閱 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294

+0

我知道它已經老了......那個bug是真的嗎? – Cris 2013-01-25 16:57:39

+2

API說。但是,它說返回一個新的流或拋出一個異常。從技術上講,這意味着首次返回一個流,然後拋出異常。我假設大多數框架只檢索一次流。 – Steve11235 2013-04-03 17:47:22

14

從「凱西凡石」答案的實現:

起初創造的輔助類,它的InputStream創建數據源:

public class InputStreamDataSource implements DataSource { 
    private InputStream inputStream; 

    public InputStreamDataSource(InputStream inputStream) { 
     this.inputStream = inputStream; 
    } 

    @Override 
    public InputStream getInputStream() throws IOException { 
     return inputStream; 
    } 

    @Override 
    public OutputStream getOutputStream() throws IOException { 
     throw new UnsupportedOperationException("Not implemented"); 
    } 

    @Override 
    public String getContentType() { 
     return "*/*"; 
    } 

    @Override 
    public String getName() { 
     return "InputStreamDataSource"; 
    } 
} 

然後您就可以從InputStream中創建的DataHandler:

DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream)) 

進口

import javax.activation.DataSource; 
import java.io.OutputStream; 
import java.io.InputStream; 
+0

'getInputStream'應該在每次調用時返回一個新的'InputStream' – husayt 2015-10-15 21:53:08

+0

您能解釋一下這個原因嗎? – Gordak 2017-05-24 11:50:07

0

(bugs_)代碼不適用於我。我使用DataSource創建電子郵件附件(來自具有inputStream名稱的對象),並且附件內容丟失。 Stefan看起來是正確的,並且每次都必須返回新的inputStream。至少在我的具體情況。接下來執行涉及問題:

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

} 
0

我已經滿足的情況下,當InputStreamDataSource請求兩次:使用日誌Handler與MTOM功能一起。 隨着this proxy stream solution我執行正常工作:

import org.apache.commons.io.input.CloseShieldInputStream; 
import javax.activation.DataHandler; 
import javax.activation.DataSource; 
... 

private static class InputStreamDataSource implements DataSource { 
    private InputStream inputStream; 

    @Override 
    public InputStream getInputStream() throws IOException { 
     return new CloseShieldInputStream(inputStream); 
    } 

    @Override 
    public OutputStream getOutputStream() throws IOException { 
     throw new UnsupportedOperationException("Not implemented"); 
    } 

    @Override 
    public String getContentType() { 
     return "application/octet-stream"; 
    } 

    @Override 
    public String getName() { 
     return ""; 
    } 
} 
0

下面是用於與彈簧引導org.springframework.core.io.Resource對象,它是我認爲如何,我們很多人都到這兒專門工作答案。請注意,您可能需要在下面的代碼中修改內容類型,因爲我將png文件插入到html格式的電子郵件中。

注意:正如其他人所說的,僅僅連接一個InputStream是不夠的,因爲它被多次使用,只需映射到Resource.getInputStream()就可以實現。類的

public class SpringResourceDataSource implements DataSource { 
    private Resource resource; 

    public SpringResourceDataSource(Resource resource) { 
     this.resource = resource; 
    } 

    @Override 
    public InputStream getInputStream() throws IOException { 
     return resource.getInputStream(); 
    } 

    @Override 
    public OutputStream getOutputStream() throws IOException { 
     throw new UnsupportedOperationException("Not implemented"); 
    } 

    @Override 
    public String getContentType() { 
     return "image/png"; 
    } 

    @Override 
    public String getName() { 
     return "SpringResourceDataSource"; 
    } 
} 

用法是這樣的:

PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(); 
    Resource logoImage = pathMatchingResourcePatternResolver.getResource("/static/images/logo.png"); 
    MimeBodyPart logoBodyPart = new MimeBodyPart(); 
    DataSource logoFileDataSource = new SpringResourceDataSource(logoImage); 


    logoBodyPart.setDataHandler(new DataHandler(logoFileDataSource));