Почему я не могу предотвратить изменение исходного файла Apache POI? - PullRequest
0 голосов
/ 28 июня 2019

Я открываю файл Excel (исходный код) в Java с помощью рабочей книги Apache POI, изменяю данные в определенном наборе ячеек, сохраняю рабочую книгу в отдельный файл, затем закрываю рабочую книгу (поскольку в документации говорится о закрытии Рабочая тетрадь, даже если она доступна только для чтения).

POI каждый раз изменяет данные в исходном файле Excel. Я пробовал несколько разных способов предотвратить это в соответствии с рекомендациями из документации POI, но эти методы не сработали

Вот две попытки, которые должны работать теоретически, но не работают.

Попытка 1 - установить исходный файл только для чтения

File file = new File("{path-to-existing-source-file}");

file.setReadOnly();

Workbook workbook = WorkbookFactory.create(file); // throws a FileNotFoundException

A FileNotFoundException для «Доступ запрещен» выбрасывается на WorkbookFactory.create(file):

java.io.FileNotFoundException: {path-to-source-file-that-exists} (Access is denied)
at java.io.RandomAccessFile.open0(Native Method)
at java.io.RandomAccessFile.open(RandomAccessFile.java:316)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:243)
at org.apache.poi.poifs.nio.FileBackedDataSource.newSrcFile(FileBackedDataSource.java:158)
at org.apache.poi.poifs.nio.FileBackedDataSource.<init>(FileBackedDataSource.java:60)
at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:224)
at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:172)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:298)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:271)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:252)
at com.stackoverflow.MyClass(MyClass.java:71)

Исходный файл существует, и он действительно только для чтения.

Попытка 2 - использовать конструктор API POI, который позволяет явно установить только для чтения

File file = new File("{path-to-existing-source-file}");
Workbook workbook = WorkbookFactory.create(file, null, true);  // true is read-only

// dataBean is just a container bean with the appropriate reference values
Sheet sheet = workbook.getSheet(dataBean.getSheetName());
Row row = sheet.getRow(dataBean.getRowNumber());
Cell cell = row.getCell(dataBean.getColumnNumber());
cell.setCellValue(dataBean.getValue());

// target is another File reference
OutputStream outStream = new FileOutputStream(new File("path-to-target-file"));
workbook.write(outStream);   // throws InvalidOperationException

InvalidOperationException выбрасывается во время вызова записи:

Caused by: org.apache.poi.openxml4j.exceptions.InvalidOperationException: 
Operation not allowed, document open in read only mode!
at org.apache.poi.openxml4j.opc.OPCPackage.throwExceptionIfReadOnly(OPCPackage.java:551)
at org.apache.poi.openxml4j.opc.OPCPackage.removePart(OPCPackage.java:955)
at org.apache.poi.openxml4j.opc.PackagePart.getOutputStream(PackagePart.java:531)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.commit(XSSFWorkbook.java:1770)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:463)
at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:236)
at com.stackoverflow.MyClass(MyClass.java:90)

«Операция не разрешена, документ открыт в режиме только для чтения!». Конечно, он установлен только для чтения; Я не хочу, чтобы источник записывался, я просто хочу, чтобы все данные перешли к новой цели.

Что можно установить или изменить, чтобы не изменять источник при использовании POI?

Нашим текущим решением является создание дубликата исходного файла, но это не очень хорошее решение.

1 Ответ

1 голос
/ 28 июня 2019

Вам нужно иметь две рабочие тетради: одну, в которой вы получаете данные (для чтения), и другую, в которую вы пишете.

Послушайте, парень, это то, что я делал несколько месяцев назад, пожалуйста, обратите внимание, что я использую .write () во второй книге (hssfWorkbookNew), а не ту, которую я использую для чтения данных, прочитайте их внимательно. Этот код предназначен только для получения первого листа XLS Excel и копирования его в новый файл.

// this method generates a new excelFile based on the excelFile he receives

public void generarXLS(File excelFile, File excelNewFile) {
        InputStream excelStream = null;
        OutputStream excelNewOutputStream = null;
        try {
            excelStream = new FileInputStream(excelFile);
            excelNewOutputStream = new FileOutputStream(excelNewFile);
            // Representation of highest level of excel sheet.
            HSSFWorkbook hssfWorkbook = new HSSFWorkbook(excelStream);
            HSSFWorkbook hssfWorkbookNew = new HSSFWorkbook();

            // Chose the sheet that we pass as parameter.
            HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(0);

            // Create new sheet we are gonna use.
            HSSFSheet hssfSheetNew = hssfWorkbookNew.createSheet("Copy-Copia");

            // Create new sheet where we will copy the data

            // Object that allow us to read a row from the sheet and extract the data from the cells
            HSSFRow hssfRow;
            HSSFRow hssfRowNew; // for hssfSheetNew
            // Initialize the object that reads value of cell
            HSSFCell cellNew;
            // Get number of rows of the sheet
            int rows = hssfSheet.getLastRowNum();
            String cellValue;

            // Style of the cell border, color background and pattern (fill pattern) used.
            CellStyle style = hssfWorkbookNew.createCellStyle();
            // Definition of the font of the cell.

            // Iterate trhough all rows to get the cells and copy them to the new sheet
            for (Row row : hssfSheet) {
                hssfRowNew = hssfSheetNew.createRow(row.getRowNum());

                if (row.getRowNum() > 999999) {
                    break;
                }

                for (Cell cell : row) {

                    cellValue = (cell.getCellType() == CellType.STRING) ? cell.getStringCellValue()
                            : (cell.getCellType() == CellType.NUMERIC) ? "" + cell.getNumericCellValue()
                                    : (cell.getCellType() == CellType.BOOLEAN) ? "" + cell.getBooleanCellValue()
                                            : (cell.getCellType() == CellType.BLANK) ? ""
                                                    : (cell.getCellType() == CellType.FORMULA) ? "FORMULA"
                                                            : (cell.getCellType() == CellType.ERROR) ? "ERROR" : "";

                    cellNew = hssfRowNew.createCell(cell.getColumnIndex(), CellType.STRING);
                    cellNew.setCellValue(cellValue);

                }
            }
            // NOTICE how I write to the new workbook
            hssfWorkbookNew.write(excelNewOutputStream);
            hssfWorkbook.close();
            hssfWorkbookNew.close();
            excelNewOutputStream.close();

            JOptionPane.showMessageDialog(null, Constantes.MSG_EXITO, "Informacion", 1);

        } catch (FileNotFoundException fileNotFoundException) {
            JOptionPane.showMessageDialog(null, "file not found", "Error", 0);

        } catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Error processing the file", "Error", 0);

        } finally {
            try {
                excelStream.close();
            } catch (IOException ex) {
                System.out.println("Error processing the file after closing it): " + ex);
            }
        }
    }
...