web-dev-qa-db-ja.com

JSでArrayBufferからファイルを書き込む方法

Meteorフレームワーク用のファイルアップローダーを作成しようとしています。原則は、Meteor.methodを介してサーバーに送信される4096ビットの小さなパケットのArrayBufferからクライアント上のファイルを分割することです。

以下の簡略化されたコードは、サーバーにチャンクを送信するクライアントの一部であり、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

以下のsimplifiedコードは、チャンクを受信して​​ファイルシステムに書き込むサーバー上の部分です。

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など)に似ていますが、一部の文字が異なります、ファイルサイズが同じではないため、エンコードの問題である可能性がありますが、それを修正する方法がわかりません...

16
Karl.S

ファイルの保存は、Uint8Arrayオブジェクトを使用して新しいバッファーを作成するのと同じくらい簡単でした。

// chunk is the Uint8Array object
fs.appendFile(path, new Buffer(chunk), function (err) {
    if (err) {
      fut.throw(err);
    } else {
      fut.return(chunk.length);
    }
});
18
Karl.S

Karl.S answer に基づいて構築すると、これはフレームワークの外で私にとってはうまくいきました:

fs.appendFileSync(outfile, new Buffer(arrayBuffer));
9
toms

新しい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;
  }
});
1
Alex K