300MB+文件Base64加密时应用报错,字节处理代码崩溃求助
大文件Base64加密崩溃问题修复方案
问题根源分析
- 内存溢出OOM:你用
mInputStream.available()创建字节数组,这个方法返回的是当前输入流中可立即读取的字节数,并非文件总大小。300MB的文件会尝试分配超大内存数组,直接撑爆内存导致崩溃。 - 文件读取不完整:while循环里的
break直接跳出循环,只读取了一次数据就停止,加密后的文件只有部分内容,自然无法正常打开。 - 子线程调用UI操作:
Toast.makeText在doInBackground子线程中调用,子线程不能直接操作UI,会引发异常。 - 流关闭不规范:手动关闭流容易在异常时遗漏,导致资源泄漏。
修复后的代码
private void encrypt(final File file) { new AsyncTask<Void, Void, Boolean>() { private String errorMsg; @Override protected Boolean doInBackground(Void[] p) { File newFile = new File(file.getAbsolutePath() + ".enc.txt"); // 用固定大小缓冲区,避免内存占用过大 byte[] buffer = new byte[8192]; // 8KB缓冲区,可按需调整 int len; try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file)); OutputStream outputStream = new FileOutputStream(newFile)) { while ((len = inputStream.read(buffer)) != -1) { byte[] encodedBytes = Base64.encode(buffer, 0, len, Base64.DEFAULT); outputStream.write(encodedBytes); } outputStream.flush(); return true; } catch (Exception e) { errorMsg = e.toString(); return false; } } @Override protected void onPostExecute(Boolean success) { if (success) { Toast.makeText(MainActivity.this, "加密成功", Toast.LENGTH_LONG).show(); } else { Toast.makeText(MainActivity.this, "加密失败:" + errorMsg, Toast.LENGTH_LONG).show(); } } }.execute(); }
关键修改说明
- 固定大小缓冲区:用8KB的小缓冲区循环读取文件,避免一次性加载大文件到内存,彻底解决OOM问题。
- 修复循环逻辑:去掉多余的
break,用while ((len = inputStream.read(buffer)) != -1)判断文件是否读取完毕,确保完整读取整个文件。 - UI操作移至主线程:错误提示和成功提示都放在
onPostExecute(主线程执行)中,避免子线程操作UI的异常。 - try-with-resources自动关流:Java 7+语法,自动关闭实现了
AutoCloseable的流,无需手动调用close,避免资源泄漏。 - 优化命名规范:调整变量名符合Java命名习惯,提升代码可读性。
内容的提问来源于stack exchange,提问作者sw team
相关产品推荐
相关产品推荐

