Получение массива байтов через input type = file

var profileImage = fileInputInByteArray;

$.ajax({
  url: 'abc.com/',
  type: 'POST',
  dataType: 'json',
  data: {
     // Other data
     ProfileImage: profileimage
     // Other data
  },
  success: {
  }
})

// Code in WebAPI
[HttpPost]
public HttpResponseMessage UpdateProfile([FromUri]UpdateProfileModel response) {
  //...
  return response;
}

public class UpdateProfileModel {
  // ...
  public byte[] ProfileImage {get ;set; }
  // ...
}
<input type="file" id="inputFile" />

Я использую вызов ajax для post Byte [] значение типа ввода = файл ввода в веб-api, который получает в формате byte []. Тем не менее, я испытываю трудности с получением массива байтов. Я ожидаю, что мы можем получить массив байтов через файловый API.

Примечание: мне нужно сначала сохранить массив байтов в переменной, прежде чем проходить через ajax call

3 ответов


[Edit]

как отмечено в комментариях выше, в то время как все еще на некоторых реализациях UA, readAsBinaryString метод не сделал свой путь к спецификациям и не должен использоваться в производстве. Вместо этого используйте readAsArrayBuffer и петля через это buffer чтобы вернуть двоичную строку:

document.querySelector('input').addEventListener('change', function() {

  var reader = new FileReader();
  reader.onload = function() {

    var arrayBuffer = this.result,
      array = new Uint8Array(arrayBuffer),
      binaryString = String.fromCharCode.apply(null, array);

    console.log(binaryString);

  }
  reader.readAsArrayBuffer(this.files[0]);

}, false);
<input type="file" />
<div id="result"></div>

для более надежного способа преобразования arrayBuffer в двоичную строку вы можете обратиться к этот ответ.


[ответ] (изменен)

да, API файла предоставляет способ конвертировать ваш файл в <input type="file"/> в двоичную строку, благодаря FileReader


$(document).ready(function(){
    (function (document) {
  var input = document.getElementById("files"),
  output = document.getElementById("result"),
  fileData; // We need fileData to be visible to getBuffer.

  // Eventhandler for file input. 
  function openfile(evt) {
    var files = input.files;
    // Pass the file to the blob, not the input[0].
    fileData = new Blob([files[0]]);
    // Pass getBuffer to promise.
    var promise = new Promise(getBuffer);
    // Wait for promise to be resolved, or log error.
    promise.then(function(data) {
      // Here you can pass the bytes to another function.
      output.innerHTML = data.toString();
      console.log(data);
    }).catch(function(err) {
      console.log('Error: ',err);
    });
  }

  /* 
    Create a function which will be passed to the promise
    and resolve it when FileReader has finished loading the file.
  */
  function getBuffer(resolve) {
    var reader = new FileReader();
    reader.readAsArrayBuffer(fileData);
    reader.onload = function() {
      var arrayBuffer = reader.result
      var bytes = new Uint8Array(arrayBuffer);
      resolve(bytes);
    }
  }

  // Eventlistener for file input.
  input.addEventListener('change', openfile, false);
}(document));
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>

<input type="file" id="files"/>
<div id="result"></div>
</body>
</html>

это длинный пост, но я устал от всех этих примеров, которые не работали для меня, потому что они использовали объекты обещания или странствующий this это имеет другое значение, когда вы используете Reactjs. Моя реализация использовала DropZone с reactjs, и я получил байты, используя фреймворк, подобный тому, что опубликовано на этом следующем сайте, когда ничто другое выше не будет работать:https://www.mokuji.me/article/drop-upload-tutorial-1 . Было 2 ключа, для меня:

  1. вы должны получить байты из объекта события, используя и во время функции onload FileReader.
  2. я пробовал различные комбинации, но, в конце концов, мы решили:

    const bytes = e.target.result.split('base64,')[1];

здесь e - это событие. Реагируют требует const, вы могли бы использовать var в обычном Javascript. Но это дало мне строку байта в кодировке base64.

поэтому я просто собираюсь включить применимые строки для интеграции этого, как если бы вы использовали React, потому что именно так я его строил, но попробуйте также обобщить это и добавить комментарии, когда это необходимо, чтобы сделать его применимым к реализации vanilla Javascript - предупредил, что я не использовал его так в такой конструкции, чтобы проверить его.

это будут ваши привязки вверху, в вашем конструкторе, в рамках React (не относящиеся к реализации Javascript vanilla):

this.uploadFile = this.uploadFile.bind(this);
this.processFile = this.processFile.bind(this);
this.errorHandler = this.errorHandler.bind(this);
this.progressHandler = this.progressHandler.bind(this);

и ты бы ... --15--> в вашем элементе DropZone. Если вы делали это без React, это эквивалентно добавлению обработчика событий onclick, который вы хотите запустить при нажатии кнопки" Загрузить файл".

<button onclick="uploadFile(event);" value="Upload File" />

затем функции (соответствующие строки... Я оставлю свой сброс индикатора прогресса загрузки и т. д.):

uploadFile(event){
    // This is for React, only
    this.setState({
      files: event,
    });
    console.log('File count: ' + this.state.files.length);

    // You might check that the "event" has a file & assign it like this 
    // in vanilla Javascript:
    // var files = event.target.files;
    // if (!files && files.length > 0)
    //     files = (event.dataTransfer ? event.dataTransfer.files : 
    //            event.originalEvent.dataTransfer.files);

    // You cannot use "files" as a variable in React, however:
    const in_files = this.state.files;

    // iterate, if files length > 0
    if (in_files.length > 0) {
      for (let i = 0; i < in_files.length; i++) {
      // use this, instead, for vanilla JS:
      // for (var i = 0; i < files.length; i++) {
        const a = i + 1;
        console.log('in loop, pass: ' + a);
        const f = in_files[i];  // or just files[i] in vanilla JS

        const reader = new FileReader();
        reader.onerror = this.errorHandler;
        reader.onprogress = this.progressHandler;
        reader.onload = this.processFile(f);
        reader.readAsDataURL(f);
      }      
   }
}

был этот вопрос по этому синтаксису, для vanilla JS, о том, как получить этот файл объект:

JavaScript / HTML5 / jQuery Drag-And-Drop Upload - "Uncaught TypeError: не удается прочитать свойства "файлы " неопределенного"

обратите внимание, что DropZone React уже поместит объект File в this.state.files для вас, пока вы добавляете files: [], на this.state = { .... } в конструкторе. Я добавил синтаксис из ответа на этот пост о том, как к вашему файловому объекту. Он должен работать, или есть другие сообщения, которые могут помочь. Но все, что Q / A сказал мне, было как получить File объект, а не сами данные blob. А даже если и так ...--20--> как в ответе Себу, который не включал readAsArrayBuffer в любом случае.

вам придется иметь другие функции, которые идут вместе с этой конструкцией - один для обработки onerror, для onprogress (оба показаны ниже), а затем основной,onload, что на самом деле делает работу один раз метод на reader вызывается в последней строке. В основном вы проходите свой event.dataTransfer.files[0] прямо в onload функция, из того, что я могу сказать.

так onload метод вызывает my