uni-app 【报Bug】new plus.io.FileReader > reader.readAsDataURL(file)转码后输出不完整(包括图片,音频)

uni-app 【报Bug】new plus.io.FileReader > reader.readAsDataURL(file)转码后输出不完整(包括图片,音频)

操作步骤:

  • 通过5+获取指定文件并转码。

预期结果:

  • 转码后的base64能完整演示

实际结果:

  • 转码后的base64 能演示,但有出现断层。如音频mp3文件拿到base64后播放时出现卡顿,少帧,图片拿到base64后演示不完整。

bug描述:

  • 按照HTML5+ IO操作获取文件信息后通过new plus.io.FileReader() > reader.readAsDataURL(file) 编码后信息不完整,已测试图片,音频文件

Image


更多关于uni-app 【报Bug】new plus.io.FileReader > reader.readAsDataURL(file)转码后输出不完整(包括图片,音频)的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

哪个平台?

更多关于uni-app 【报Bug】new plus.io.FileReader > reader.readAsDataURL(file)转码后输出不完整(包括图片,音频)的实战教程也可以访问 https://www.itying.com/category-93-b0.html


回复 1***@qq.com: 。。。问题是Android 还是 iOS ,HX使用的版本是多少,具体哪个机型,还是所有机型 【正确报bug的姿势】https://ask.dcloud.net.cn/article/38139

这是转码后的base64,在电脑上播放失败

用 entry.file 的得到的file对象 不是继承自 blob 与普通的h5 不一致 而且io.fileReader readAsDataURL方法 得到的音频视频 无法播放

请问解决了吗?

根据你提供的信息,这确实是uni-app/5+环境中一个已知的文件读取问题。plus.io.FileReaderreadAsDataURL方法在处理较大文件或特定格式时,确实可能出现数据截断或编码不完整的情况。

主要原因分析:

  1. 5+底层实现限制plus.io.FileReader是HTML5+规范中的API,其底层实现(特别是在Android平台)对一次性读取大文件到内存并转换为Base64可能存在缓冲区限制或编码处理缺陷。
  2. Base64编码内存开销:Base64编码会使数据体积增加约33%。对于较大的音频或图片文件,在内存中进行完整的转换与拼接可能出现问题。
  3. 异步处理机制不完善:该API在文件读取与编码完成的回调触发时,数据可能尚未完全准备就绪。

建议的解决方案:

方案一:使用分片读取(推荐用于大文件) 对于大文件,避免一次性读取。可以使用plus.io.Fileslice方法分片读取后,手动拼接Base64。

function readFileAsDataURL(filePath) {
  return new Promise((resolve, reject) => {
    plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
      entry.file((file) => {
        const chunkSize = 1024 * 512; // 512KB分片
        const chunks = Math.ceil(file.size / chunkSize);
        let currentChunk = 0;
        let base64Data = '';

        function readChunk() {
          const start = currentChunk * chunkSize;
          const end = Math.min(start + chunkSize, file.size);
          const blob = file.slice(start, end);
          
          const reader = new plus.io.FileReader();
          reader.onload = (e) => {
            // 移除dataURL前缀,只保留Base64数据
            const chunkData = e.target.result.split(',')[1];
            base64Data += chunkData;
            currentChunk++;
            
            if (currentChunk < chunks) {
              readChunk();
            } else {
              resolve(`data:${file.type};base64,${base64Data}`);
            }
          };
          reader.onerror = reject;
          reader.readAsDataURL(blob);
        }
        
        readChunk();
      }, reject);
    }, reject);
  });
}

方案二:使用ArrayBuffer手动转换 先读取为ArrayBuffer,再手动转换为Base64,避免API内部转换问题:

function fileToBase64(filePath) {
  return new Promise((resolve, reject) => {
    plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
      entry.file((file) => {
        const reader = new plus.io.FileReader();
        reader.onload = (e) => {
          const arrayBuffer = e.target.result;
          const base64 = btoa(
            new Uint8Array(arrayBuffer).reduce(
              (data, byte) => data + String.fromCharCode(byte),
              ''
            )
          );
          resolve(`data:${file.type};base64,${base64}`);
        };
        reader.onerror = reject;
        reader.readAsArrayBuffer(file);
      }, reject);
    }, reject);
  });
}

方案三:使用uni-app API替代 如果文件在项目目录中,优先使用uni-app的API:

// 对于项目静态资源
const base64 = await uni.getFileSystemManager().readFileSync(filePath, 'base64');

// 对于选择文件
uni.chooseFile({
  success: (res) => {
    const tempFilePath = res.tempFilePaths[0];
    const base64 = await uni.getFileSystemManager().readFileSync(tempFilePath, 'base64');
  }
});

临时规避方案: 对于小文件,可以尝试先转换为Blob URL直接使用,避免Base64转换:

const objectURL = URL.createObjectURL(file);
// 使用objectURL作为音视频源或图片源
回到顶部