如何在 JS 中从 ArrayBuffer 写入文件

Posted

技术标签:

【中文标题】如何在 JS 中从 ArrayBuffer 写入文件【英文标题】:How to write a file from an ArrayBuffer in JS 【发布时间】:2015-10-13 09:33:23 【问题描述】:

我正在尝试为 Meteor 框架编写文件上传器。 原理是将客户端上的文件从一个ArrayBuffer中拆分成4096位的小包,通过Meteor.method发送到服务器。

下面的简化代码是客户端向服务器发送块的部分,它会重复直到offset达到data.byteLength :

// data is an ArrayBuffer
var total = data.byteLength;
var offset = 0;

var upload = function() 
  var length = 4096; // chunk size

  // adjust the last chunk size
  if (offset + length > total) 
     length = total - offset;
  

  // I am using Uint8Array to create the chunk
  // because it can be passed to the Meteor.method natively
  var chunk = new Uint8Array(data, offset, length);

  if (offset < total) 
     // Send the chunk to the server and tell it what file to append to
     Meteor.call('uploadFileData', fileId, chunk, function (err, length) 
        if (!err) 
          offset += length;
          upload();
        
     
  
;
upload(); // start uploading

下面的简化代码是服务器上接收块并将其写入文件系统的部分:

var fs = Npm.require('fs');
var Future = Npm.require('fibers/future');

Meteor.methods(
  uploadFileData: function(fileId, chunk) 
    var fut = new Future();
    var path = '/uploads/' + fileId;

    // I tried that with no success
    chunk = String.fromCharCode.apply(null, chunk);

    // how to write the chunk that is an Uint8Array to the disk ?
    fs.appendFile(path, chunk, 'binary', function (err) 
      if (err) 
        fut.throw(err);
       else 
        fut.return(chunk.length);
      
    );
    return fut.wait();
  
);

我未能将有效文件写入磁盘,实际上文件已保存但我无法打开它,当我在文本编辑器中看到内容时,它类似于原始文件(例如 jpg)但有些字符不同,我认为这可能是编码问题,因为文件大小不一样,但我不知道如何解决...

【问题讨论】:

你能改为传递一个 blob 吗?它们通常作为缓冲区出现在​​节点中,由 fs.AppendFile() 处理。 @dandavis 其实你给了我一半的答案,毕竟解决方案很简单,谢谢! 【参考方案1】:

以Karl.S answer 为基础,这对我有用,在任何框架之外:

fs.appendFileSync(outfile, Buffer.from(arrayBuffer));

【讨论】:

不推荐使用新缓冲区。请改用 Buffer.from(arrayBuffer)。 不推荐使用同步版本的 I/O 函数,因为它会阻塞事件循环,除非你有理由这样做。【参考方案2】:

保存文件就像使用 Uint8Array 对象创建一个新的缓冲区一样简单:

// chunk is the Uint8Array object
fs.appendFile(path, Buffer.from(chunk), function (err) 
    if (err) 
      fut.throw(err);
     else 
      fut.return(chunk.length);
    
);

【讨论】:

new Buffer(chunk) 不推荐使用 Buffer.from(chunk)【参考方案3】:

只是想在较新的 Meteor 中添加这一点,您可以使用 async/await 避免一些回调地狱。 Await 也会抛出错误并将错误推送到客户端

Meteor.methods(
  uploadFileData: async function(file_id, chunk) 
    var path = 'somepath/' + file_id; // be careful with this, make sure to sanitize file_id
    await fs.appendFile(path, new Buffer(chunk));
    return chunk.length;
  
);

【讨论】:

以上是关于如何在 JS 中从 ArrayBuffer 写入文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中从 JavaScript 调用 Python 函数?

哪位朋友使用过js中的ArrayBuffer,请教一个转换问题

如何在 Flutter 中从 firebase 存储读取和写入文本文件?

如何在 Javascript/Node 中从 blob 写入 .wav 文件

在 Dataflow 中从 BigQuery 写入云存储时如何设置文件大小而不是分片数

如何通过Websocket将arraybuffer作为二进制发送?