Comment convertir un fichier en base64 en JavaScript?


187

Maintenant, j'obtiens l'objet File par cette ligne:

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

J'ai besoin d'envoyer ce fichier via json en base 64. Que dois-je faire pour le convertir en chaîne base64?

Réponses:


118

Méthode ES6 moderne (async / attente)

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:

Si vous voulez attraper des erreurs

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

Ce code est incorrect. Si vous awaitutilisez une fonction qui renvoie une promesse rejetée, vous n'obtiendrez pas d'erreur renvoyée par l'appel; il sera lancé et vous devrez l'attraper.
Dancrumb

1
Excellent exemple d'utilisation des fonctions asynchrones et des promesses
Thiago Frias

292

Essayez la solution en utilisant 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

Notez qu'il .files[0]s'agit d'un Filetype, qui est une sous-catégorie de Blob. Ainsi, il peut être utilisé avec FileReader.
Voir l' exemple de travail complet .


2
En savoir plus sur l'API FileReader: developer.mozilla.org/en-US/docs/Web/API/FileReader et la prise en charge du navigateur: caniuse.com/#feat=filereader
Lukas Liesis

7
J'ai essayé d'utiliser return reader.resultla getBase64()fonction (plutôt que d'utiliser console.log(reader.result)) parce que je veux capturer la base64 en tant que variable (puis l'envoyer à Google Apps Script). J'ai appelé la fonction avec: var my_file_as_base64 = getBase64(file)puis j'ai essayé d'imprimer sur console avec console.log(my_file_as_base64 )et je viens de l'obtenir undefined. Comment puis-je attribuer correctement la base64 à une variable?
user1063287

1
J'ai fait une question sur le commentaire ci-dessus si quelqu'un peut répondre. stackoverflow.com/questions/47195119/…
user1063287

J'ai besoin d'ouvrir ce fichier Base64 dans le navigateur avec le même nom de fichier, je l'ouvre en utilisant window.open (url, '_blank') qui fonctionne bien, comment puis-je donner un nom de fichier à cela? s'il vous plaît aider.
Munish Sharma

Merci! Je pense que cela n'est pas très bien expliqué sur developer.mozilla.org/en-US/docs/Web/API/FileReader
...

124

Si vous recherchez une solution basée sur la promesse, voici le code de @ Dmitri adapté pour cela:

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

J'ai besoin d'ouvrir ce fichier Base64 dans le navigateur avec le même nom de fichier, je l'ouvre en utilisant window.open (url, '_blank') qui fonctionne bien, comment puis-je donner un nom de fichier à cela? s'il vous plaît aider.
Munish Sharma

42

En s'appuyant sur les réponses de Dmitri Pavlutin et joshua.paling, voici une version étendue qui extrait le contenu base64 (supprime les métadonnées au début) et assure également le remplissage correct .

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, le premier remplacement consiste à attraper le fichier vide, le deuxième remplacement est manquant virgule - encoded = reader.result.replace ("data:", "") .replace (/^.*; base64, /, "");
user3333134

Ma parole, ce coma m'a vraiment manqué. Ce qui est incroyable, c'est que cela ne semble pas du tout déranger mon backend, j'ai quand même pu télécharger des fichiers Excel avec succès o_O. J'ai corrigé l'expression rationnelle pour prendre également en compte votre cas d'utilisation de fichier vide. Merci.
Arnaud P

2
J'ai une version encore plus facile: resolve(reader.result.replace(/^.*,/, ''));. Puisque le coma ,est en dehors de l'alphabet base64, nous pouvons dépouiller tout ce qui se présente jusqu'au coma inclus. stackoverflow.com/a/13195218/1935128
Johnride

Ok merci pour la mise en garde, bien que selon l'expression régulière que j'ai écrite ici (j'aurais besoin d'expérimenter à nouveau pour être sûr), il peut y en avoir data:, sans aucune virgule, donc je vais garder cette première partie telle quelle. J'ai mis à jour la réponse en conséquence.
Arnaud P

1
@ArnaudP Erreur Typecript: la propriété 'replace' n'existe pas sur la chaîne de type '| ArrayBuffer '.
Romel Gomez

12

La fonction JavaScript btoa () peut être utilisée pour convertir des données en chaîne encodée en base64


6
btoa fonctionne uniquement avec une chaîne. Comment l'utiliser avec un fichier?
Vassily

10
vous devrez d'abord lire le fichier, puis le transmettre à cette fonction .. Quelque chose comme jsfiddle.net/eliseosoto/JHQnk
Pranav Maniar

1
@PranavManiar Votre violon ne fonctionne plus. Pouvez-vous mettre à jour le lien?
Dan

5

Voici quelques fonctions que j'ai écrites pour obtenir un fichier au format json qui peut être facilement transmis:

    //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
Promettez tout, basé dans un array.map fonctionne très bien! Au moins pour moi.
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]);
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.