Android导出文件首次写入正常后续输出Null 数据库重访问内容错误
根因分析
- Cursor资源泄漏:代码中查询数据库得到的
cDeliveryTable游标使用后未调用close()释放,多次调用后会触发Android游标数上限,后续查询返回的游标无法正常遍历数据,写入循环不会执行,最终文件内容为空。 - 目录未预创建:
archive参数为true时,仅拼接了txt文件路径,未提前判断父目录是否存在,也未调用mkdirs()创建目录。首次调用时如果父目录恰好存在可写入成功,后续如果目录被系统清理、权限变更,会导致文件创建失败,无内容写入。 - CustDeliveryTable实例化异常:构造方法仅传入
_id查询数据,未校验查询结果是否有效。如果后续调用时对应_id的记录被删除、全局数据库实例GlobalVars.db状态异常(比如被意外关闭、处于未提交事务中),会导致实例的Name/Address/Number属性全部为null,最终CargoStr()返回null;null;null这类异常内容。 - 全局变量状态被篡改:
GlobalVars.DirectoryPath、GlobalVars.DirectoryFileName这类全局配置如果在首次调用后被业务逻辑修改,会导致后续写入的文件路径和预期不一致,读取旧路径文件时自然内容不符合预期。
修复建议
- 用try-with-resources自动管理Cursor、BufferedWriter等可关闭资源,避免手动释放遗漏
- 写文件前先判断父目录是否存在,不存在则调用
mkdirs()创建 - 给
CustDeliveryTable构造方法加查询结果校验,取不到有效数据时抛出明确异常或打印错误日志,避免空属性静默拼接 - 避免直接用全局变量存储数据库实例、路径配置,可加final修饰防止被意外修改
关联代码
public static String ExportTofile (boolean archive) throws Exception { if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { throw new Exception("Нет доступа к SDCard"); } File sdFile; File sdPath = Environment.getExternalStorageDirectory(); sdPath = new File(sdPath.getAbsolutePath() + "/" + GlobalVars.DirectoryPath); if (archive) { sdFile = new File(sdPath +".txt"); } else sdFile = new File(GlobalVars.AppPathData(), GlobalVars.DirectoryFileName); Cursor cDeliveryTable; try { BufferedWriter br = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(sdFile), "windows-1251")); Log.d(GlobalVars.LOG_TAG, "ExpotToFile: " + sdFile.getAbsolutePath()); cDeliveryTable = GlobalVars.db.rawQuery("select * from CustDeliveryTable order by _id", null); cDeliveryTable.moveToFirst(); while (!cDeliveryTable.isAfterLast()) { CustDeliveryTable st = new CustDeliveryTable(cDeliveryTable.getLong(cDeliveryTable.getColumnIndex("_id"))); br.write(st.CargoStr() + "\r\n"); cDeliveryTable.moveToNext(); } br.close(); } catch (FileNotFoundException e) { e.printStackTrace(); throw e; } catch (IOException e) { e.printStackTrace(); throw e; } return sdFile.getAbsolutePath(); } public String CargoStr() { String sLine; sLine = this.Name + ";" + this.Address + ";" + this.Number + ";"; return sLine.substring(0, sLine.length() - 1); }
现象说明
- 首次写入结果:正常输出结构化业务数据
- 后续写入结果:内容为空或全为null
内容的提问来源于stack exchange,提问作者Darsi
相关产品推荐
相关产品推荐

