2016-10-11 68 views
2

當前我正在開發Android。如要求所述,應用程序應能夠讀取Excel文件以輸入數據。在Android中閱讀Excel

至於其他人開始這個話題,我有Java Excel ApiApache POI經歷,但都需要有一些修改,以適應我的要求:

JExcel API
- 無法支持XLSX

的Apache POI
- 支持以及爲XLS文件
- 支持XLSX在Dalvik的,你需要克服64K和使用javax李brary,或使用端口版本(即從Andrew Kondratev
- 文件大小將增加2.4MB

但是我們有其他選擇使用Android 4或更低版本的Excel文件嗎?

回答

4

對於那些誰需要全功能的Excel文件的工作程序(即圖紙,VBA等...),你應該的Apache POI去,這是顯而易見,但仍然是目前最好的解決辦法。

但是,如果您只需要閱讀Excel,那麼使用JavaScript解決方案可能會很好。使用js-xlsx庫,可以將Excel文件轉換爲JSON。和庫規模很小,只有395KB(僅包括xlsx.core.min.js

我相信這不是最好的解決辦法:
- WebView需要與UI Thread工作,它可能會阻止當UI閱讀大型Excel文件。
- 性能問題
但是,您可以將其更改爲其他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庫到資產文件夾)

<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>