• Android 导入导出excel xls、xlsx


    1.导入依赖

    implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '3.17'
    implementation group: 'org.apache.xmlbeans', name: 'xmlbeans', version: '3.1.0'
    implementation 'javax.xml.stream:stax-api:1.0'
    implementation 'com.fasterxml:aalto-xml:1.2.2'

    工具类

    1. package com.example.exportfile;
    2. import android.content.ContentUris;
    3. import android.content.Context;
    4. import android.database.Cursor;
    5. import android.graphics.Canvas;
    6. import android.graphics.pdf.PdfDocument;
    7. import android.net.Uri;
    8. import android.os.Build;
    9. import android.os.Environment;
    10. import android.provider.DocumentsContract;
    11. import android.provider.MediaStore;
    12. import android.text.TextUtils;
    13. import android.util.Log;
    14. import android.view.View;
    15. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    16. import org.apache.poi.ss.formula.eval.NumberEval;
    17. import org.apache.poi.ss.usermodel.Cell;
    18. import org.apache.poi.ss.usermodel.CellType;
    19. import org.apache.poi.ss.usermodel.CellValue;
    20. import org.apache.poi.ss.usermodel.FormulaEvaluator;
    21. import org.apache.poi.ss.usermodel.Row;
    22. import org.apache.poi.ss.usermodel.Sheet;
    23. import org.apache.poi.ss.usermodel.Workbook;
    24. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    25. import java.io.BufferedInputStream;
    26. import java.io.BufferedOutputStream;
    27. import java.io.File;
    28. import java.io.FileInputStream;
    29. import java.io.FileOutputStream;
    30. import java.io.IOException;
    31. import java.io.InputStream;
    32. import java.io.OutputStream;
    33. import java.util.ArrayList;
    34. import java.util.List;
    35. public class SheetHelper {
    36. static String TAG = "<<< SheetHelper >>>";
    37. /**
    38. * 导出Excel
    39. *
    40. * @param title 标题,配合 DeviceInfo 按需传入
    41. * @param listData 导出行数据
    42. * @param fileDir 导出文件夹
    43. * @param fileName 导出文件名
    44. * @param context activity上下文
    45. * @param fileNameReplace 文件名称存在时,是否需要替换
    46. * @return
    47. */
    48. public static boolean exportExcel(String[] title, List listData, String fileDir, String fileName, Context context, boolean fileNameReplace) {
    49. if (TextUtils.isEmpty(fileDir) || TextUtils.isEmpty(fileName) || listData == null) {
    50. Log.e(TAG, " 导出" + "入参不合规");
    51. return false;
    52. }
    53. try {
    54. // 创建excel xlsx格式
    55. Workbook wb = new XSSFWorkbook();
    56. // 创建工作表
    57. Sheet sheet = wb.createSheet();
    58. //创建行对象
    59. Row row = sheet.createRow(0);
    60. // 设置有效数据的行数和列数
    61. int colNum = title.length; // String[] title = {"序号", "设备号", "手机品牌", "最新位置", "换机换卡次数", "应用安装数量", "卸载应用次数", "违规app个数"};
    62. for (int i = 0; i < colNum; i++) {
    63. sheet.setColumnWidth(i, 20 * 256); // 显示20个字符的宽度 列宽
    64. Cell cell1 = row.createCell(i);
    65. //第一行
    66. cell1.setCellValue(title[i]);
    67. }
    68. // 导入数据
    69. for (int rowNum = 0; rowNum < listData.size(); rowNum++) {
    70. // 之所以rowNum + 1 是因为要设置第二行单元格
    71. row = sheet.createRow(rowNum + 1);
    72. // 设置单元格显示宽度
    73. row.setHeightInPoints(28f);
    74. // DeviceInfo 这个是我的业务类,这个是根据业务来进行填写数据
    75. DeviceInfo bean = listData.get(rowNum);
    76. for (int j = 0; j < title.length; j++) {
    77. Cell cell = row.createCell(j);
    78. //要和title[]一一对应
    79. switch (j) {
    80. case 0:
    81. //序号
    82. cell.setCellValue(bean.getRow());
    83. break;
    84. case 1:
    85. //设备id
    86. cell.setCellValue(bean.getDeviceId());
    87. break;
    88. case 2:
    89. //手机品牌
    90. cell.setCellValue(bean.getPhoneBrand());
    91. break;
    92. case 3:
    93. //最新位置
    94. cell.setCellValue(bean.getLatestLocation());
    95. break;
    96. case 4:
    97. //换机换卡次数
    98. cell.setCellValue(bean.getChangeSum());
    99. break;
    100. case 5:
    101. //应用安装数量
    102. cell.setCellValue(bean.getInstallAppSum());
    103. break;
    104. case 6:
    105. //卸载应用次数
    106. cell.setCellValue(bean.getUninstallAppSum());
    107. break;
    108. case 7:
    109. //违规app个数
    110. cell.setCellValue(bean.getViolationAppSum());
    111. break;
    112. }
    113. }
    114. }
    115. String s = Environment.getExternalStorageDirectory() + "/" + fileDir;
    116. // String mSDCardFolderPath = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + "/" + fileDir;
    117. File dir = new File(s);
    118. //判断文件是否存在
    119. if (!dir.exists()) {
    120. //不存在则创建
    121. dir.mkdirs();
    122. }
    123. File excel = new File(dir, fileName + ".xlsx");
    124. if (!excel.exists()) {
    125. excel.createNewFile();
    126. } else {
    127. if (fileNameReplace) {
    128. //String newFileName = getNewFileName(getFiles(dir.getPath(), new ArrayList<>()), excel.getPath());
    129. String newFileName = getXlsxNewFileName(excel);
    130. excel = new File(newFileName);
    131. excel.createNewFile();
    132. }
    133. }
    134. Log.e(TAG, " 导出路径" + excel.getPath().toString());
    135. FileOutputStream fos = new FileOutputStream(excel);
    136. wb.write(fos);
    137. wb.close();
    138. fos.flush();
    139. fos.close();
    140. return true;
    141. } catch (IOException e) {
    142. Log.e("ExpressExcle", "exportExcel", e);
    143. return false;
    144. }
    145. }
    146. /**
    147. * 导入excel
    148. *
    149. * @param fileName 本地文件路径
    150. */
    151. public static List readExcel(String fileName) {
    152. Log.d(TAG, "!!!导入路径!!!" + fileName);
    153. if (TextUtils.isEmpty(fileName)) {
    154. Log.d(TAG, "!!!导入失败!!!" + " 路径为空 ");
    155. return null;
    156. }
    157. try {
    158. InputStream inputStream = new FileInputStream(fileName);
    159. Workbook workbook;
    160. if (fileName.endsWith(".xls")) {
    161. workbook = new HSSFWorkbook(inputStream);
    162. } else if (fileName.endsWith(".xlsx")) {
    163. workbook = new XSSFWorkbook(inputStream);
    164. } else {
    165. Log.d(TAG, "!!!导入失败!!!" + " 文件格式错误 ");
    166. return null;
    167. }
    168. int numberOfSheets = workbook.getNumberOfSheets();
    169. List strings = new ArrayList<>();
    170. for (int u = 0; u < numberOfSheets; u++) {
    171. Sheet sheet = workbook.getSheetAt(u);//获取表
    172. int rowsCount = sheet.getPhysicalNumberOfRows();//获取行数
    173. int lastRowNum = sheet.getLastRowNum();//获取最后一行,,从0开始
    174. Log.d(TAG, "行数:" + (lastRowNum + 1));
    175. FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator();
    176. for (int r = 0; r <= lastRowNum; r++) {
    177. String str = "";
    178. Row row = sheet.getRow(r);//拿到行对象
    179. if (row != null) {
    180. int physicalNumberOfCells = row.getPhysicalNumberOfCells();//获取该行可用的列数、
    181. short lastCellNum = row.getLastCellNum();//获取改行最后一列的列数
    182. int lastCell = lastCellNum;
    183. Log.d(TAG, "导入 第" + (r + 1) + "行最后一列:" + lastCell);
    184. for (int i = 0; i < lastCell; i++) {
    185. CellValue v0 = formulaEvaluator.evaluate(row.getCell(i));//获取单元格对象
    186. if (v0 != null) {
    187. CellType cellTypeEnum = v0.getCellTypeEnum();
    188. if (cellTypeEnum.getCode() == 1) {
    189. //文本类型
    190. str += v0.getStringValue() + "&&";
    191. } else if (cellTypeEnum.getCode() == 0) {
    192. //整数,小数类型
    193. // double numberValue = v0.getNumberValue();
    194. String stringValue = new NumberEval(v0.getNumberValue()).getStringValue();
    195. str += stringValue + "&&";
    196. } else {
    197. //其他类型,暂时不解析
    198. }
    199. }
    200. }
    201. Log.d(TAG, "导入 第" + (r + 1) + "行 内容:" + str);
    202. strings.add(str);
    203. } else {
    204. Log.d(TAG, "第 " + (r + 1) + " 行没有可用表格,跳过");
    205. continue;
    206. }
    207. }
    208. }
    209. workbook.close();
    210. return strings;
    211. } catch (IOException e) {
    212. e.printStackTrace();
    213. return null;
    214. }
    215. }
    216. /**
    217. * 导出PDF
    218. *
    219. * @param view 要导出的view,如果view高度过高(超过一屏的高度),在改view外部套一层Scrollview即可
    220. * @param fileDir 导出文件夹
    221. * @param fileName 导出文件名称
    222. * @param fileNameReplace 文件名称存在时,是否需要替换
    223. * @return
    224. */
    225. public static boolean createPdfFromView(View view, String fileDir, String fileName, boolean fileNameReplace) {
    226. try {
    227. if (view == null || fileDir == null || fileName == null) {
    228. Log.e(TAG, "导出PDF" + "入参为空");
    229. return false;
    230. }
    231. String s = Environment.getExternalStorageDirectory() + "/" + fileDir;
    232. // String mSDCardFolderPath = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + "/" + fileDir;
    233. File dir = new File(s);
    234. //判断文件是否存在
    235. if (!dir.exists()) {
    236. //不存在则创建
    237. dir.mkdirs();
    238. }
    239. File pdfFile = new File(dir, fileName + ".PDF");
    240. if (!pdfFile.exists()) {
    241. pdfFile.createNewFile();
    242. } else {
    243. if (fileNameReplace) {
    244. String newFileName = getPDFNewFileName(pdfFile);
    245. pdfFile = new File(newFileName);
    246. pdfFile.createNewFile();
    247. }
    248. }
    249. PdfDocument document = new PdfDocument();
    250. //页对象
    251. PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(
    252. view.getWidth(),
    253. view.getHeight(),
    254. 1)
    255. .create();
    256. // 开始页
    257. PdfDocument.Page page = document.startPage(pageInfo);
    258. //绘制页
    259. Canvas canvas = page.getCanvas();
    260. view.draw(canvas);
    261. //结束页
    262. document.finishPage(page);
    263. //TODO 需要的话,增加更多页
    264. //导出文档
    265. FileOutputStream os = null;
    266. Log.i(TAG, "导出PDF" + " 开始导出,导出路径:" + pdfFile);
    267. os = new FileOutputStream(pdfFile);
    268. document.writeTo(os);
    269. os.close();
    270. Log.i(TAG, "导出PDF" + " 导出成功");
    271. document.close();
    272. return true;
    273. } catch (IOException e) {
    274. // TODO Auto-generated catch block
    275. e.printStackTrace();
    276. return false;
    277. }
    278. }
    279. private static String getXlsxNewFileName(File file) {
    280. if (file.exists()) {
    281. String newPath = file.getPath().substring(0, file.getPath().length() - 5) + "(1).xlsx";
    282. return getXlsxNewFileName(new File(newPath));
    283. } else {
    284. return file.getPath();
    285. }
    286. }
    287. private static String getPDFNewFileName(File file) {
    288. if (file.exists()) {
    289. String newPath = file.getPath().substring(0, file.getPath().length() - 4) + "(1).PDF";
    290. return getPDFNewFileName(new File(newPath));
    291. } else {
    292. return file.getPath();
    293. }
    294. }
    295. static class DeviceInfo {
    296. private String row;//行
    297. private String deviceId;//设备id
    298. private String phoneBrand;//手机品牌
    299. private String latestLocation;//最新位置
    300. private String changeSum;//换机换卡次数
    301. private String installAppSum;//应用安装数量
    302. private String uninstallAppSum;//卸载应用次数
    303. private String violationAppSum;//违规app个数
    304. public DeviceInfo() {
    305. }
    306. public String getRow() {
    307. return row;
    308. }
    309. public void setRow(String row) {
    310. this.row = row;
    311. }
    312. public String getDeviceId() {
    313. return deviceId;
    314. }
    315. public void setDeviceId(String deviceId) {
    316. this.deviceId = deviceId;
    317. }
    318. public String getPhoneBrand() {
    319. return phoneBrand;
    320. }
    321. public void setPhoneBrand(String phoneBrand) {
    322. this.phoneBrand = phoneBrand;
    323. }
    324. public String getLatestLocation() {
    325. return latestLocation;
    326. }
    327. public void setLatestLocation(String latestLocation) {
    328. this.latestLocation = latestLocation;
    329. }
    330. public String getChangeSum() {
    331. return changeSum;
    332. }
    333. public void setChangeSum(String changeSum) {
    334. this.changeSum = changeSum;
    335. }
    336. public String getInstallAppSum() {
    337. return installAppSum;
    338. }
    339. public void setInstallAppSum(String installAppSum) {
    340. this.installAppSum = installAppSum;
    341. }
    342. public String getUninstallAppSum() {
    343. return uninstallAppSum;
    344. }
    345. public void setUninstallAppSum(String uninstallAppSum) {
    346. this.uninstallAppSum = uninstallAppSum;
    347. }
    348. public String getViolationAppSum() {
    349. return violationAppSum;
    350. }
    351. public void setViolationAppSum(String violationAppSum) {
    352. this.violationAppSum = violationAppSum;
    353. }
    354. }
    355. }

    2.导出 xls   需要异步调用

    1. 核心代码:
    2. boolean isSuccess = SheetHelper.exportExcel(title, deviceInfos, "应用痕迹导出文件夹", "导出测试", MainActivity.this, true);
    3. 示例:
    4. List deviceInfos = new ArrayList<>();
    5. for (int i = 0; i < 20; i++) {
    6. SheetHelper.DeviceInfo deviceInfo = new SheetHelper.DeviceInfo();
    7. deviceInfo.setRow(String.valueOf(i + 1));//序号
    8. deviceInfo.setDeviceId("1531359236" + i);//设备id
    9. deviceInfo.setPhoneBrand("华为" + i);//手机品牌
    10. deviceInfo.setLatestLocation("北京" + i);//最新位置
    11. deviceInfo.setChangeSum(String.valueOf(i));//换机换卡次数
    12. deviceInfo.setInstallAppSum(String.valueOf(i));//应用安装数量
    13. deviceInfo.setUninstallAppSum(String.valueOf(i));//卸载应用次数
    14. deviceInfo.setViolationAppSum(String.valueOf(i));//违规app个数
    15. deviceInfos.add(deviceInfo);
    16. }
    17. try {
    18. String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    19. int permission = ActivityCompat.checkSelfPermission(MainActivity.this, "android.permission.WRITE_EXTERNAL_STORAGE");
    20. if (permission != PackageManager.PERMISSION_GRANTED) {
    21. ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_CODE);
    22. } else {
    23. // boolean isSuccess = SheetHelper.exportExcel(phonebillExpressBeans, "应用痕迹导出文件夹", "导出测试", MainActivity.this);
    24. String[] title = {"序号", "设备号", "手机品牌", "最新位置", "换机换卡次数", "应用安装数量", "卸载应用次数", "违规app个数"};
    25. boolean isSuccess = SheetHelper.exportExcel(title, deviceInfos, "应用痕迹导出文件夹", "导出测试", MainActivity.this, true);
    26. runOnUiThread(new Runnable() {
    27. @Override
    28. public void run() {
    29. if (isSuccess) {
    30. Toast.makeText(MainActivity.this, "导出成功", Toast.LENGTH_SHORT).show();
    31. } else {
    32. Toast.makeText(MainActivity.this, "导出失败", Toast.LENGTH_SHORT).show();
    33. }
    34. }
    35. });
    36. }
    37. } catch (Exception e) {
    38. e.printStackTrace();
    39. }
    40. }
    41. }).start();

    3.导入  需要异步调用

    1. 首先调用系统文件管理器
    2. Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    3. intent.setType("*/*");//设置类型,我这里是任意类型,任意后缀的可以这样写。
    4. intent.addCategory(Intent.CATEGORY_OPENABLE);
    5. startActivityForResult(intent, 1000);
    6. 接受管理器选中的文件
    7. @Override
    8. protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    9. super.onActivityResult(requestCode, resultCode, data);
    10. try {
    11. if (resultCode == Activity.RESULT_OK && requestCode == 1000) {
    12. Uri uri = data.getData();//得到uri,后面就是将uri转化成file的过程。
    13. String absolutePath = FileChooseUtil.uriToPath(this, uri);
    14. Log.d("选择了文件", "文件路径:" + absolutePath);
    15. new Thread(new Runnable() {
    16. @Override
    17. public void run() {
    18. List strings = SheetHelper.readExcel(absolutePath);
    19. runOnUiThread(new Runnable() {
    20. @Override
    21. public void run() {
    22. if (strings != null) {
    23. String str = "";
    24. for (String string : strings) {
    25. String[] split = string.split("&&");
    26. for (String s : split) {
    27. Log.i("拿到数据", s);
    28. str += s;
    29. }
    30. str += "\n";
    31. }
    32. mTv_content.setText(str);
    33. Toast.makeText(MainActivity.this, "导入成功", Toast.LENGTH_SHORT).show();
    34. } else {
    35. Toast.makeText(MainActivity.this, "导入失败", Toast.LENGTH_SHORT).show();
    36. }
    37. }
    38. });
    39. }
    40. }).start();
    41. }
    42. } catch (Exception e) {
    43. Toast.makeText(MainActivity.this, "导入异常", Toast.LENGTH_SHORT).show();
    44. e.printStackTrace();
    45. }
    46. }

    产考:

    Android 系统文件浏览器_钟情短发姑娘的博客-CSDN博客

    4.注意:

    需要读写权限

    
    

    高版本动态申请权限

    String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    int permission = ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE");
    if (permission != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, 1);
    } else {
    //logic
    }

    Android 10  有私密文件策略。解决:

    res下新建xml文件夹,新建文件file_paths,文件内容如下

    
        
            
            
    
            
    
            
    
            
            
        
    

    manifest  application 注册fileprovider

    
        
    

    sdk 29以上 允许根目录新建文件

    application 加上

    android:requestLegacyExternalStorage="true"
  • 相关阅读:
    微服务模式:服务发现模式
    React项目中Antd组件库 Tab选项卡 defaultActiveKey 不生效解决方案
    自动化运维管理工具 Ansible
    京东API接口大全
    Docker学习
    elasticsearch bucket 之rare terms聚合
    医院患者挂号app(IDEA,SpringBoot,SSM,MySQL)+全套视频教程
    读书笔记——C++高性能编程(六)
    神经网络(十七)RCNN及其变体的概述
    pycharm中出现这个的原因是什么,如何解决?
  • 原文地址:https://blog.csdn.net/qq_36488374/article/details/126956375