У меня есть следующий метод:
public String exportAsCsv(CqlQuery query) {
Iterator<String> result = queryService.execute(.....);
StringBuilder buf = new StringBuilder();
for (String nextLine : result) {
buf.append(nextLine);
}
return buf.toString();
}
Он выполняет некоторый запрос, который возвращает Iterator<String>
- он содержит гигабайты данных, поэтому добавление его в StringBuilder
- не лучшая идея...
Я хотел бы изменить свой метод так, чтобы он возвращал InputStream
.
Это может быть одна возможная реализация (псевдокод):
public InputStream exportAsCsv(CqlQuery query) {
final Iterator<String> result = queryService.execute(query,false);
return new MagicalInputStream(){
@Overwrite
byte[] readNext() {
if(!result.hasNext()) {
return null;
} else {
return result.next().getBytes();
}
}
}
}
Я ищу InputStream
где мне нужно реализовать абстрактный метод (например, byte[] readNext()
), который будет использоваться для чтения блоков данных - один за другим. Таким образом, этот входной поток должен буферизовать фрагмент чтения, передать его обратно, а когда его буфер пуст, он должен прочитать следующий фрагмент. Идея состоит в том, что я читаю следующие элементы из Итератора ТОЛЬКО, когда "клиент" рад следующим байтам от входного потока.
Или может быть другая возможность изменить мой метод, чтобы он возвращал InputStream
вместо String
- любые идеи?
Вся реализация InputStream
можно было бы избежать, если вы позволите вашему методу принять java.io.Writer
. Вместо добавления строк в StringBuilder
вы добавляете их в предоставленный Writer.
public void exportAsCsv(CqlQuery query, Writer writer) {
Iterator<String> result = queryService.execute(.....);
for (String nextLine : result) {
writer.append(nextLine);
}
}
Если вы действительно хотите InputStream, вы можете попробовать что-то вроде этого:
public InputStream exportAsCsv(CqlQuery query) {
Iterator<String> result = queryService.execute(.....);
return new SequenceInputStream(asStreamEnum(result));
}
private Enumeration<InputStream> asStreamEnum(final Iterator<String> it) {
return new Enumeration<InputStream>() {
@Override
public boolean hasMoreElements() {
return it.hasNext();
}
@Override
public InputStream nextElement() {
try {
return new ByteArrayInputStream(it.next().getBytes("UTF-8"));
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
}
};
}
Я еще не проверял этот подход, поэтому будьте предупреждены; концептуально, однако, я думаю, что это то, что вам нужно.