js判断文件类型详解
通过file的type属性判断
<input type="file" onchange="onchangecb(this)" />
<script>
function onchangecb(e) {
const file = e.files[0];
console.log(file.type);
}
</script>
像html
中input
标签,就是根据选择文件的后缀来生成一个File
对象。
像下面的几种文件:
txt
文件:
jpg
文件:
mp4
文件:
使用文件后缀来判断
function onchangecb(e) {
const file = e.files[0];
//获取最后一个.的位置
const index = file.name.lastIndexOf('.');
//获取后缀
const ext = file.name.substr(index + 1);
console.log(ext);
}
在得到文件后缀名后,根据后缀即可判断文件的类型(文件格式)。比如需要判断一个文件是否是图片格式,首先定义一个判断函数:
function isImage(ext) {
return (
['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff'].indexOf(
ext.toLowerCase()
) !== -1
);
}
虽然可以直接通过对象的type
属性或者文件后缀来获取文件类型,但是如果强行修改文件后缀,同样可以将其他类型的文件上传至服务器,或者文件压根就没有后缀,那又要怎么判断呢?因此前端需要使用一个更加合理的方式。
根据二进制流及文件头来判断
虽然文件后缀可以手动改,因此可以直接通过读取文件的二进制来判断。
通常来说固定类型的文件头都是相同的,比如说jpeg
的文件头是FF D8 FF E0
。
这里提供一些常用的文件头:
const fileMap = {
JPEG: 'FF D8 FF E0',
JPG: 'FF D8 FF E1',
PNG: '89 50 4E 47',
GIF: '47 49 46 38',
TIFF: '49 49 2A 00',
BMP: '42 4D',
DWG: '41 43 31 30',
PSD: '38 42 50 53',
RTF: '7B 5C 72 74 66',
XML: '3C 3F 78 6D 6C',
HTML: '68 74 6D 6C 3E',
EML: '44 65 6C 69 76 65 72 79 2D 64 61 74 65 3A',
DBX: 'CF AD 12 FE C5 FD 74 6F',
PST: '21 42 44 4E',
XLS: 'D0 CF 11 E0',
DOC: 'D0 CF 11 E0',
MDB: '53 74 61 6E 64 61 72 64 20 4A',
WPD: 'FF 57 50 43',
PDF: '25 50 44 46 2D 31 2E',
QDF: 'AC 9E BD 8F',
PWL: 'E3 82 85 96',
ZIP: '50 4B 03 04',
RAR: '52 61 72 21',
WAV: '57 41 56 45',
AVI: '41 56 49 20',
RAM: '2E 72 61 FD',
RM: '2E 52 4D 46',
MPG: '00 00 01 BA',
MPG: '00 00 01 B3',
MOV: '6D 6F 6F 76',
ASF: '30 26 B2 75 8E 66 CF 11',
MID: '4D 54 68 64',
MP3: '49 44 33',
};
通过onchange
方法获取到选择的文件后,使用FileReader
读取文件的二进制,之后判断二进制的前几位是否跟符合相应类型文件的文件头。
以下是一些使用文件头来判断文件类型的简单代码
// 判断文件后缀与该文件内容是否相同类型
async function isSameFileType(file) {
const suffix = getFileSuffix(file.name).toUpperCase();
const fileBlobString = await blobToString(file.slice(0, 14));
// 如果文件类型中没有该类型,默认为false
if (!(suffix in fileMap)) {
return false;
}
return fileBlobString.includes(fileMap[suffix]);
}
async function blobToString(blob) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = function () {
const ret = reader.result
.split('') // 分隔开
.map((v) => v.charCodeAt()) // 循环返回指定位置的字符的 Unicode 编码
.map((v) => v.toString(16).toUpperCase()) // 返回十六进制格式
.map((v) => v.padStart(2, '0')) // 给空的那个填充 00 ,防止空缺
.join(' '); // 每个子节之间空格隔开
resolve(ret);
};
reader.readAsBinaryString(blob); // 调用之后触发onload事件
});
// 二进制=》ascii码=》转成16进制字符串
}
// 获取文件后缀
function getFileSuffix(filename) {
return filename.substring(filename.lastIndexOf('.') + 1, filename.length);
}
判断是否是png
类型:
async function isPng(file) {
// 同理
const ret = await blobToString(file.slice(0, 4));
const ispng = ret === fileMap.PNG;
return ispng;
}
当然也可以针对图片高宽进行限制:
在png
二进制中,第18-20位是图片的宽,22-24是高。
获取图片宽高:
function getRectByOffset(file, widthOffset, heightOffset, reverse) {
let width = await blobToString(file.slice(...widthOffset));
let height = await blobToString(file.slice(...heightOffset));
const w = parseInt(width.replace(" ", ""), 16);
const h = parseInt(height.replace(" ", ""), 16);
return { w, h };
}
修改一下之前判断isPng
的方法,加上高宽限制
const IMG_WIDTH_LIMIT = 1000;
const IMG_HEIGHT_LIMIT = 800
function isPng(file) {
// 同理
const ret = await this.blobToString(file.slice(0, 4));
const ispng = ret === fileMap.PNG;
if (ispng) {
const { w, h } = await this.getRectByOffset(file, [18, 20], [22, 24]);
console.log(`png 宽高 ${w},${h}`);
if (w > IMG_WIDTH_LIMIT || h > IMG_HEIGHT_LIMIT) {
this.$message.error(
"png图片宽高不得超过 " + IMG_WIDTH_LIMIT + "和" + IMG_HEIGHT_LIMIT
);
return false;
}
}
return ispng;
}
标签:function,文件,const,后缀,js,return,详解,file,文件类型
From: https://www.cnblogs.com/wp-leonard/p/17894444.html