在没有 Apache POI 的情况下解析 Excel 文件

问题描述 投票:0回答:5

我知道我们可以使用 Apache POI 来解析 Excel 文件并获取数据。但我听说了一件奇怪的事情,Excel 文件可以以与我们解析 CSV 类似的方式传递(就像从文件流中读取文件并用“逗号”分隔符分隔每个列值)。当我们解析Excel时,我们必须使用制表符作为分隔符。是否可以?如果是的话,那么为什么 Apache 会提出如此复杂的框架呢?我很困惑。有人可以帮助我吗?

java apache-poi
5个回答
5
投票

CSV 是一种文本格式,因此可以使用分隔符进行解析。旧版 Excel 是一种二进制且专有的格式,因此需要巧妙的解码。新的 Excel 格式是压缩的 XML,但在将其转换为像逐个读取单元格这样简单的内容之前,人们还应该了解该文档的结构。所以你的问题的答案是否定的,你需要使用 Apache POI,而且 - 这没有什么问题。

顺便说一句,在成为一名优秀开发人员的道路上,您需要学会在寻求帮助之前进行一些自己的研究。亲自动手是学习东西的最好方法。


2
投票

您可能对自己所听到的内容感到困惑,或者告诉您的人也感到困惑。

Excel 文件的某些部分可以(在某种程度上)存储为 CSV 文件,因为表格数据结构非常适合 CSV 文件格式。但是,如果您以 CSV 格式保存,那么您只会在每个单元格中获得纯文本 - 您会丢失所有格式信息、任何图表、多个工作表等。

Apache POI 使用原生 XLS excel 格式,因此可以处理 excel 中的所有内容,而不仅仅是某些单元格中的限制性纯文本。 CSV 文件有其用途,但它们绝对不能直接替代普通 Excel 文件。


0
投票

我尝试在不使用 POI 等任何外部 JAR 的情况下读取/写入 excel 文件。我能够将文件写入 xls 格式。这是我的代码

FileWriter fwriter = new FileWriter(file,true);
writer = new BufferedWriter(fwriter);
writer.newLine();
writer.write("a"    + "\t");
writer.write("b"    + "\t");
writer.write("c"    + "\t");
writer.write("d"    + "\t");
writer.write("e"    + "\t");
writer.write("f"    + "\t");

读取文件 这是我的阅读代码

if(file != null) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(file));
                String line;
                while((line = reader.readLine()) != null) {
                    String[] component = line.split("\\t");
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

0
投票
InputStream is = new FileInputStream(new File(filepath));
        StreamingReader reader=null;
        try {
            reader = StreamingReader.builder()
                    .rowCacheSize(100)     
                    .bufferSize(4096)     
                    .sheetIndex(0)        
                    .read(is);
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }finally{
            is.close();
        }
        //pass here to reader and itrate it 
          for (Row row : reader) {
            if (row.getRowNum()!=0){
                for (Cell cell : row) {
              // write ur logic to store ur value 
                }

            }
        }

0
投票

遗憾的是,它不像 .csv 文件那样以逗号分隔。 但是,如果您只想从 .xlsx 文件中获取表格内容,而不需要所有花哨的 ApachePOI 内容。您可以使用我的简单解析器:

如何:

  • 将所有代码复制到某个类中。
  • 调用
    fromXLSX
    ,其中第一个参数是.xlsx文件,第二个参数是excel工作表的名称(保留为空将默认选择第一个工作表)
  • 它返回一个包含表格内容的
    String[#ROWS][#COLUMN]

免责声明: 仅测试字符串和数字值。不确定它是否适用于公式或日期

public static String[][] fromXLSX(File xlsx, String sheet) {
    FileInputStream fis;
    try {
        fis = new FileInputStream(xlsx);
        ZipInputStream zis = new ZipInputStream(fis);
        ZipEntry ze = zis.getNextEntry();
        
        LinkedList<CellData> cellDatas = null;
        String[] sharedStrings = null;
        
        while(ze != null) {
            String fileName = ze.getName();
            
            if ((sheet == null && fileName.contains("worksheets")) || (sheet != null && fileName.endsWith(sheet + ".xml"))) {
                cellDatas = cellDataFromXLSXextractedXML(readZipEntryToString(zis));
            } else if (fileName.endsWith("sharedStrings.xml")) {
                sharedStrings = sharedStringsFromXML(readZipEntryToString(zis));
            }
            
            
            zis.closeEntry();
            ze = zis.getNextEntry();
        }
        
        zis.closeEntry();
        zis.close();
        fis.close();
        
        int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = 0, maxY = 0;
        
        for(CellData c : cellDatas) {
            int x = c.getCol();
            int y = c.getRow();
            
            if (x < minX)
                minX = x;
            if (x > maxX)
                maxX = x;
            if (y < minY)
                minY = y;
            if (y > maxY)
                maxY = y;
            
            //replace String values
            if(c.string) {
                c.value = sharedStrings[c.getValueInt()];
            }
        }
        int w = maxX - minX + 1;
        int h = maxY - minY + 1;
        
        String[][] values = new String[h][w];
        
        for(CellData c : cellDatas) {
            values[c.getRow() - minY][c.getCol() - minX] = c.value;
        }
        
        return values;
    
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    return null;
}

private static String readZipEntryToString(ZipInputStream zis) throws IOException {
    byte[] buffer = new byte[1024];
    int len;
    
    StringBuilder xml = new StringBuilder();
    while ((len = zis.read(buffer)) > 0) {
        String str = new String(buffer, 0, len);
        xml.append(str);
    }
    return xml.toString();
}

private static String[] sharedStringsFromXML(String xml) {
    LinkedList<String> res = new LinkedList<>();
    
    int index = 0;
    while((index = xml.indexOf("<t>", index)) != -1) {
        
        int end = xml.indexOf("</t>", index);
        res.add(xml.substring(index + 3, end));
        index = end;
    }
    return (String[]) res.toArray(new String[res.size()]);
}

private static LinkedList<CellData> cellDataFromXLSXextractedXML(String sheetXml) {
    String sheetData = sheetXml.substring(sheetXml.indexOf("<sheetData>")  + "<sheetData>".length(), sheetXml.indexOf("</sheetData>"));
    
    LinkedList<CellData> cellData = new LinkedList<>();
    
    int index = 0;
    while((index = sheetData.indexOf("<c r=\"", index)) != -1) {
        String cellID = sheetData.substring(index + 6, sheetData.indexOf('"', index + 6));
        int endOfTag = sheetData.indexOf('>', index);
        int typeString = sheetData.indexOf("t=\"s\"", index);
        
        boolean isStr = typeString != -1 && typeString < endOfTag;
        int valOpen = sheetData.indexOf("<v>", endOfTag);
        int valClose = sheetData.indexOf("</v>", valOpen);
        
        String value = sheetData.substring(valOpen + 3, valClose);
        
        cellData.add(new CellData(cellID, value, isStr));
        index = endOfTag;
    }
    
    return cellData;
}

private static class CellData {
    public String cellID;
    public String value;
    public boolean string;
    
    public CellData(String cellID, String value, boolean string) {
        this.cellID = cellID;
        this.value = value;
        this.string = string;
    }
    
    private int getCol() {
        String rev_id = new StringBuilder(cellID).reverse().toString();
        int pos = 0;
        int sum = 0;
        while(Character.isDigit(rev_id.charAt(pos))) {
            pos++;
        }
        int offs = pos;
        
        while(pos < rev_id.length()) {
            sum += (((int)rev_id.charAt(pos)) - ((int)'A')) * (powInt(26, pos - offs));
            pos++;
        }
        return sum;
    }
    
    private int getRow() {
        int pos = 0;
        while(!Character.isDigit(cellID.charAt(pos))) {
            pos++;
        }
        return Integer.parseInt(cellID.substring(pos));
    }
    
    public int getValueInt() {
        return Integer.parseInt(value);
    }
    
    private int powInt(int base, int to) {
        int res = 1;
        for(int i = 0; i < to; i++) {
            res *= base;
        }
        return res;
    }
    
    @Override
    public String toString() {
        return "Cell: [" + getCol() + ", " + getRow() + "]: " + value + " (str: " +string + ")";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.