java中使用sax的方式读取大数据量的excel数据

1.当使用sax事件驱动读取大数据量的excel的使用maven导入我们需要的jar包:

<properties>
    <poi.version>3.17</poi.version>
    <xerces.version>2.11.0</xerces.version>
</properties>
 <!-- POI -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>xerces</groupId>
        <artifactId>xercesImpl</artifactId>
        <version>${xerces.version}</version>
    </dependency>

2.定义行处理器:

public interface RowHandler {
    /**
     * 处理一行数据
     * @param sheetIndex 当前Sheet序号
     * @param rowIndex 当前行号
     * @param rowList 行数据列表
     */
    void handle(int sheetIndex, int rowIndex, List<Object> rowList);
}

3.定于字符串枚举类型

public enum CellDataType {
    /** Boolean类型 */
    BOOL("b"),
    /** 类型错误 */
    ERROR("e"),
    /** 计算结果类型 */
    FORMULA("str"),
    /** 富文本类型 */
    INLINESTR("inlineStr"),
    /** 字符串类型 */
    SSTINDEX("s"),
    /** 数字类型 */
    NUMBER(""),
    /** 日期类型 */
    DATE("m/d/yy"),
    /** 空类型 */
    NULL("");

    /** 属性值 */
    private String name;

    /**
     * 构造
     *
     * @param name 类型属性值
     */
    private CellDataType(String name) {
        this.name = name;
    }

    /**
     * 获取对应类型的属性值
     *
     * @return 属性值
     */
    public String getName() {
        return name;
    }

    /**
     * 类型字符串转为枚举
     * @param name 类型字符串
     * @return 类型枚举
     */
    public static CellDataType of(String name) {
        if(null == name) {
            //默认数字
            return NUMBER;
        }

        if(BOOL.name.equals(name)) {
            return BOOL;
        }else if(ERROR.name.equals(name)) {
            return ERROR;
        }else if(INLINESTR.name.equals(name)) {
            return INLINESTR;
        }else if(SSTINDEX.name.equals(name)) {
            return SSTINDEX;
        }else if(FORMULA.name.equals(name)) {
            return FORMULA;
        }else {
            return NULL;
        }
    }
}

4.定义一个抽象接口为实现接口编程,方便扩展03版

import java.io.File;
import java.io.InputStream;

public interface SaxReader<T> {
    /**
     * 开始读取Excel,读取所有sheet
     *
     * @param path Excel文件路径
     * @return this
     */
    T read(String path) ;

    /**
     * 开始读取Excel,读取所有sheet
     *
     * @param file Excel文件
     * @return this
     */
    T read(File file) ;

    /**
     * 开始读取Excel,读取所有sheet,读取结束后并不关闭流
     *
     * @param in Excel包流
     * @return this
     */
    T read(InputStream in) ;

    /**
     * 开始读取Excel
     *
     * @param path 文件路径
     * @param sheetIndex Excel中的sheet编号,如果为-1处理所有编号的sheet
     * @return this
     */
    T read(String path, int sheetIndex);

    /**
     * 开始读取Excel
     *
     * @param file Excel文件
     * @param sheetIndex Excel中的sheet编号,如果为-1处理所有编号的sheet
     * @return this
     */
    T read(File file, int sheetIndex);

    /**
     * 开始读取Excel,读取结束后并不关闭流
     *
     * @param in Excel流
     * @param sheetIndex Excel中的sheet编号,如果为-1处理所有编号的sheet
     * @return this
     */
    T read(InputStream in, int sheetIndex) ;

}

5.定义抽象类实现部分接口方法

import java.io.File;
import java.io.InputStream;

public abstract class AbstractReader<T> implements SaxReader<T> {
  @Override
  public T read(String path) {
      return read(new File(path),-1);
  }

  @Override
  public T read(File file) {
      return read(file,-1);
  }

  @Override
  public T read(InputStream in) {
      return read(in,-1);
  }

  @Override
  public T read(String path, int sheetIndex) {
      return read(new File(path),sheetIndex);
  }

}

  1. 编写实现方法实现事件驱动
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.xml.sax.*;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Excel07Bysax extends  AbstractReader<Excel07Bysax> implements ContentHandler {

    // saxParser
    private static final String CLASS_SAXPARSER = "org.apache.xerces.parsers.SAXParser";
    /** Cell单元格元素 */
    private static final String C_ELEMENT = "c";
    /** 行元素 */
    private static final String ROW_ELEMENT = "row";
    /** Cell中的行列号 */
    private static final String R_ATTR = "r";
    /** Cell类型 */
    private static final String T_ELEMENT = "t";
    /** SST(SharedStringsTable) 的索引 */
    private static final String S_ATTR_VALUE = "s";
    // 列中属性值
    private static final String T_ATTR_VALUE = "t";
    // sheet r:Id前缀
    private static final String RID_PREFIX = "rId";

    // excel 2007 的共享字符串表,对应sharedString.xml
    private SharedStringsTable sharedStringsTable;
    // 当前行
    private int curRow;
    // 当前列
    private int curCell;
    // 上一次的内容
    private String lastContent;
    // 单元数据类型
    private CellDataType cellDataType;
    // 当前列坐标, 如A1,B5
    private String curCoordinate;
    // 前一个列的坐标
    private String preCoordinate;
    // 行的最大列坐标
    private String maxCellCoordinate;
    // 单元格的格式表,对应style.xml
    private StylesTable stylesTable;
    // 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引
    private int numFmtIndex;
    // 单元格存储的格式化字符串,nmtFmt的formateCode属性的值
    private String numFmtString;
    // sheet的索引
    private int sheetIndex;
    // 存储每行的列元素
    List<Object> rowCellList = new ArrayList<>();
    /** 行处理器 */
    private RowHandler rowHandler;
    /**
     * 构造
     *
     * @param rowHandler 行处理器
     */
    public Excel07Bysax(RowHandler rowHandler) {
        this.rowHandler = rowHandler;
    }

    @Override
    public Excel07Bysax read(File file, int sheetIndex) {
        try {
            return read(OPCPackage.open(file),sheetIndex);
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Excel07Bysax read(InputStream in, int sheetIndex) {
        try {
            return read(OPCPackage.open(in),sheetIndex);
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Excel07Bysax read(OPCPackage opcPackage, int sheetIndex)   {
        //获得excel包
        InputStream sheetInputStream = null;
        try{

                //xssf读取器
                final XSSFReader xssfReader = new XSSFReader(opcPackage);
                // 获取共享样式表
                //style.xml
                stylesTable = xssfReader.getStylesTable();
                // 获取共享字符串表
                // sharedStrings.xml
                this.sharedStringsTable = xssfReader.getSharedStringsTable();
                if (sheetIndex > -1) {
                    this.sheetIndex = sheetIndex;
                    // 根据 rId# 或 rSheet# 查找sheet
                    sheetInputStream = xssfReader.getSheet(RID_PREFIX + (sheetIndex + 1));
                    parse(sheetInputStream);
                } else {
                    this.sheetIndex = -1;
                    // 遍历所有sheet
                    final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
                    while (sheetInputStreams.hasNext()) {
                        // 重新读取一个sheet时行归零
                        curRow = 0;
                        this.sheetIndex++;
                        sheetInputStream = sheetInputStreams.next();
                        parse(sheetInputStream);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (OpenXML4JException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            }
        return this;
    }

    /**
     *  读取第一个xml时标签回调处理方法
     * @param uri
     * @param localName
     * @param qName
     * @param attributes
     * @throws SAXException
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // 单元格元素
        if (C_ELEMENT.equals(qName)) {//c为元素名称

            // 获取当前列坐标
            String tempCurCoordinate = attributes.getValue(R_ATTR);//获取当前位置
            // 前一列为null,则将其设置为"@",A为第一列,ascii码为65,前一列即为@,ascii码64
            if (preCoordinate == null) {
                preCoordinate = String.valueOf('@');
            } else {
                // 存在,则前一列要设置为上一列的坐标
                preCoordinate = curCoordinate;
            }
            // 重置当前列
            curCoordinate = tempCurCoordinate;
            // 设置单元格类型
            setCellType(attributes);
        }

        lastContent = "";
    }
    /**
     * 设置单元格的类型
     *
     * @param attribute
     */
    private void setCellType(Attributes attribute) {
        // 重置numFmtIndex,numFmtString的值
        numFmtIndex = 0;
        numFmtString = "";
        this.cellDataType = CellDataType.of(attribute.getValue(T_ATTR_VALUE));

        // 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf的第几个
        final String xfIndexStr = attribute.getValue(S_ATTR_VALUE);
        //判断是否为日期类型
        if (xfIndexStr != null) {
            int xfIndex = Integer.parseInt(xfIndexStr);
            XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(xfIndex);
            numFmtIndex = xssfCellStyle.getDataFormat();
            numFmtString = xssfCellStyle.getDataFormatString();

            if (numFmtString == null) {
                cellDataType = CellDataType.NULL;
                numFmtString = BuiltinFormats.getBuiltinFormat(numFmtIndex);
            } else if (org.apache.poi.ss.usermodel.DateUtil.isADateFormat(numFmtIndex, numFmtString)) {
                cellDataType = CellDataType.DATE;
            }
        }

    }

    /**
     *  标签结束的回调处理方法
     * @param uri
     * @param localName
     * @param qName
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        final String contentStr = StrUtil.trim(lastContent);

        if (T_ELEMENT.equals(qName)) {
            // type标签
            rowCellList.add(curCell++, contentStr);
        } else if (C_ELEMENT.equals(qName)) {
            // cell标签
            Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
            // 补全单元格之间的空格
            fillBlankCell(preCoordinate, curCoordinate, false);
            rowCellList.add(curCell++, value);
        } else if (ROW_ELEMENT.equals(qName)) {
            // 如果是row标签,说明已经到了一行的结尾
            // 最大列坐标以第一行的为准
            if (curRow == 0) {
                maxCellCoordinate = curCoordinate;
            }

            // 补全一行尾部可能缺失的单元格
            if (maxCellCoordinate != null) {
                fillBlankCell(curCoordinate, maxCellCoordinate, true);
            }

            rowHandler.handle(sheetIndex, curRow, rowCellList);

            // 一行结束
            // 清空rowCellList,
            rowCellList.clear();
            // 行数增加
            curRow++;
            // 当前列置0
            curCell = 0;
            // 置空当前列坐标和前一列坐标
            curCoordinate = null;
            preCoordinate = null;
        }

    }

    /**
     * s标签结束的回调处理方法
     * @param ch
     * @param start
     * @param length
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // 得到单元格内容的值
        lastContent = lastContent.concat(new String(ch, start, length));
    }

    /**
     * 填充空白单元格,如果前一个单元格大于后一个,不需要填充<br>
     *
     * @param preCoordinate 前一个单元格坐标
     * @param curCoordinate 当前单元格坐标
     * @param isEnd 是否为最后一个单元格
     */
    private void fillBlankCell(String preCoordinate, String curCoordinate, boolean isEnd) {
        if (false == curCoordinate.equals(preCoordinate)) {
            int len = ExcelSaxUtil.countNullCell(preCoordinate, curCoordinate);
            if (isEnd) {
                len++;
            }
            while (len-- > 0) {
                rowCellList.add(curCell++, "");
            }
        }
    }

    @Override
    public void setDocumentLocator(Locator locator) {

    }

    @Override
    public void startDocument() throws SAXException {

    }

    @Override
    public void endDocument() throws SAXException {

    }

    @Override
    public void startPrefixMapping(String prefix, String uri) throws SAXException {

    }

    @Override
    public void endPrefixMapping(String prefix) throws SAXException {

    }

    @Override
    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {

    }

    @Override
    public void processingInstruction(String target, String data) throws SAXException {

    }

    @Override
    public void skippedEntity(String name) throws SAXException {

    }
    //
    /**
     * 处理流中的Excel数据
     *
     * @param sheetInputStream sheet流
     * @throws IOException IO异常
     * @throws SAXException SAX异常
     */
    private void parse(InputStream sheetInputStream) throws IOException, SAXException {
        fetchSheetReader().parse(new InputSource(sheetInputStream));
    }
    /**
     * 获取sheet的解析器
     *
     * @return {@link XMLReader}
     * @throws SAXException SAX异常
     */
    private XMLReader fetchSheetReader() throws SAXException {
        //创建xml读取器
        XMLReader xmlReader = null;
        try {
            xmlReader = XMLReaderFactory.createXMLReader(CLASS_SAXPARSER);
        } catch (SAXException e) {
            if (e.getMessage().contains("org.apache.xerces.parsers.SAXParser")) {
                throw new RuntimeException(e+ "You need to add 'xerces:xercesImpl' to your project and version >= 2.11.0");
            } else {
                throw e;
            }
        }
        //添加本类进入xml解析器
        xmlReader.setContentHandler(this);
        return xmlReader;
    }
}

7.加入实现类中的一些工具类

package com.xx.websocket.saxexcel;

import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;

import java.util.Date;

public class ExcelSaxUtil {
    // 填充字符串
    public static final char CELL_FILL_CHAR = '@';
    // 列的最大位数
    public static final int MAX_CELL_BIT = 3;
    /**
     * 计算两个单元格之间的单元格数目(同一行)
     *
     * @param preRef 前一个单元格位置,例如A1
     * @param ref 当前单元格位置,例如A8
     * @return 同一行中两个单元格之间的空单元格数
     */
    public static int countNullCell(String preRef, String ref) {
        // excel2007最大行数是1048576,最大列数是16384,最后一列列名是XFD
        // 数字代表列,去掉列信息
        String preXfd = StrUtil.nullToDefault(preRef, "@").replaceAll("\\d+", "");
        String xfd = StrUtil.nullToDefault(ref, "@").replaceAll("\\d+", "");

        // A表示65,@表示64,如果A算作1,那@代表0
        // 填充最大位数3
        preXfd = StrUtil.fillBefore(preXfd, CELL_FILL_CHAR, MAX_CELL_BIT);
        xfd = StrUtil.fillBefore(xfd, CELL_FILL_CHAR, MAX_CELL_BIT);

        char[] preLetter = preXfd.toCharArray();
        char[] letter = xfd.toCharArray();
        // 用字母表示则最多三位,每26个字母进一位
        int res = (letter[0] - preLetter[0]) * 26 * 26 + (letter[1] - preLetter[1]) * 26 + (letter[2] - preLetter[2]);
        return res - 1;
    }
    /**
     * 根据数据类型获取数据
     *
     * @param cellDataType 数据类型枚举
     * @param value 数据值
     * @param sharedStringsTable {@link SharedStringsTable}
     * @param numFmtString 数字格式名
     * @return 数据值
     */
    public static Object getDataValue(CellDataType cellDataType, String value, SharedStringsTable sharedStringsTable, String numFmtString) {
        if (null == value) {
            return null;
        }

        Object result;
        switch (cellDataType) {
            case BOOL:
                result = (value.charAt(0) != '0');
                break;
            case ERROR:
                result="error:"+value.toString();
//                result = StrUtil.format("\\\"ERROR: {} ", value);
                break;
            case FORMULA:
//                result = StrUtil.format("\"{}\"", value);
                  result=value;
                break;
            case INLINESTR:
                result = new XSSFRichTextString(value.toString()).toString();
                break;
            case SSTINDEX:
                try {
                    final int index = Integer.parseInt(value);
                    result = new XSSFRichTextString(sharedStringsTable.getEntryAt(index)).getString();
                } catch (NumberFormatException e) {
                    result = value;
                }
                break;
            case NUMBER:
                result = getNumberValue(value, numFmtString);
                break;
            case DATE:
                try {
                    result = getDateValue(value);
                } catch (Exception e) {
                    result = value;
                }
                break;
            default:
                result = value;
                break;
        }
        return result;
    }
    /**
     * 获取日期
     *
     * @param value 单元格值
     * @return 日期
     * @since 4.1.0
     */
    private static Date getDateValue(String value) {
        return org.apache.poi.ss.usermodel.DateUtil.getJavaDate(Double.parseDouble(value), false);
    }
    /**
     * 获取数字类型值
     *
     * @param value 值
     * @param numFmtString 格式
     * @return 数字,可以是Double、Long
     * @since 4.1.0
     */
    private static Number getNumberValue(String value, String numFmtString) {
        if(StrUtil.isBlank(value)) {
            return null;
        }
        double numValue = Double.parseDouble(value);
        // 普通数字
        if (null != numFmtString && numFmtString.indexOf('.') < 0) {
            final long longPart = (long) numValue;
            if (longPart == numValue) {
                // 对于无小数部分的数字类型,转为Long
                return longPart;
            }
        }
        return numValue;
    }

}

此为工具类

package com.xx.websocket.saxexcel;

public class StrUtil {
    public static final String EMPTY = "";

    /**
     * 当给定字符串为null时,转换为Empty
     *
     * @param str 被转换的字符串
     * @return 转换后的字符串
     */
    public static String nullToEmpty(CharSequence str) {
        return nullToDefault(str, EMPTY);
    }

    /**
     * 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。
     *
     * <pre>
     * nullToDefault(null, &quot;default&quot;)  = &quot;default&quot;
     * nullToDefault(&quot;&quot;, &quot;default&quot;)    = &quot;&quot;
     * nullToDefault(&quot;  &quot;, &quot;default&quot;)  = &quot;  &quot;
     * nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;
     * </pre>
     *
     * @param str 要转换的字符串
     * @param defaultStr 默认字符串
     *
     * @return 字符串本身或指定的默认字符串
     */
    public static String nullToDefault(CharSequence str, String defaultStr) {
        return (str == null) ? defaultStr : str.toString();
    }
    /**
     * 将已有字符串填充为规定长度,如果已有字符串超过这个长度则返回这个字符串<br>
     * 字符填充于字符串前
     *
     * @param str 被填充的字符串
     * @param filledChar 填充的字符
     * @param len 填充长度
     * @return 填充后的字符串
     * @since 3.1.2
     */
    public static String fillBefore(String str, char filledChar, int len) {
        return fill(str, filledChar, len, true);
    }
    /**
     * 将已有字符串填充为规定长度,如果已有字符串超过这个长度则返回这个字符串
     *
     * @param str 被填充的字符串
     * @param filledChar 填充的字符
     * @param len 填充长度
     * @param isPre 是否填充在前
     * @return 填充后的字符串
     * @since 3.1.2
     */
    public static String fill(String str, char filledChar, int len, boolean isPre) {
        final int strLen = str.length();
        if (strLen > len) {
            return str;
        }

        String filledStr = StrUtil.repeat(filledChar, len - strLen);
        return isPre ? filledStr.concat(str) : str.concat(filledStr);
    }
    /**
     * 重复某个字符
     *
     * @param c 被重复的字符
     * @param count 重复的数目,如果小于等于0则返回""
     * @return 重复字符字符串
     */
    public static String repeat(char c, int count) {
        if (count <= 0) {
            return EMPTY;
        }

        char[] result = new char[count];
        for (int i = 0; i < count; i++) {
            result[i] = c;
        }
        return new String(result);
    }
//    /**
//     * 格式化文本, {} 表示占位符<br>
//     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
//     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
//     * 例:<br>
//     * 通常使用:format("this is {} for {}", "a", "b") =》 this is a for b<br>
//     * 转义{}: format("this is \\{} for {}", "a", "b") =》 this is \{} for a<br>
//     * 转义\: format("this is \\\\{} for {}", "a", "b") =》 this is \a for b<br>
//     *
//     * @param template 文本模板,被替换的部分用 {} 表示
//     * @param params 参数值
//     * @return 格式化后的文本
//     */
//    public static String format(CharSequence template, Object... params) {
//        if (null == template) {
//            return null;
//        }
//        if (isEmpty(params) || isBlank(template)) {
//            return template.toString();
//        }
//        return StrFormatter.format(template.toString(), params);
//    }
    /**
     * 数组是否为空
     *
     * @param <T> 数组元素类型
     * @param array 数组
     * @return 是否为空
     */
    @SuppressWarnings("unchecked")
    public static <T> boolean isEmpty(final T... array) {
        return array == null || array.length == 0;
    }
    /**
     * 字符串是否为空白 空白的定义如下: <br>
     * 1、为null <br>
     * 2、为不可见字符(如空格)<br>
     * 3、""<br>
     *
     * @param str 被检测的字符串
     * @return 是否为空
     */
    public static boolean isBlank(CharSequence str) {
        int length;

        if ((str == null) || ((length = str.length()) == 0)) {
            return true;
        }

        for (int i = 0; i < length; i++) {
            // 只要有一个非空字符即为非空字符串
            if (false == isBlankChar(str.charAt(i))) {
                return false;
            }
        }

        return true;
    }
    /**
     * 是否空白符<br>
     * 空白符包括空格、制表符、全角空格和不间断空格<br>
     *
     * @see Character#isWhitespace(int)
     * @see Character#isSpaceChar(int)
     * @param c 字符
     * @return 是否空白符
     * @since 4.0.10
     */
    public static boolean isBlankChar(int c) {
        return Character.isWhitespace(c) || Character.isSpaceChar(c) || c == '\ufeff' || c == '\u202a';
    }
    /**
     * 是否为“null”、“undefined”,不做空指针检查
     *
     * @param str 字符串
     * @return 是否为“null”、“undefined”
     */
    private static boolean isNullOrUndefinedStr(CharSequence str) {
        String strString = str.toString().trim();
        return "null".equals(strString) || "undefined".equals(strString);
    }
    // ------------------------------------------------------------------------ Trim
    /**
     * 除去字符串头尾部的空白,如果字符串是<code>null</code>,依然返回<code>null</code>。
     *
     * <p>
     * 注意,和<code>String.trim</code>不同,此方法使用<code>NumberUtil.isBlankChar</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
     *
     * <pre>
     * trim(null)          = null
     * trim(&quot;&quot;)            = &quot;&quot;
     * trim(&quot;     &quot;)       = &quot;&quot;
     * trim(&quot;abc&quot;)         = &quot;abc&quot;
     * trim(&quot;    abc    &quot;) = &quot;abc&quot;
     * </pre>
     *
     * @param str 要处理的字符串
     *
     * @return 除去头尾空白的字符串,如果原字串为<code>null</code>,则返回<code>null</code>
     */
    public static String trim(CharSequence str) {
        return (null == str) ? null : trim(str, 0);
    }
    /**
     * 除去字符串头尾部的空白符,如果字符串是<code>null</code>,依然返回<code>null</code>。
     *
     * @param str 要处理的字符串
     * @param mode <code>-1</code>表示trimStart,<code>0</code>表示trim全部, <code>1</code>表示trimEnd
     *
     * @return 除去指定字符后的的字符串,如果原字串为<code>null</code>,则返回<code>null</code>
     */
    public static String trim(CharSequence str, int mode) {
        if (str == null) {
            return null;
        }

        int length = str.length();
        int start = 0;
        int end = length;

        // 扫描字符串头部
        if (mode <= 0) {
            while ((start < end) && (isBlankChar(str.charAt(start)))) {
                start++;
            }
        }

        // 扫描字符串尾部
        if (mode >= 0) {
            while ((start < end) && (isBlankChar(str.charAt(end - 1)))) {
                end--;
            }
        }

        if ((start > 0) || (end < length)) {
            return str.toString().substring(start, end);
        }

        return str.toString();
    }

}

8.此方法是吧xlsx作为xml进行读取,我们可以修改xlsx文件更好的观察

 1.修改xlsx文件的后缀为zip,并且解压此文件
11122449-7a1b16c5a3dc9c0c.png
图片.png
2.查询xl文件打开sheet1,图中的t是作为字符的类型,s代表字符型 ,属性s中的value值,我们去style.xml中找对应的第几个从零开始算。
11122449-8248e33d8d36661c.png
图片.png
11122449-91e0a72dbc08e00f.png
图片.png

当t等于s,我们拿到v中的值去sharedStrings.xml中找第几个从0开始取出string的值


11122449-1d0a097f496e598c.png
图片.png
11122449-8befc4fb1e4d5a1a
小新java讲堂

猜你喜欢

转载自blog.csdn.net/weixin_33877885/article/details/87491628
今日推荐