如何在JavaScript中将文件转换为base64?

369

更新: TypeScript 版本也可以在回答中找到。

现在我通过这行代码获取文件对象:

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

我需要通过 JSON 以 base64 的形式发送该文件。请问如何将其转换为 base64 字符串?

15个回答

439
尝试使用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一起使用。
查看完整的工作示例


4
了解更多有关FileReader API的信息:https://developer.mozilla.org/en-US/docs/Web/API/FileReader,以及浏览器支持情况:http://caniuse.com/#feat=filereader。 - Lukas Liesis
20
我试图在getBase64()函数中使用return reader.result(而不是console.log(reader.result)),因为我想将base64作为变量捕获(然后发送到Google Apps Script)。 我使用以下代码调用函数:var my_file_as_base64 = getBase64(file),然后尝试用console.log(my_file_as_base64 )打印到控制台,但只得到了undefined。 如何正确地将base64分配给变量? - user1063287
2
我将上面的评论转化为一个问题,如果有人能回答的话。https://dev59.com/dFYN5IYBdhLWcg3wm5EL - user1063287
我需要在浏览器中打开这个Base64文件,并且使用相同的文件名。我正在使用window.open(url, '_blank')来打开它,这个方法运行良好。请问如何给它指定文件名?请帮忙。 - Munish Sharma
谢谢!我认为https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL上的解释不是很清楚。 - johey

426

现代 ES6 方式(async/await)

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

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

Main();

更新:

如果你想捕获错误

async function Main() {
   const file = document.querySelector('#myfile').files[0];
   try {
      const result = await toBase64(file);
      return result
   } catch(error) {
      console.error(error);
      return;
   }
   //...
}

20
这段代码不正确。如果你await一个返回拒绝(rejected)Promise的函数,你将不会得到一个通过调用返回的错误(Error),它会被抛出,你需要捕获它。 - Dancrumb
1
异步函数和 Promise 的绝佳使用示例。 - Thiago Frias
5
我曾尝试使用这段代码片段,试图将<input type='file' />中的图像转换,但是出现了错误。:Users.js:41 Uncaught (in promise) TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'。 - nishi
谢谢,还有一个问题,我如何设置内容类型为仅图像? - SHAHEEREZ
@SHAHEEREZ,你需要在表单输入中指定内容类型,而不是在代码中。<input type="file" accept="image/png, image/jpeg"> - Дмитрий Васильев

162
如果您想要一个基于 Promise 的解决方案,这是 @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)
);

我需要在浏览器中使用相同的文件名打开这个Base64文件,我正在使用window.open(url, '_blank')打开它,这很好用,但是我该如何给它一个文件名呢?请帮忙。 - Munish Sharma

100

在 Dmitri Pavlutin 和 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
4
我还有一个更简单的版本:resolve(reader.result.replace(/^.*,/, ''));。由于逗号,不在base64字母表内,因此我们可以将包括逗号在内的所有内容都删除掉。https://dev59.com/Y2Ys5IYBdhLWcg3wBvf7#13195218 - Johnride
1
@ArnaudP Typescript 错误:类型“string | ArrayBuffer”上不存在属性“replace”。 - Romel Gomez
@RomelGomez 是的,这段代码是 js,所以没有编译器会干扰你关于类型的问题。然而,在我的 ts 代码中,我在 .replace(...) 前面添加了 .toString()。不确定是否真正必要,但为了保险起见,我会更新我的答案。谢谢。 - Arnaud P
这个让我省了很多麻烦,非常感谢。 - Nyuu
显示剩余2条评论

24

TypeScript版本

const file2Base64 = (file:File):Promise<string> => {
    return new Promise<string> ((resolve,reject)=> {
         const reader = new FileReader();
         reader.readAsDataURL(file);
         reader.onload = () => resolve(reader.result?.toString() || '');
         reader.onerror = error => reject(error);
     })
    }

2
reader.result 可能为 null,这会导致 TypeScript 报错。以下代码处理了这种情况:reader.onload = () => resolve(reader.result ? reader.result.toString() : '') - Rahul Ravindran
2
为了防止“对象可能为'null'”的错误,您可以使用可选链接运算符,如下所示:reader.onload = () => resolve(reader.result?.toString() || ''); - Oleksandr Danylchenko
谢谢,我已经更新了代码 :) - Cyber Progs

15

JavaScript btoa()函数可用于将数据转换为base64编码的字符串。

<div>
    <div>
        <label for="filePicker">Choose or drag a file:</label><br>
        <input type="file" id="filePicker">
    </div>
    <br>
    <div>
        <h1>Base64 encoded version</h1>
        <textarea id="base64textarea" 
                  placeholder="Base64 will appear here" 
                  cols="50" rows="15"></textarea>
    </div>
</div>
var handleFileSelect = function(evt) {
    var files = evt.target.files;
    var file = files[0];

    if (files && file) {
        var reader = new FileReader();

        reader.onload = function(readerEvt) {
            var binaryString = readerEvt.target.result;
            document.getElementById("base64textarea").value = btoa(binaryString);
        };

        reader.readAsBinaryString(file);
    }
};

if (window.File && window.FileReader && window.FileList && window.Blob) {
    document.getElementById('filePicker')
            .addEventListener('change', handleFileSelect, false);
} else {
    alert('The File APIs are not fully supported in this browser.');
}

8
btoa 只能用于字符串。如何在文件上使用它? - Vassily
15
您需要首先阅读文件,然后将其传递给这个函数。类似于 http://jsfiddle.net/eliseosoto/JHQnk/ 的内容。 - Pranav Maniar
3
@PranavManiar,您的代码已经失效了。您能否更新链接? - Dan
这是我找到的唯一有效的解决办法。 - jjxtra

10

这里是我编写的几个函数,可以将文件以json格式获取,以便于传递和处理:

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

    //take a single JavaScript File object
    function getFile(file) {
        const 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,
                    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
Promise.all,基于数组映射的方式非常好用!至少对我来说是这样。 - davidwillianx

4
const fileInput = document.querySelector('input');

fileInput.addEventListener('change', (e) => {

// get a reference to the file
const file = e.target.files[0];

// encode the file using the FileReader API
const reader = new FileReader();
reader.onloadend = () => {

    // use a regex to remove data url part
    const base64String = reader.result
        .replace('data:', '')
        .replace(/^.+,/, '');

    // log to console
    // logs wL2dvYWwgbW9yZ...
    console.log(base64String);
};
reader.readAsDataURL(file);});

1
请参考此链接:https://pqina.nl/blog/convert-a-file-to-a-base64-string-with-javascript/,了解如何使用JavaScript将文件转换为Base64字符串。 - Om Fuke

2
我使用了这个简单的方法,它成功地起作用了。
 function  uploadImage(e) {
  var file = e.target.files[0];
    let reader = new FileReader();
    reader.onload = (e) => {
    let image = e.target.result;
    console.log(image);
    };
  reader.readAsDataURL(file);
  
}

1
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]);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接