为 FileReader.readAsDataURL 将 URL 转换为 File 或 Blob

参考资料: ReadAsDataURL

考虑到以下例子:

function previewFile(file) {


var reader  = new FileReader();


reader.onloadend = function () {
console.log(reader.result);
}
reader.readAsDataURL(file);
}

上面写着:

ReadAsDataURL (blob) ;

Blob: 从中读取的 Blob 或文件。

  1. 一个本地文件 URL 如何能像: 'file:///C:/path-to/root.png' 传递到 readAsDataURL()

  2. 在 Firefox 插件中可以使用 FileReader()吗?

319728 次浏览

Try this I learned this from @nmaier when I was mucking around with converting to ico: Well i dont really understand what array buffer is but it does what we need:

function previewFile(file) {


var reader  = new FileReader();


reader.onloadend = function () {
console.log(reader.result); //this is an ArrayBuffer
}
reader.readAsArrayBuffer(file);
}

notice how i just changed your readAsDataURL to readAsArrayBuffer.

Here is the example @nmaier gave me: https://stackoverflow.com/a/24253997/1828637

it has a fiddle

if you want to take this and make a file out of it i would think you would use file-output-stream in the onloadend

This information is outdated as of now, but cannot be deleted.

  1. You can create File instances just by specifying a path when your code is chrome-privileged:

    new File("/path/to/file");
    

    File is a sub-class of Blob, so all File instances are also valid Blobs. Please note that this requires a platform path, and not a file URL.

  2. Yes, FileReader is available to addons.

File and FileReader are available in all windows. If you want to use them in a non-window scope (like bootstrap.js or a code module), you may use nsIDOMFile/nsIDOMFileReader.

To convert a URL to a Blob for FileReader.readAsDataURL() do this:

var request = new XMLHttpRequest();
request.open('GET', MY_URL, true);
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.readAsDataURL(request.response);
reader.onload =  function(e){
console.log('DataURL:', e.target.result);
};
};
request.send();

Expanding on Felix Turner s response, here is how I would use this approach with the fetch API.

async function createFile(){
let response = await fetch('http://127.0.0.1:8080/test.jpg');
let data = await response.blob();
let metadata = {
type: 'image/jpeg'
};
let file = new File([data], "test.jpg", metadata);
// ... do something with the file or return it
}
createFile();

Here is my code using async awaits and promises

const getBlobFromUrl = (myImageUrl) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
request.open('GET', myImageUrl, true);
request.responseType = 'blob';
request.onload = () => {
resolve(request.response);
};
request.onerror = reject;
request.send();
})
}


const getDataFromBlob = (myBlob) => {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsDataURL(myBlob);
})
}


const convertUrlToImageData = async (myImageUrl) => {
try {
let myBlob = await getBlobFromUrl(myImageUrl);
console.log(myBlob)
let myImageData = await getDataFromBlob(myBlob);
console.log(myImageData)
return myImageData;
} catch (err) {
console.log(err);
return null;
}
}


export default convertUrlToImageData;

I know this is an expansion off of @tibor-udvari's answer, but for a nicer copy and paste.

async function createFile(url, type){
if (typeof window === 'undefined') return // make sure we are in the browser
const response = await fetch(url)
const data = await response.blob()
const metadata = {
type: type || 'video/quicktime'
}
return new File([data], url, metadata)
}

The suggested edit queue is full for @tibor-udvari's excellent fetch answer, so I'll post my suggested edits as a new answer.

This function gets the content type from the header if returned, otherwise falls back on a settable default type.

async function getFileFromUrl(url, name, defaultType = 'image/jpeg'){
const response = await fetch(url);
const data = await response.blob();
return new File([data], name, {
type: data.type || defaultType,
});
}


// `await` can only be used in an async body, but showing it here for simplicity.
const file = await getFileFromUrl('https://example.com/image.jpg', 'example.jpg');

Here's a simplest way to get blob or file object with vanila.js and promise

const fileURL_to_blob = (file_url) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest();
request.open('GET', file_url, true);
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.readAsDataURL(request.response);
reader.onload =  function(e){
//console.log('DataURL:', e.target.result);
resolve(e.target.result);
};
};
request.onerror=function(e){
reject(e);
}
request.send();
});
}

I ended up wanting something similar to this but without having to pass the type for the file or the filename, so I made my own example based on @Felix Turner's example. I used the content-disposition header for the filename first in case the file is coming back from an API endpoint, but use the last part of the URL path if that header doesn't exist.

function getFilenameFromContentDisposition(res) {
let filename = null;


const disposition = res.headers.get("content-disposition");


if (disposition?.includes("attachment")) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches?.[1]) {
filename = matches[1].replace(/['"]/g, "");
// Sometimes the filename comes in a URI encoded format so decode it
filename = decodeURIComponent(filename);
// Sometimes the filename starts with UTF-8, remove that
filename = filename.replace(/^UTF-8/i, "").trim();
}
}


return filename;
}


async function getFileFromLink(url) {
const fileRes = await fetch(url);
const blob = await fileRes.blob();


let fileName = getFilenameFromContentDisposition(fileRes);
if (!fileName) {
fileName = url.split("/").pop();
}


const file = new File([blob], fileName, {
type: blob.type,
});


return file;
}

If you wanted to make this better, I'd use the content-disposition package on npm for the parsing as the formatting of it can get strange. I'd also probably use the mime package for ensuring that the filename from the URL has a proper file extension based on the returned content-type