0

I want to read a slice of a file using a FileReader, and then send it to a server. This is what I have so far:

const createReader = onRead => {
  const reader = new FileReader();
  reader.onloadend = function(evt) {
    if (evt.target.readyState === FileReader.DONE) {
      const arrayBuffer = evt.target.result;
      const bytes = new Uint8Array(arrayBuffer);
      console.log("BYTES: ", bytes);
      onRead(evt.target.result);
    }
  };
  return reader;
};

const reader = createReader(fileSlice => {
  console.log("BYTES: ", fileSlice);
  // send to server
});
reader.readAsArrayBuffer(blob);

Here's what it printed when I uploaded a simple .txt file:

However, it returns an array, and I'm not sure how to convert this into a format that I can send over to my server through HTTP.

enter image description here

Does anyone know what I need to do in order to convert that byte array into a format that I can eventually turn back into the original file?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
bigpotato
  • 26,262
  • 56
  • 178
  • 334

2 Answers2

2

You can POST the Uint8Array to the server. You can convert a Uint8Array to a string using TextDecoder

guest271314
  • 1
  • 15
  • 104
  • 177
  • Would it be possible to convert it to a string somehow? I eventually want to convert / reassemble the bytes back to a file. – bigpotato Jan 28 '18 at 20:00
  • Yes, you can use `TextDecoder` `.decode()` method. What is the `type` of the original `File` object, `"text/plain"`? – guest271314 Jan 28 '18 at 20:00
  • wow perfect! thanks!! well the file is going to be anything the user uploads. will that change anything? – bigpotato Jan 28 '18 at 20:02
  • @Edmund Yes. Media files have metadata at arbitrary locations within the file – guest271314 Jan 28 '18 at 20:03
  • Dang it. So is there a solution to upload any file regardless of the type? – bigpotato Jan 28 '18 at 20:04
  • See [ts-ebml](https://github.com/legokichi/ts-ebml), [How to use “segments” mode at SourceBuffer of MediaSource to render same result at Chomium, Chorme and Firefox?](https://stackoverflow.com/questions/46379009/how-to-use-segments-mode-at-sourcebuffer-of-mediasource-to-render-same-result) – guest271314 Jan 28 '18 at 20:06
  • The original Question mentions "slice of a file". What are you trying to achieve? Are you trying to stream a file to the server? – guest271314 Jan 28 '18 at 20:09
  • Sorry about that, I'm actually splitting the file into slices and then trying to reassemble them together. So given each "file slice", can I reassemble them using the TextDecoder / Encoder? – bigpotato Jan 28 '18 at 20:10
  • What is the purpose of splitting the file into slices only to reassemble to file? – guest271314 Jan 28 '18 at 20:11
  • The file is going to be uploaded in pieces, and downloaded in pieces too – bigpotato Jan 28 '18 at 20:11
  • As long as the entire file is re-assembled in the same order there should not be an issue, see also [Node.js: splitting stream content for n-parts](https://stackoverflow.com/questions/43631320/node-js-splitting-stream-content-for-n-parts) – guest271314 Jan 28 '18 at 20:13
0

Read the file chunk, make sure you use readAsArrayBuffer

var readChunck = function (offset, length, file) {
  var r = new FileReader();
  var chunck = file.slice(offset, length + offset);
  r.onload = readEventHandler;
  r.readAsArrayBuffer(chunck)
}

In the vent handler (readEventHandler), convert the ArrayBuffer to Base64String and post to the server:

var readEventHandler = function (evt) {

  var data = {
    data: self.arrayBufferToBase64String(evt.target.result)
  }

  self.httpClient.post(url, data)
    .subscribe(data=> {
     // do stuff 
    });

  // ...
}

And here is the conversion function:

private arrayBufferToBase64String(buffer: ArrayBuffer) {
  let binaryString = ''
  var bytes = new Uint8Array(buffer);
  for (var i = 0; i < bytes.byteLength; i++) {
    binaryString += String.fromCharCode(bytes[i]);
  }

  return window.btoa(binaryString);
}

On the server side (ASP Core Web API in this case):

[HttpPost, DisableRequestSizeLimit]
[Route("{blobId}/uploads/{uploadId}/parts/{partNumber}")]
public async Task<IActionResult> UploadPart(
  [FromRoute] string blobId,
  [FromRoute] string uploadId,
  [FromRoute] int partNumber,
  [FromBody] FilePartModel part)
  {
    if (!GuidValidator.IsValidGuid(blobId)) throw new ArgumentException("Invalid BLOB Id");
    if (!GuidValidator.IsValidGuid(uploadId)) throw new ArgumentException("Invalid Upload Id");

    var bytes = Convert.FromBase64String(part.Data);
    using (var stream = new MemoryStream(bytes))
    {
      var etag = await _blobsService.UploadPartAsync(Guid.Parse(blobId), Guid.Parse(uploadId), partNumber, stream);

      return Ok(new FilePart { ETag = etag, PartNumber = partNumber });
    }
}

FilePartModel is just a simple model class:

public class FilePartModel
{
    public string Data { get; set; }
}
Assaf S.
  • 4,676
  • 2
  • 22
  • 18