Android端通过Storage Access Framework保存OneDrive文件损坏解决方案求助
问题根因
该问题属于OneDrive的Storage Access Framework(SAF)实现缺陷:当通过openOutputStream(Uri)打开文件写入流时,OneDrive不会自动截断原文件末尾超出新写入内容长度的部分。如果新内容体积小于原文件,原文件末尾的多余内容就会残留,最终出现你观察到的内容错误。该逻辑和本地存储、其他云盘的SAF实现不一致。
修复方案
不需要单独适配OneDrive,修改写入逻辑即可全局兼容所有存储提供商:
方案1(推荐,适配Android 7.0+)
打开输出流时显式指定写入+截断模式"wt",会直接清空原文件全部内容后再写入新内容,修改保存逻辑的代码如下:
binding.buttonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (OpenFileUri == null) return; // 第二个参数传入"wt"表示w写入,t截断原有内容 try (OutputStream mOutputStream = getActivity().getContentResolver().openOutputStream(OpenFileUri, "wt")) { try (PrintWriter p = new PrintWriter(mOutputStream)) { String t = binding.editBox.getText().toString(); p.print(t); // 注意这里改成print不要用println,避免额外多写一个换行符 } catch (Exception e1) { e1.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } });
注:原代码中使用
println(t)会额外在内容末尾加一个换行符,和用户输入的原始内容不一致,建议替换为print(t)。
方案2(兼容Android 7.0以下版本)
如果需要支持更低系统版本,可以写完内容后手动截断文件到新内容的长度:
binding.buttonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (OpenFileUri == null) return; String content = binding.editBox.getText().toString(); byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8); try (OutputStream mOutputStream = getActivity().getContentResolver().openOutputStream(OpenFileUri)) { mOutputStream.write(contentBytes); mOutputStream.flush(); // 手动截断文件到新内容的长度 try (ParcelFileDescriptor pfd = getActivity().getContentResolver().openFileDescriptor(OpenFileUri, "rw")) { if (pfd != null) { Os.ftruncate(pfd.getFileDescriptor(), contentBytes.length); } } catch (Exception e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } });
内容的提问来源于stack exchange,提问作者PEK
相关产品推荐
相关产品推荐

