Как преобразовать файл в base64 в JavaScript?

187

Теперь я получаю объект File по этой строке:

file = document.querySelector('#files > input[type="file"]').files[0]

Мне нужно отправить этот файл через json в base 64. Что мне нужно сделать, чтобы преобразовать его в строку base64?

Василий
источник

Ответы:

118

Современный способ ES6 (асинхронный / ожидающий)

const toBase64 = file => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
});

async function Main() {
   const file = document.querySelector('#myfile').files[0];
   console.log(await toBase64(file));
}

Main();

UPD:

Если вы хотите ловить ошибки

async function Main() {
   const file = document.querySelector('#myfile').files[0];
   const result = await toBase64(file).catch(e => Error(e));
   if(result instanceof Error) {
      console.log('Error: ', result.message);
      return;
   }
   //...
}
Дмитрий Васильев
источник
Этот код неверен. Если вы awaitиспользуете функцию, которая возвращает отклоненное обещание, вы не получите сообщение об ошибке, возвращаемое вызовом; это будет брошено, и вам нужно будет поймать его.
Dancrumb
1
Отличный пример использования асинхронных функций и обещаний
Тиаго Фриас
292

Попробуйте решение, используя FileReader класс :

function getBase64(file) {
   var reader = new FileReader();
   reader.readAsDataURL(file);
   reader.onload = function () {
     console.log(reader.result);
   };
   reader.onerror = function (error) {
     console.log('Error: ', error);
   };
}

var file = document.querySelector('#files > input[type="file"]').files[0];
getBase64(file); // prints the base64 string

Обратите внимание, что .files[0]это Fileтип, который является подклассом Blob. Таким образом, он может быть использован с FileReader.
Смотрите полный рабочий пример .

Дмитрий Павлутин
источник
2
подробнее об API FileReader: developer.mozilla.org/en-US/docs/Web/API/FileReader и поддержка браузера: caniuse.com/#feat=filereader
Лукас Лиезис
7
Я попытался использовать return reader.resultиз getBase64()функции (а не использовать console.log(reader.result)), потому что я хочу захватить base64 в качестве переменной (и затем отправить его в Google Apps Script). Я вызвал функцию с:, var my_file_as_base64 = getBase64(file)а затем попытался распечатать на консоли с console.log(my_file_as_base64 )и только что получил undefined. Как правильно назначить base64 переменной?
user1063287
1
Я сделал вопрос из вышеупомянутого комментария, если кто-то может ответить. stackoverflow.com/questions/47195119/...
user1063287
Мне нужно открыть этот файл Base64 в браузере с тем же именем файла, я открываю его с помощью window.open (url, '_blank'), который работает нормально, как я могу дать этому имя файла? пожалуйста помоги.
Munish Sharma
Спасибо! Я думаю, что это не очень хорошо объяснено на developer.mozilla.org/en-US/docs/Web/API/FileReader/…
johey
124

Если вы ищете решение, основанное на обещаниях, то код @ Dmitri, адаптированный для этого:

function getBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
  });
}

var file = document.querySelector('#files > input[type="file"]').files[0];
getBase64(file).then(
  data => console.log(data)
);
joshua.paling
источник
Мне нужно открыть этот файл Base64 в браузере с тем же именем файла, я открываю его с помощью window.open (url, '_blank'), который работает нормально, как я могу дать этому имя файла? пожалуйста помоги.
Munish Sharma
42

Основываясь на ответах Дмитрия Павлутина и joshua.paling, вот расширенная версия, которая извлекает содержимое base64 (удаляет метаданные в начале), а также обеспечивает правильное заполнение .

function getBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => {
      let encoded = reader.result.toString().replace(/^data:(.*,)?/, '');
      if ((encoded.length % 4) > 0) {
        encoded += '='.repeat(4 - (encoded.length % 4));
      }
      resolve(encoded);
    };
    reader.onerror = error => reject(error);
  });
}
Арно П
источник
2
Chrome 69, первая замена - перехват пустого файла, вторая замена - запятая - encoded = reader.result.replace ("data:", "") .replace (/^.*; base64, /, "");
user3333134
Клянусь словом, я действительно скучал по этой коме. Что удивительно, так это то, что это, похоже, совсем не мешало моему бэкэнду, я все еще был в состоянии успешно загружать файлы Excel o_O. Я исправил регулярное выражение, чтобы учесть и ваш случай использования пустого файла. Спасибо.
Арно П
2
У меня есть еще более простая версия resolve(reader.result.replace(/^.*,/, ''));. Поскольку кома ,находится за пределами алфавита base64, мы можем удалить все, что подходит, включая кому. stackoverflow.com/a/13195218/1935128
Джонрид
Хорошо, спасибо за заголовки, хотя в соответствии с регулярным выражением, которое я написал здесь (я должен был поэкспериментировать снова, чтобы быть уверенным), может быть data:, без всякой запятой, поэтому я оставлю эту первую часть как есть. Я обновил ответ соответственно.
Арно П
1
@ArnaudP Ошибка машинописного текста: свойство 'replace' не существует для типа 'string | ArrayBuffer.
Ромель Гомес
12

Функция JavaScript btoa () может использоваться для преобразования данных в строку в кодировке base64

Пранав Маниар
источник
6
btoa работает только со строкой. Как использовать это с файлом?
Василий
10
сначала вам нужно будет прочитать файл, а затем передать его этой функции. Что-то вроде jsfiddle.net/eliseosoto/JHQnk
Pranav Maniar
1
@PranavManiar Ваша скрипка больше не работает. Вы можете обновить ссылку?
Дан
5

Вот пара функций, которые я написал, чтобы получить файл в формате json, который можно легко передать:

    //takes an array of JavaScript File objects
    function getFiles(files) {
        return Promise.all(files.map(file => getFile(file)));
    }

    //take a single JavaScript File object
    function getFile(file) {
        var reader = new FileReader();
        return new Promise((resolve, reject) => {
            reader.onerror = () => { reader.abort(); reject(new Error("Error parsing file"));}
            reader.onload = function () {

                //This will result in an array that will be recognized by C#.NET WebApi as a byte[]
                let bytes = Array.from(new Uint8Array(this.result));

                //if you want the base64encoded file you would use the below line:
                let base64StringFile = btoa(bytes.map((item) => String.fromCharCode(item)).join(""));

                //Resolve the promise with your custom file structure
                resolve({ 
                    bytes: bytes,
                    base64StringFile: base64StringFile,
                    fileName: file.name, 
                    fileType: file.type
                });
            }
            reader.readAsArrayBuffer(file);
        });
    }

    //using the functions with your file:

    file = document.querySelector('#files > input[type="file"]').files[0]
    getFile(file).then((customJsonFile) => {
         //customJsonFile is your newly constructed file.
         console.log(customJsonFile);
    });

    //if you are in an environment where async/await is supported

    files = document.querySelector('#files > input[type="file"]').files
    let customJsonFiles = await getFiles(files);
    //customJsonFiles is an array of your custom files
    console.log(customJsonFiles);
tkd_aj
источник
1
Обещаю всем, на основе массива .map отлично работает! По крайней мере для меня.
davidwillianx
0
onInputChange(evt) {
    var tgt = evt.target || window.event.srcElement,
    files = tgt.files;
    if (FileReader && files && files.length) {
        var fr = new FileReader();
        fr.onload = function () {
            var base64 = fr.result;
            debugger;
        }
        fr.readAsDataURL(files[0]);
    }
}
user2120895
источник