在 JavaScript 中,可以通过读取文件的头部字节(也称为"文件签名"或"魔数")来确定文件的实际类型。这种方法通常用于防止用户上传文件时伪造文件类型。例如,用户可能重命名一个 .exe 文件为 .jpg 以绕过某些限制。但文件头部的字节序列是特定文件类型的特征。
示例实现以下是一个示例来展示如何在浏览器环境中读取文件头部的标识以确定文件类型。
你可以使用 FileReader API 来读取文件的字节数据,并通过比较文件头部的字节序列来判断文件类型。
1. 定义文件类型的魔数首先,定义一个文件签名(魔数)到文件类型的映射:
const fileSignatures = {
'89504E47': 'image/png',
'FFD8FF': 'image/jpeg',
'47494638': 'image/gif',
'504B0304': 'application/zip',
'25504446': 'application/pdf',
// 添加其他文件类型签名
}; 2. 读取文件头部字节 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Type Detection</title>
</head>
<body>
<input type="file" id="fileInput">
<script type="module">
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (file) {
const fileType = await getFileType(file);
console.log(`Detected file type: ${fileType}`);
}
});
async function getFileType(file) {
const fileSignature = await getFileSignature(file);
const fileType = fileSignatures[fileSignature];
return fileType || 'Unknown';
}
async function getFileSignature(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = (event) => {
if (event.target.readyState === FileReader.DONE) {
const uint8Array = new Uint8Array(event.target.result);
const fileHeader = Array.from(uint8Array).map(byte => byte.toString(16).padStart(2, '0')).join('').toUpperCase();
// 取前 4 个字节的文件签名
resolve(fileHeader.slice(0, 8));
}
};
// 读取文件前 4 个字节(常见文件签名长度不同,适当调整)
reader.readAsArrayBuffer(file.slice(0, 4));
});
}
</script>
</body>
</html> 解释文件签名定义 (fileSignatures):
这是一个映射文件签名到文件 MIME 类型的对象。实际应用中,你可以添加更多的文件签名。读取文件头部字节 (getFileSignature 方法):
getFileSignature 方法使用 FileReader API 来读取文件的头部字节。将头部字节转换为字符串并返回。这里读取了文件的前 4 个字节并转换成16 进制字符串。判断文件类型 (getFileType 方法):
getFileType 方法调用 getFileSignature 获取文件签名。如果签名匹配预定义的文件签名,则返回对应的文件 MIME 类型。文件输入事件监听:
当用户选择文件时,触发 change 事件,调用 getFileType 方法来检测文件类型,并在控制台中打印结果。功能扩展更丰富的文件类型支持:
可以在 fileSignatures 对象中添加更多类型的文件签名。例如,TIFF 文件签名可以是 49492A00 或 4D4D002A,PDF 文件签名可以是 25504446 等。文件头部字节长度调整:
根据具体文件类型的签名长度调整读取的字节数。例如,有的文件类型签名超过 4 个字节。错误处理:
添加对异常情况的处理,如文件读取失败的处理逻辑等。通过这种方法,你可以有效地判断文件的实际类型,并增强文件上传的安全性和可靠性。
网友回复


