java 按块发送文件

7ivaypg9  于 2023-06-20  发布在  Java
关注(0)|答案(2)|浏览(108)

以块的形式发送Excel文件时遇到问题。我有这样一段代码,它应该做这件事,它的工作很好,到一定程度。但是,问题是它只写入前100条记录。在此之后,文件大小保持不变,就像它有所有10,000条记录一样,但当打开时,它只有100条记录。

@Override
public void generateAndSendExcelChunks(ServletOutputStream outputStream) throws IOException {
    Workbook workbook = new SXSSFWorkbook();

    Sheet sheet = workbook.createSheet("Datos");
    int totalRows = 10000;
    int rowsPerChunk = 100;
    int currentRow = 0;

    while (currentRow < totalRows) {
        int endRow = currentRow + rowsPerChunk;
        endRow = Math.min(endRow, totalRows);
        generateChunkData(sheet, currentRow, endRow);
        workbook.write(outputStream);
        outputStream.flush();
        sheet = workbook.createSheet("Datos");
        currentRow = endRow;
    }

    workbook.close();
}

private void generateChunkData(Sheet sheet, int startRow, int endRow) {
    for (int i = startRow; i < endRow; i++) {
        Row row = sheet.createRow(i);
        Cell cell = row.createCell(0);
        cell.setCellValue("Valor " + (i + 1));
    }
}

sheet = workbook.createSheet("Datos");行不起作用,因为它试图创建一个名称已经存在的工作表。如果我试图获取对该工作表的引用,它会在这一行给出一个"stream closed"错误:workbook.write(outputStream);。预期功能是将所有信息存储在同一工作表中,而不覆盖任何内容。

mnemlml8

mnemlml81#

你可以使用另一种方法。您可以将Excel文件拆分为二进制块并发送它们。然后接收端可以根据每个块的名称将它们放在一起
发送者:

public class ExcelSplitter {
    public static void main(String[] args) {
        String inputFilePath = "input.xlsx";
        String outputFolderPath = "output";
        int blockSize = 1024; // Size of each binary block in bytes

        try {
            // Load the Excel file
            FileInputStream fileInputStream = new FileInputStream(inputFilePath);
            Workbook workbook = WorkbookFactory.create(fileInputStream);
            
            // Iterate over each sheet in the workbook
            for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
                Sheet sheet = workbook.getSheetAt(sheetIndex);
                String sheetName = sheet.getSheetName();

                // Convert the sheet to binary blocks
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
                for (Row row : sheet) {
                    for (Cell cell : row) {
                        // Write cell data as bytes to the output stream
                        dataOutputStream.write(cell.toString().getBytes());
                    }
                }
                dataOutputStream.close();

                // Split the binary data into blocks
                byte[] binaryData = byteArrayOutputStream.toByteArray();
                int numBlocks = (int) Math.ceil((double) binaryData.length / blockSize);
                for (int blockIndex = 0; blockIndex < numBlocks; blockIndex++) {
                    int startIndex = blockIndex * blockSize;
                    int endIndex = Math.min((blockIndex + 1) * blockSize, binaryData.length);
                    byte[] blockData = new byte[endIndex - startIndex];
                    System.arraycopy(binaryData, startIndex, blockData, 0, blockData.length);

                    // Save each binary block as a separate file
                    String outputFilePath = outputFolderPath + "/" + sheetName + "_block" + blockIndex + ".bin";
                    FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);
                    fileOutputStream.write(blockData);
                    fileOutputStream.close();
                }
            }

            // Close the workbook and input stream
            workbook.close();
            fileInputStream.close();

            System.out.println("Excel file split into binary blocks successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

接收方:

public class ExcelReconstructor {
    public static void main(String[] args) {
        String inputFolderPath = "input_chunks";
        String outputFilePath = "output.xlsx";
        int blockSize = 1024; // Size of each binary block in bytes

        try {
            // List all binary chunk files in the input folder
            File folder = new File(inputFolderPath);
            File[] chunkFiles = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".bin"));
            
            // Sort the chunk files based on the block index
            List<File> sortedChunkFiles = new ArrayList<>();
            for (int i = 0; i < chunkFiles.length; i++) {
                sortedChunkFiles.add(null);
            }
            for (File chunkFile : chunkFiles) {
                String fileName = chunkFile.getName();
                int blockIndex = Integer.parseInt(fileName.substring(fileName.lastIndexOf("_block") + 6, fileName.lastIndexOf(".")));
                sortedChunkFiles.set(blockIndex, chunkFile);
            }

            // Create the output file
            FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);

            // Concatenate the binary data from each chunk file
            for (File chunkFile : sortedChunkFiles) {
                FileInputStream fileInputStream = new FileInputStream(chunkFile);
                byte[] blockData = new byte[blockSize];
                int bytesRead = fileInputStream.read(blockData);
                while (bytesRead != -1) {
                    // Write the block data to the output file
                    fileOutputStream.write(blockData, 0, bytesRead);
                    bytesRead = fileInputStream.read(blockData);
                }
                fileInputStream.close();
            }

            // Close the output file stream
            fileOutputStream.close();

            System.out.println("Binary chunks reconstructed into Excel file successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
mnowg1ta

mnowg1ta2#

你想做的事是不可能的。至少到目前为止还没有使用Apache POI
Office Open XML文件(如*.xlsx文件)也是包含特殊内部文件结构中的数据的ZIP存档。ZIP压缩文件包含*.xml文件和其他文件也在一个特殊的目录结构。不同的部分彼此相关。关系存储在*.rel文件中,该文件存储特殊的关系XML。例如,如果简单地解压缩*.xlsx文件,就可以看到这一点。7-Zip默认可以这样做,使用其他ZIP-Software需要重命名文件*.zip
在知道这一点并看到这个结构之后,考虑如何考虑所有的关系来填充这个块。总结:非常困难,几乎不可能。
打开任何类型的Workbook对象都会打开该ZIP存档并将内部存储的文件读入内存。Workbook.write将完整的内部ZIP内容写入文件。因此,在Workbook.write之后,工作簿对象在再次打开之前不会变得更有用。因此,在循环中使用它,如:将第一内容放入,写入,将第二内容放入,写入,…不可能一定是这样的:打开工作簿,放入第一个内容,写入,关闭工作簿,打开工作簿,放入第二个内容,写入,关闭工作簿,...但这与您的需求相矛盾,因为打开工作簿总是将所有内容读入内存。
但是为什么不像程序员所想的那样简单地使用SXSSFWorkbook呢?参见SXSSF(流用户模型API)。使用默认属性,这正是您要做的。它只在内存中保留100行图纸数据。其他图纸数据将写入临时图纸XML文件中。只有其他数据和关系永久保留在内存中。完成后,SXSSFWorkbook.write使用临时存储的工作表数据合成ZIP存档。
当然SXSSFWorkbook.write也需要写整个*.xlsx-ZIP-archive。因此,如果您的问题是将一个大文件发送到客户端,那么使用SXSSFWorkbook.write在服务器端存储*.xlsx文件。然后把它想象成一个大的二进制文件,交付(提供下载)给客户端。应该有默认的方法来解决这种任务,因为这是一个默认的任务。自我编程划分成块是没有必要的,是一个坏主意,在我看来。

相关问题