我在Java中編寫了StringOutputStream
類,因爲我需要來自OutputStream
的pre-Base64編碼數據轉到字符串。我需要這個字符串作爲字符串,因爲我將把它放入W3C XML Document
。將大型流複製到字符串 - Java
一切都會好的,但我正在處理(相對)較大的對象。生成的對象結果約爲25 MB(在String表示之前)。我將它作爲Applet運行,因此我有66 MB的堆空間,它很快就會耗盡。
我已經嘗試了一些方法至今:
- 追加接收的字節到一個String對象(使用
strObj.concat((byte) b)
和strObj += new String((byte) b)
)有和無緩衝 - 接收的字節添加到
StringBuffer
- 將字節添加到字節數組中,然後當需要字符串時,將該字節數組轉換爲字符串
第一個工作,直到abo ut 11 MB,當舊字符串和新字符串在連接時佔用太多空間時。
第二個是完全失敗,它只能達到7 MB左右。
第三是(也許?)最好的,它存儲整個流,但是當試圖獲取字符串時,它不會令人驚訝地失敗。
我該如何做這項工作?可能嗎?
我想我有可用的空間來容納結果字符串,但它是複製是問題(因爲您需要傳統副本的源和目標)。我知道字符串是不可變的,但是有什麼方法可以將一些字符追加到最後?
這裏是我的三個例子:
package com.myorg.SigningServer.Util.Security;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import com.technicolor.SigningServer.Applet.SigningApplet;
public class StringOutputStream extends OutputStream {
byte[] array = new byte[1024*1024*22];
StringBuffer sb = new StringBuffer();
String output = "";
int prevByte = -1;
long numBytes = 0;
int bufferPos = 0;
int bufferSize = 512*1024;
byte[] buffer = new byte[bufferSize];
public void write2(int b) throws IOException {
sb.append((byte) b);
}
public void write3(int b) throws IOException {
array[(int) numBytes] = (byte) b;
numBytes++;
}
public void write1(int b) throws IOException {
numBytes++;
bufferPos++;
buffer[bufferPos] = (byte) b;
if(bufferPos == bufferSize-1)
{
bufferPos = 0;
System.gc();
System.out.println("Generating string "+numBytes+"; String length "+output.length());
output = output.concat(new String(buffer));
System.gc();
}
}
public void flush1() {
output = output.concat(new String(Arrays.copyOf(buffer, bufferPos)));
bufferPos = 0;
System.gc();
}
public String toString2()
{
return sb.toString();
}
public String toString3()
{
return new String(array);
}
public String toString1()
{
return output;
}
}
有關代碼的幾個注意事項:很明顯,你命名你想用寫()和toString()方法。此外,字節數組(當前)是靜態分配的,但是如果我轉到該路由(並且在其他方法中未使用),則該數組將被更改。
編輯1:我的整體問題 的更多信息:
這是一個較大的應用程序需要的數據,它的標誌,並上傳到服務器的一部分。我必須在文件中讀入數據,然後對其進行SHA-1哈希處理,對其進行加密,然後構造一個XML文檔(以及其他一些內容,例如時間)。然後,必須對XML文檔進行簽名(通過XML DSig,又名javax.xml.crypto.dsig.XMLSignatureFactory
)並上載回服務器。
要簽名的文件從1KB到大約50MB。
有幾個問題:
- XML DSig的目前的Java實現不解析和XML流,只是W3C節點。(我也找不到任何其他的實現)
- 我的老闆希望這不需要最小的客戶端安裝,所以這就是爲什麼選擇一個Applet(它是一個簽名的applet,所以它可以訪問客戶端上的任何東西) 。
你能解釋爲什麼'java.io.ByteArrayOutputStream'或'java.io.StringWriter'不適合你嗎? – Pointy 2010-06-09 16:30:30
ByteArrayOutputStream與方法3完全相同,它會複製所有內容,然後在調用toString時耗盡內存。 StringWriter內存耗用大約10 MB,與方法2大致相同。 – HalfBrian 2010-06-09 16:38:44
您是否可以將更多關於您正在嘗試解決的問題的問題添加到您的問題中?這可能會幫助所有人從盒子外面思考,並從另一個角度解決問題。例如。你專注於22MB的數據 - 正在簽名的數據是否已修復?這是一個硬性上限大小? – mdma 2010-06-09 17:03:20