【问题标题】:file.slice fails second timefile.slice 第二次失败
【发布时间】:2020-10-02 10:01:44
【问题描述】:

我正在尝试制作一个(前端)Javascript,它能够复制非常大的文件(即从文件输入元素中读取它们并使用 StreamSaver.js“下载”它们)。

这是实际代码:

<html>
<header>
    <title>File copying</title>
</header>
<body>
<script src="https://cdn.jsdelivr.net/npm/web-streams-polyfill@2.0.2/dist/ponyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/streamsaver@2.0.3/StreamSaver.min.js"></script>

<script type="text/javascript">
    const streamSaver = window.streamSaver;

    async function copyFile() {
        const fileInput = document.getElementById("fileInput");
        const file = fileInput.files[0];
        if (!file) {
            alert('select a (large) file');
            return;
        }
        const newName = file.name + " - Copy";
        let remaining = file.size;
        let written = 0;
        const chunkSize = 1048576; // 1MB

        const writeStream = streamSaver.createWriteStream(newName);
        const writer = writeStream.getWriter();

        while (remaining > 0) {
            let readSize = chunkSize > remaining ? remaining : chunkSize;
            let blob = file.slice(written, readSize);
            let aBuff = await blob.arrayBuffer();
            await writer.write(new Uint8Array(aBuff));
            written += readSize;
            remaining -= readSize;
        }
        await writer.close();
    }
</script>
<input type="file" id="fileInput"/>
<button onclick="copyFile()">Copy file</button>
</body>
</html>

似乎在while 的第二个循环中,aBuff 变量值(blob.arrayBuffer)是一个空的ArrayBuffer

我是否以错误的方式读取文件?我的意图是逐块读取(可能很大)文件并对每个块执行某些操作(在这种情况下,只需通过 StreamSaver.js 将其输出到下载文件)。现在的浏览器有什么更好的方法?

【问题讨论】:

    标签: javascript async-await download stream fileapi


    【解决方案1】:

    我会使用 blob.stream()new Response(blob).body 之类的东西来读取文件的所有块,如果需要,还可以读取 TransformStream。但是,如果您需要自定义切片大小或更好的浏览器支持,则可以创建自己的 blob -> readableStream 实用程序

    // Taken from https://www.npmjs.com/package/screw-filereader
    function stream (blob) {
      var position = 0
      var blob = this
    
      return new ReadableStream({
        pull (controller) {
          var chunk = blob.slice(position, position + 1048576)
    
          return chunk.arrayBuffer().then(buffer => {
            position += buffer.byteLength
            var uint8array = new Uint8Array(buffer)
            controller.enqueue(uint8array)
    
            if (position == blob.size)
              controller.close()
          })
        }
      })
    }
    
    stream(blob).pipeTo(writeStream)
    

    通过这种方式,您可以将其通过管道传输到流保护程序,而不是手动编写每个块

    【讨论】:

      猜你喜欢
      • 2013-12-17
      • 2011-03-22
      • 1970-01-01
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 2015-09-02
      • 2014-07-12
      相关资源
      最近更新 更多