Я пишу класс StringOutputStream
на Java, потому что мне нужны данные в кодировке до Base64 из OutputStream
, чтобы перейти к строке.Мне нужно это как String, потому что я собираюсь поместить его в W3C XML Document
.
Все бы хорошо, но я имею дело с (относительно) большими объектами.Полученный объект оказывается около 25 МБ (до представления String).Я запускаю это как апплет, поэтому у меня есть 66 МБ пространства кучи, которое быстро истощается.
Я уже пробовал несколько методов:
- Добавить полученный байтк объекту String (используя
strObj.concat((byte) b)
и strObj += new String((byte) b)
) с буферизацией и без нее - Добавьте полученный байт к
StringBuffer
- Добавьте байт в байтовый массив, затем, когдаТребуется строка, преобразуйте этот байтовый массив в строку
Номер один работает примерно до 11 МБ, когда старая строка и новая строка занимают слишком много места при объединении.
Номер два был полным провалом, он получает только около 7 МБ.
Номер три был (возможно?) Лучшим, он хранит весь поток, но при попытке получить его String, что неудивительно,не удается.
Как бы я сделал эту работу?Возможно ли это?
Я думаю, у меня есть свободное место для хранения результирующей строки, но проблема заключается в копировании (поскольку для традиционной копии вам нужны источник и место назначения).Я знаю, что строки неизменяемы, но есть ли способ добавить некоторые символы в конец?
Вот три моих примера:
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 ().Кроме того, байтовый массив (в настоящее время) статически размещен, но это изменится, если я пойду по этому маршруту (и не будет использоваться во время других методов).
Edit 1: Дополнительная информацияо моей общей проблеме:
Это часть более крупного приложения, которое принимает данные, подписывает их и загружает на сервер.Я должен прочитать файл, взять его хэш SHA-1, зашифровать его, а затем создать документ XML (с некоторыми другими вещами, такими как время).Затем этот документ XML должен быть подписан (через XML DSig, он же javax.xml.crypto.dsig.XMLSignatureFactory
) и загружен обратно на сервер.
Файлы для подписи имеют размер от 1 КБ до примерно 50 МБ.
Есть несколько проблем:
- Текущая реализация Java DSig на Java не анализирует и XML-потоки, только узлы w3c.(Я также не могу найти других реализаций, которые это делают)
- Мой начальник хочет, чтобы это не требовало минимальной установки на стороне клиента, поэтому был выбран апплет (это подписанный апплет, поэтому он может получить доступ ко всему наклиент).