【问题标题】:Read Excel in Android在 Android 中读取 Excel
【发布时间】:2017-02-19 12:52:26
【问题描述】:

目前我正在从事 android 开发。正如要求所述,应用程序应该能够读取 Excel 文件以进行数据输入。

当其他人从这个主题开始时,我已经完成了 Java Excel ApiApache POI,但两者都需要进行一些修改以满足我的要求:

JExcel API
- 无法支持 XLSX

Apache POI
- 很好地支持 XLS 文件
- 要在 Dalvik 中支持 XLSX,您需要克服 64K 和 javax 库,或者使用端口版本(即来自Andrew Kondratev
- 文件大小将增加 2.4MB

但是我们是否有其他选项可以在 Android 4 或更低版本中处理 Excel 文件?

【问题讨论】:

    标签: android excel apache-poi jexcelapi


    【解决方案1】:

    对于那些需要使用完整功能的 excel 文件(即绘图、VBA 等...)的应用程序,您应该使用 Apache POI,这很简单但现在仍然是最好的解决方案。

    但是,如果您只需要阅读 Excel,则最好使用 JavaScript 解决方案。使用js-xlsx 库,您可以将 Excel 文件转换为 JSON。而且库很小,只有395KB(只包括xlsx.core.min.js

    我认为这不是最好的解决方案:
    - WebView 需要与 UI Thread 配合使用,读取大型 Excel 文件时可能会阻塞 UI。
    - 性能问题
    但是您可以将其更改为其他 JavaScript 引擎,例如 RhinoV8 来解决这些问题。

    这里是代码

    回调接口:

    public interface ExcelReaderListener {
        void onReadExcelCompleted(List<String> stringList);
    }
    

    MainActivity:

    private ProgressDialog progressDialog;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        new AlertDialog.Builder(MainActivity.this)
                .setMessage("message")
                .setTitle("title")
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
    
                        new FileChooser(MainActivity.this, new String[]{"xls", "xlsx"})
                                .setFileListener(new FileChooser.FileSelectedListener() {
                                    @Override
                                    public void fileSelected(File file) {
                                        progressDialog = new ProgressDialog(MainActivity.this);
                                        progressDialog.setTitle("title");
                                        progressDialog.setMessage("message");
                                        progressDialog.setIndeterminate(true);
                                        progressDialog.setCanceledOnTouchOutside(false);
    
                                        Toast.makeText(MainActivity.this, file.getName(), Toast.LENGTH_SHORT).show();
                                        String filePath = file.getAbsolutePath();
                                        ExcelReaderListener excelReaderListener = MainActivity.this;
    
                                        progressDialog.show();
                                        try {
                                            final WebView webView = new WebView(MainActivity.this);
                                            new JSExcelReader(filePath, webView, excelReaderListener);
                                        } catch (Exception ex) {
                                            Log.e("Import excel error", ex.getMessage());
                                        }
                                    }
                                })
                                .showDialog();
                    }
                })
                .show();
    }
    
    @Override
    public void onReadExcelCompleted(List<String> stringList) {
        Toast.makeText(MainActivity.this, "Parse Completed", Toast.LENGTH_SHORT).show();
    
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
    
        // Write into DB
        ...
    }
    

    用户选择excel文件的界面:

    https://rogerkeays.com/simple-android-file-chooser

    JSExcelReader:(读取excel并将其转换为ArrayList的核心部分)

    public class JSExcelReader {
    
        private ExcelReaderListener callback;
    
        public JSExcelReader(String filePath, final WebView webView, ExcelReaderListener callback) {
            this.callback = callback;
    
            File file = new File(filePath);
    
            try (InputStream is = new FileInputStream(file)) {
                // convert file to Base64
                if (file.length() > Integer.MAX_VALUE)
                    Log.e("File too big", "file too big");
                byte[] bytes = new byte[(int) file.length()];
    
                int offset = 0;
                int numRead;
                while (offset < bytes.length &&
                (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                    offset += numRead;
                }
    
                if (offset < bytes.length)
                    throw new Exception("Could not completely read file");
    
                final String b64 = Base64.encodeToString(bytes, Base64.NO_WRAP);
    
                // feed the string into webview and get the result
                WebSettings webSettings = webView.getSettings();
                webSettings.setJavaScriptEnabled(true);
                webView.loadUrl("file:///android_asset/AndroidParseExcel.html");
                webView.setWebViewClient(new WebViewClient() {
                    public void onPageFinished(WebView view, String url) {
                        webView.evaluateJavascript("convertFile('" + b64 + "');", new ValueCallback<String>() {
                            @Override
                            public void onReceiveValue(String value) {
                                parseJSON(value);
                            }
                        });
                    }
                });
            } catch (Exception ex) {
                Log.e("Convert Excel failure", ex.getMessage());
            }
        }
    
        private void parseJSON(String jsonString) {
            try {
                // return value is something like "{\n\"Sheet1\":\n[\"title\"...
                // you need to remove those escape character first
                JSONObject jsonRoot = new JSONObject(jsonString.substring(1, jsonString.length() - 1)
                                                                .replaceAll("\\\\n", "")
                                                                .replaceAll("\\\\\"", "\"")
                                                                .replaceAll("\\\\\\\\\"", "'"));
                JSONArray sheet1 = jsonRoot.optJSONArray("Sheet1");
                List<String> stringList = new ArrayList<>();
    
                JSONObject jsonObject;
                for (int i = 0; i < sheet1.length(); i++) {
                    jsonObject = sheet1.getJSONObject(i);
    
                    stringList.add(jsonObject.optString("title"));
                }
    
                callback.onReadExcelCompleted(stringList);
            } catch (Exception ex) {
                Log.e("Error in parse JSON", ex.getMessage());
            }
        }
    }
    

    AndroidParseExcel.html:(你应该把这个和 JavaScript 库放到 asset 文件夹中)

    <html>
    <script src="file:///android_asset/xlsx.core.min.js"></script>
    <head></head>
    <body>
    </body>
    <script type ="text/javascript">
    
        "use strict";
    
        var X = XLSX;
    
        function convertFile(b64data) {
            var wb = X.read(b64data, {type: 'base64',WTF: false});
    
            var result = {};
            wb.SheetNames.forEach(function(sheetName) {
                var roa = X.utils.sheet_to_row_object_array(wb.Sheets[sheetName]);
                if(roa.length > 0){
                    result[sheetName] = roa;
                }
            });
    
            return JSON.stringify(result, 2, 2);
        }
    </script>
    </html>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-28
      • 2017-05-22
      • 2018-04-05
      • 1970-01-01
      相关资源
      最近更新 更多