Я еще не нашел способа сделать следующее:
Надеюсь сделать все это по частям (что-то прочитать, что-то сгенерировать, что-то написать, что-то повторить). Но я не выяснил, смогу ли я избежать проблем с памятью и избежать записи на диск. Что-то вроде этого может сработать? :
Но (2) кажется проблемой:
Потоковая передача Apache POI сохраняет в памяти ограниченное количество строк, и это здорово, но конечный результат все равно сбрасывает книгу в файл.
Кто-нибудь делал что-то подобное раньше? (И возможно ли это вообще, учитывая, что Excel представляет собой двоичный формат и представляет собой набор сжатых XML-файлов?)
Нет, CSV, к сожалению, здесь не вариант.
двоичный формат? Глядя на API, я вижу, что SXSSFWorkbook управляет XSSFWorkbook, поэтому я ожидаю, что результирующий файл xlsx будет сжатым zip-файлом, содержащим текст XML.
Да, ты прав. Я еще покопался и обнаружил, что это заархивированные XML-файлы. Это может изменить ситуацию, если сжатие будет... транзитивным? Необходимо проверить, может ли сжатие нескольких файлов по отдельности дать тот же результат, что и сжатие коллекции файлов. Или, я думаю, мне придется заархивировать фрагменты XML, поскольку полная таблица может стать слишком большой. Время для дополнительных исследований.
DeferredSXSSFWorkbookможет и актуально, но я не пробовала.
Круто, я такого не видел. Спасибо! Посмотрю.




Эффективная потоковая передача больших документов по мере их создания является распространенной проблемой . SXSSFWorkbook предоставляет хорошую основу, используя модель скользящего окна. На практике поиск оптимального подхода потребует профилирования в конкретном контексте.
Для справки ниже я обновил приведенный пример , чтобы можно было регулировать размер окна. Вариант этого примера , используемый в командной строке, можно использовать для оценки вывода. Кажется, что результат работает без проблем на любом сетевом томе, но результат может зависеть от деталей предложения этого поставщика. Экспериментальная книга DeferredSXSSFWorkbook может оказаться актуальной в будущем; @PJ Fanning подробно рассказывает здесь.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.junit.Assert;
/**
* @see https://stackoverflow.com/q/78456843/230513
*/
public class StreamTest {
private static final int N = 1000;
private static final int W = 10;
public static void main(String[] args) throws IOException {
// keep W rows in memory, N - W rows will be flushed to disk
var wb = new SXSSFWorkbook(W);
var sh = wb.createSheet();
for (int rownum = 0; rownum < N; rownum++) {
Row row = sh.createRow(rownum);
for (int cellnum = 0; cellnum < 10; cellnum++) {
Cell cell = row.createCell(cellnum);
String address = new CellReference(cell).formatAsString();
cell.setCellValue(address);
}
}
// Verify that W rows before N - W are flushed and inaccessible
for (int rownum = N - (2 * W); rownum < N - W; rownum++) {
Assert.assertNull(sh.getRow(rownum));
}
// The last W rows are still in memory
for (int rownum = N - W; rownum < N; rownum++) {
Assert.assertNotNull(sh.getRow(rownum));
}
var file = new File("sxssf.xlsx");
try (FileOutputStream out = new FileOutputStream(file)) {
wb.write(out);
} finally {
// dispose of temporary files backing this workbook on disk
wb.dispose();
}
}
}
Я написал небольшой POC на основе примера DeferredSXSSF и подтвердил, что он не будет записывать временные файлы с помощью writeAvoidingTempFiles(). Но я пока не вижу способа заставить DeferedSDSSF работать с многочастной загрузкой S3. Все происходит автоматически: генерация строк, их сброс на вывод по мере необходимости в зависимости от окна в памяти. Мне нужно было каким-то образом определить, когда минимальная сумма загрузки была записана в выходной поток (или соответствующий PipedInputStream), чтобы вручную загрузитьPart() в S3, верно?
Извините, я не вижу API-перехватчика для промежуточных результатов. Я вижу апелляцию, но вам, возможно, придется завершить потоковую передачу, прежде чем начинать многочастную загрузку.
В конечном итоге это сработало для меня очень хорошо. Я написал в PipedOutputStream, сгенерировал лист в основном потоке и попросил другой поток прочитать из соответствующего PipedInputStream, накопить буфер до тех пор, пока он не станет достаточно большим для каждого вызова многочастной загрузки.
можете ли вы использовать CSV?