zoukankan      html  css  js  c++  java
  • Android EXCEL 解析 xls 和 xlsx,方法其实很简单

    前言

    Excel 解析,一般来说是在服务端进行的,但是如果移动端要实现解析Excel的功能,那也是有实现的方法的。

    不过由于Android 原生用Java/Kotlin实现,所以也可以参考服务端解析Excel的方法。

    首先说,jxl,过去比较流行的解析office文档的框架,但目前官方的版本,在移动端上是不能解析xlsx。

    然后是POI,是如今比较主流的处理office文档的框架,可以导入也可以生成,缺点是:官方的依赖包的体积较大,官方最新版本在android项目所需sdk需要minSDK 24及以上。

    最后找到的一个比较轻便简单的方案是,通过一个国外的开发者对POI包进行简化后的库android5xlsx,保留了在Android5以上解析xls和xlsx的功能(开发者本人吐槽在android5以下解析Excel真有点绕)

    android5xlsx的github地址

    下面是我的项目中简单使用这个库的一些步骤(非源码分析讲解,请谅解):(Android 10 环境实测有效)

    使用步骤

    一、解除 65 K 方法的限制

    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.2"
        defaultConfig {
    		.....
            versionName "1.0"
            multiDexEnabled true  //true 开启多dex,解除65k限制
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
    }
    

    二、将android5xlsx的核心的两个jar包导入项目lib文件夹

    将简单解析Excel文件内容的操作,封装在一个工具类ExcelUtils内:

    Excel解析工具类代码

    import android.util.Log;
    import com.blankj.utilcode.util.LogUtils;
    import org.apache.poi.hssf.usermodel.HSSFDateUtil;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.CellValue;
    import org.apache.poi.ss.usermodel.FormulaEvaluator;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.text.SimpleDateFormat;
    
    /**
     * @description: Excel 工具类
     * @author: ODM
     * @date: 2020/4/11
     */
    public class ExcelUtils {
    
        /**
         * 读取Excel文件
         * @param file
         * @throws FileNotFoundException
         */
        public static void readExcel(File file) throws FileNotFoundException {
            if(file == null) {
                Log.e("NullFile","读取Excel出错,文件为空文件");
                return;
            }
            InputStream stream = new FileInputStream(file);
            try {
                XSSFWorkbook workbook = new XSSFWorkbook(stream);
                XSSFSheet sheet = workbook.getSheetAt(0);
                int rowsCount = sheet.getPhysicalNumberOfRows();
                FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator();
                for (int r = 0; r<rowsCount; r++) {
                    Row row = sheet.getRow(r);
                    int cellsCount = row.getPhysicalNumberOfCells();
                    //每次读取一行的内容
                    for (int c = 0; c<cellsCount; c++) {
                        //将每一格子的内容转换为字符串形式
                        String value = getCellAsString(row, c, formulaEvaluator);
                        String cellInfo = "r:"+r+"; c:"+c+"; v:"+value;
                        LogUtils.d(cellInfo);
                    }
                }
            } catch (Exception e) {
                /* proper exception handling to be here */
                LogUtils.e(e.toString());
            }
    
        }
    
        /**
         * 读取excel文件中每一行的内容
         * @param row
         * @param c
         * @param formulaEvaluator
         * @return
         */
        private static String getCellAsString(Row row, int c, FormulaEvaluator formulaEvaluator) {
            String value = "";
            try {
                Cell cell = row.getCell(c);
                CellValue cellValue = formulaEvaluator.evaluate(cell);
                switch (cellValue.getCellType()) {
                    case Cell.CELL_TYPE_BOOLEAN:
                        value = ""+cellValue.getBooleanValue();
                        break;
                    case Cell.CELL_TYPE_NUMERIC:
                        double numericValue = cellValue.getNumberValue();
                        if(HSSFDateUtil.isCellDateFormatted(cell)) {
                            double date = cellValue.getNumberValue();
                            SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yy");
                            value = formatter.format(HSSFDateUtil.getJavaDate(date));
                        } else {
                            value = ""+numericValue;
                        }
                        break;
                    case Cell.CELL_TYPE_STRING:
                        value = ""+cellValue.getStringValue();
                        break;
                    default:
                        break;
                }
            } catch (NullPointerException e) {
                /* proper error handling should be here */
                LogUtils.e(e.toString());
            }
            return value;
        }
    
        /**
         * 根据类型后缀名简单判断是否Excel文件
         * @param file 文件
         * @return 是否Excel文件
         */
        public static boolean checkIfExcelFile(File file){
            if(file == null) {
                return false;
            }
            String name = file.getName();
            //”.“ 需要转义字符
            String[] list = name.split("\.");
            //划分后的小于2个元素说明不可获取类型名
            if(list.length < 2) {
                return false;
            }
            String  typeName = list[list.length - 1];
            //满足xls或者xlsx才可以
            return "xls".equals(typeName) || "xlsx".equals(typeName);
        }
    }
    
    

    三、简单解析一个Excel文件 演示

    在页面打开文件管理器,选取手机本地的excel文件,然后利用ExcelUtils打印出excel文件的内容:

    顺带一提,读取Excel也是需要对应读写文件的权限的哦~

    class MemberFragment : BaseMVVMFragment() {
    
        // 打开系统自带的文件选择器
        private fun openFileSelector() {
            val intent = Intent(Intent.ACTION_GET_CONTENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = "*/*"
    //        intent.type = "application/vnd.ms-excel application/x-excel" 未知无效原因
            this.startActivityForResult(intent, 1)
        }
    
        override fun onActivityResult(
            requestCode: Int,
            resultCode: Int,  data: Intent?
        ) {
            super.onActivityResult(requestCode, resultCode, data)
            if (data == null) {
                // 用户未选择任何文件,直接返回
                return
            }
            val uri: Uri? = data.data // 获取用户选择文件的URI
            uri?.let {
                val file = UriUtils.uri2File(it)
                if(ExcelUtils.checkIfExcelFile(file)){
                    ExcelUtils.readExcel(file) //读取Excel file 内容
                }
            }
        }
    
    }
    

    在本地文件管理器中,任意选择一个excel文件,这里是选择了读取 test2.xlsx 文件,以下是excel文件内的内容

    解析结果:以log打印结果展示

    可以看到可以按照从左到右读取每一行内容,一直向下读取。

    有需要的同学可以根据需求,改造一下解析工具类,可以将解析结果转为所需要的实体类对象,也可以写入Excel,更更更具体多样的操作请参考开发者给出的demo吧。

    总结

    我认为这是在Android端解析Excel 的xls xlsx内容的方案中,使用起来比较简单且轻便挺不错的方案。

    我的文章中的代码比较简陋,仅为各位同学提供一个实现这个功能的思路~

    十分谢谢阅读的同学,欢迎交流和讨论~

  • 相关阅读:
    MyEclipse配置DataBase Explorer
    Eclipse 如何设置注释的模板
    游戏开发技术
    static_cast 与reinterpret_cast
    一个人的成功取决于晚上的8点至10点经典语录必读
    发送消息给线程
    转载ofstream和ifstream详细用法
    Effective STL笔记
    Making your C++ code robust
    TGA文件
  • 原文地址:https://www.cnblogs.com/DMingO/p/12789902.html
Copyright © 2011-2022 走看看