2010-09-02 46 views
0

我需要在freemarker中加載和處理模板。我正在使用管道流通過freemarker讀回生成的結果。Freemarker中的管道流問題

示例代碼:

PipedInputStream pi = new PipedInputStream(); 
PipedOutputStream po = new PipedOutputStream(pi); 
Writer writer = new OutputStreamWriter(po); 
configuration.getTemplate("xx").process(rootMap, writer); 

的問題是,有時它的freemarker procsss方法內凍結。 沒有錯誤,沒有例外,但它不是從process方法返回。

如果我將管道流轉換成ByteArray流,它工作正常。

我是否正確使用管道流?

+0

爲什麼要讀回生成的結果?你想用它做什麼? – 2010-09-02 07:50:33

+0

@Arne:我想讀取生成的模板並將其寫入另一個流。 (zip流)。 – mhshams 2010-09-02 08:40:05

+0

爲什麼不簡單地在zip流中使用OutputStreamWriter? – 2010-09-02 08:46:00

回答

2

不,管道流設計爲在兩個線程之間傳遞數據。管道兩端之間只有一個小緩衝區。如果寫入管道輸出流,則如果緩衝區已滿,則線程將被阻塞,直到另一個線程將從相應的管道輸入流中讀取。這不會只用一個線程。

從Javadoc中:

典型地,數據被從一個 PipedInputStream對象由一個線程 和數據讀出寫入到對應由 其他線程PipedOutputStream的 。

所以對於小模板,只需使用一個StringWriter,路數您可以通過File.createTempFile()創建一個臨時文件使用FileWriter

+0

感謝您的重播 您是否有任何其他解決方案適用於大型模板?我無法寫入臨時文件(沒有Access) – mhshams 2010-09-02 07:45:44

+0

@穆罕默德:你真的沒有訪問權限嗎?或者你根本不知道要寫入的正確位置?如果你能弄清楚哪裏(提示:查看'java.io.tmpdir'屬性),通常會有一個你有權限的臨時目錄。 – 2010-09-02 08:10:46

+0

@Donal:運行在服務器上的應用程序(OSGI),我不確定我可以在客戶環境中寫入文件。 – mhshams 2010-09-02 08:38:18

0

正如Arne寫道,管道流中的緩衝區空間量相當小。如果你不能使用一個可以容納所有數據的緩衝區(無論是在內存中還是在磁盤上),那麼你可以嘗試的一件事是看看你是否可以在另一個線程中使用管道流將模板處理髮送回去到你正在做這件事的主線程。

PipedInputStream pi = new PipedInputStream(); 
final Writer writer = new OutputStreamWriter(new PipedOutputStream(pi)); 
Thread worker = new Thread(new Runnable() { 
    public void run() { 
     configuration.getTemplate("xx").process(rootMap, writer); 
    } 
}); 
worker.start(); 

您可能需要final關鍵字添加到其他變量,以使您的真實代碼這項工作。這取決於變量configuration,參數getTemplaterootMap變量是局部變量還是實例(或類)變量。

(指定當然線程的行爲時,我可以子類Thread,但我更喜歡實例化的界面 - Runnable在這種情況下 - 這樣的事情)

0

這是我如何做它的工作。

final String uploadReportAsCsv = FreeMarkerTemplateUtils.processTemplateIntoString(
         fileUploadReportTemplate, modelMap); 

message.addAttachment("fileUploadProcessedReport.csv", 
    new InputStreamSource() { 
     //InputStreamResource from Spring is always returning an open stream, 
     // thus we need to create this anonymous class. 
     @Override 
     public InputStream getInputStream() throws IOException { 
      return new StringInputStream(uploadReportAsCsv); 
     } 
    } 
);