jjzjj

android - 在 Android 中读取 Excel

coder 2023-12-26 原文

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

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

JExcel API:
- 不支持 XLSX

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

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

最佳答案

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

但是,如果您只需要阅读 Excel,那么使用 JavaScript 解决方案可能会更好。用js-xlsx库,您可以将 Excel 文件转换为 JSON。而且库体积小,只有 395KB(只包含 xlsx.core.min.js)

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

这是代码

回调接口(interface):

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

主要 Activity :

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>

关于android - 在 Android 中读取 Excel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39969478/

有关android - 在 Android 中读取 Excel的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  3. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  4. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  5. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  6. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  7. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  8. ruby - 如何从 ARGF 读取 csv - 2

    在Ruby1.9中,我如何从ARGF中读取CSV?我尝试了以下方法,但没有打印任何内容:require'csv'CSV(ARGF).readdo|row|prowendhttp://www.ruby-doc.org/core-1.9.3/ARGF.htmlhttp://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html 最佳答案 如果你想偷懒你可以试试:CSV.new(ARGF.file).eachdo|row|...end来源:http://www.ruby-doc.org/std

  9. Ruby:写入 stdin 并从 stdout 读取? - 2

    我正在编写一个ruby​​程序,它应该执行另一个程序,通过stdin向它传递值,从它的stdout读取响应,然后打印响应。这是我目前所拥有的。#!/usr/bin/envrubyrequire'open3'stdin,stdout,stderr=Open3.popen3('./MyProgram')stdin.puts"helloworld!"output=stdout.readerrors=stderr.readstdin.closestdout.closestderr.closeputs"Output:"puts"-------"putsoutputputs"\nErrors:"p

  10. ruby - 是否可以从 ruby​​ 脚本返回值并在 c 或 shell 脚本中读取该值? - 2

    我们如何从ruby​​脚本返回值?#!/usr/bin/envrubya="test"a我们如何在Ubuntu终端或java或c中访问'a'的值? 最佳答案 在ruby​​/python脚本中打印你的变量,然后可以通过示例从shell脚本中读取它:#!/bin/bashruby_var=$(rubymyrubyscript.rb)python_var=$(pythonmypythonscript.py)echo"$ruby_var"echo"$python_var"注意你的ruby​​/python脚本只打印这个变量(有更多复杂的方

随机推荐