Come convertire file in base64 in JavaScript?


186

Ora sto ottenendo l'oggetto File da questa riga:

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

Devo inviare questo file tramite json in base 64. Cosa devo fare per convertirlo in stringa base64?

Risposte:


118

Moderna modalità ES6 (asincrona / attende)

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:

Se vuoi rilevare errori

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;
   }
   //...
}

Questo codice non è corretto Se awaituna funzione che restituisce una promessa rifiutata, non riceverai un errore restituito dalla chiamata; verrà lanciato e dovrai prenderlo.
Dancrumb,

1
Grande esempio di utilizzo delle funzioni e delle promesse asincrone
Thiago Frias,

292

Prova la soluzione usando la FileReader classe :

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

Si noti che .files[0]è un Filetipo, che è una sottoclasse di Blob. Quindi può essere utilizzato con FileReader.
Vedi l' esempio di lavoro completo .


2
leggi di più sull'API FileReader: developer.mozilla.org/en-US/docs/Web/API/FileReader e supporto browser: caniuse.com/#feat=filereader
Lukas Liesis

7
Ho provato a utilizzare return reader.resultla getBase64()funzione (anziché utilizzare console.log(reader.result)) perché voglio catturare Base64 come variabile (e quindi inviarlo a Google Apps Script). Ho chiamato la funzione con: var my_file_as_base64 = getBase64(file)e poi ho provato a stampare su console con console.log(my_file_as_base64 )e ho appena ottenuto undefined. Come posso assegnare correttamente la base64 a una variabile?
user1063287

1
Ho fatto una domanda dal commento sopra se qualcuno può rispondere. stackoverflow.com/questions/47195119/...
user1063287

Ho bisogno di aprire questo file Base64 nel browser con lo stesso nome file, lo sto aprendo usando window.open (url, '_blank') che funziona bene, come posso dare un nome file a quello? per favore aiuto.
Munish Sharma,

Grazie! Penso che questo non sia spiegato molto bene su developer.mozilla.org/en-US/docs/Web/API/FileReader/…
johey

123

Se stai cercando una soluzione basata sulla promessa, questo è il codice di @ Dmitri adattato per questo:

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)
);

Ho bisogno di aprire questo file Base64 nel browser con lo stesso nome file, lo sto aprendo usando window.open (url, '_blank') che funziona bene, come posso dare un nome file a quello? per favore aiuto.
Munish Sharma,

42

Basandoci sulle risposte di Dmitri Pavlutin e joshua.paling, ecco una versione estesa che estrae il contenuto base64 (rimuove i metadati all'inizio) e assicura anche che il riempimento sia eseguito correttamente .

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, il primo sostituto è quello di catturare file vuoti, il secondo sostituto manca virgola - codificato = reader.result.replace ("data:", "") .replace (/^.*; base64, /, "");
user3333134,

La mia parola, mi mancava davvero quel coma. Ciò che è incredibile è che non sembrava disturbare affatto il mio backend, ero ancora in grado di caricare correttamente i file Excel o_O. Ho risolto il problema con regex per tenere conto anche del caso d'uso del file vuoto. Grazie.
Arnaud P

2
Ho una versione ancora più semplice: resolve(reader.result.replace(/^.*,/, ''));. Dato che il coma ,è al di fuori dell'alfabeto base64, possiamo eliminare tutto ciò che arriva fino al coma compreso. stackoverflow.com/a/13195218/1935128
Johnride

Ok grazie per il testa a testa, anche se secondo la regex che ho scritto qui (dovrei sperimentare di nuovo per essere sicuro), potrebbe esserci solo data:, senza alcuna virgola, quindi terrò la prima parte così com'è. Ho aggiornato la risposta di conseguenza.
Arnaud P

1
@ArnaudP Errore dattiloscritto: la proprietà 'sostituisci' non esiste sul tipo 'stringa | ArrayBuffer'.
Romel Gomez,


5

Ecco un paio di funzioni che ho scritto per ottenere un file in un formato json che può essere passato facilmente:

    //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);

1
Prometti tutto, basato su un array.map funziona alla grande! Almeno per me.
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]);
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.