前端文件上传识别文件类型的几种方法,快看你是哪个?
后台-插件-广告管理-内容页头部广告(手机) |
在我们的日常开发过程中,我们会经常接触到一些文件上传的事情,其中在前端这边识别识别文件类型的是非常常见的功能,例如来限制文件上传的类型,接下来我们来了解一下最常见的几种方式。
通过文件扩展名判断类型
最简单快捷的方法就是 hiyaJavaScript 获取文件名的扩展名,对比扩展名来判断文件类型,如下代码所示:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>文件类型识别</title>
- </head>
- <body>
- <h2>文件类型识别</h2>
- <input type="file" id="fileInput" />
- <p id="fileType">文件类型</p>
- <script>
- document
- .getElementById("fileInput")
- .addEventListener("change", function (event) {
- const file = event.target.files[0];
- if (!file) {
- document.getElementById("fileType").textContent = "没有文件被选中";
- return;
- }
- const fileName = file.name;
- const extensionIndex = fileName.lastIndexOf(".");
- let fileType;
- if (extensionIndex === -1 || extensionIndex === 0) {
- fileType = "未知";
- } else {
- fileType = fileName.substring(extensionIndex + 1);
- }
- document.getElementById("fileType").textContent =
- "文件类型: " + fileType;
- });
- </script>
- </body>
- </html>
当然 JavaScript 这方面的代码你也可以这样子实现,看你需求:
- document
- .getElementById("fileInput")
- .addEventListener("change", function (event) {
- const file = event.target.files[0];
- if (!file) {
- document.getElementById("fileType").textContent = "没有文件被选中";
- return;
- }
- let fileType = file.type;
- if (!fileType) {
- const fileNameParts = file.name.split(".");
- const extension = fileNameParts[fileNameParts.length - 1];
- if (extension === "md") {
- fileType = "text/markdown";
- }
- }
- document.getElementById("fileType").textContent = "文件类型: " + fileType;
- });
上传一个文件,文件的类型被输出出来了:
%20仅通过文件扩展名来判断类型存在安全和准确性风险,因为它可能被恶意用户篡改以上传危险文件,且不能可靠地反映文件的真实内容,同时还无法识别没有扩展名的文件。
%20通过%20MIME%20类型判断
%20当我们使用%20HTML%20的%20%20标签时,可以通过文件的%20type%20属性获取%20MIME%20类型:
%20- document
- %20%20.getElementById("fileInput")
- %20%20.addEventListener("change",%20function%20(event)%20{
- %20%20%20%20const%20file%20=%20event.target.files[0];
- %20%20%20%20if%20(!file)%20{
- %20%20%20%20%20%20document.getElementById("fileType").textContent%20=%20"没有文件被选中";
- %20%20%20%20%20%20return;
- %20%20%20%20}
- %20
- %20%20%20%20document.getElementById("fileType").textContent%20=%20"文件类型:%20"%20+%20file.type;
- %20%20});
这段代码为文件输入元素添加了一个%20change%20事件监听器。当用户选择文件后,会触发这个事件。事件处理函数会获取用户选中的文件,并显示它的%20MIME%20类型。
%20 %20 %20%20 %20%20MIME(多用途互联网邮件扩展,Multi-purpose%20Internet%20Mail%20Extensions)最初是为了改进电子邮件中的文件传输而设计的,但它的使用范围已经扩展到互联网的其他领域。MIME%20定义了一系列的数据类型和数据格式,用于在网络上交换数据。
%20
但是%20MIME%20类型有时可能不准确或为空。
%20 %20 %20使用%20FileReader%20读取文件内容
%20FileReader%20是%20HTML5%20提供的%20API,可以用来读取文件的内容,通过读取文件内容的一部分,可以更准确地判断文件类型:
%20- <!DOCTYPE%20html>
- <html%20lang="en">
- %20%20<head>
- %20%20%20%20<meta%20charset="UTF-8"%20/>
- %20%20%20%20<meta%20http-equiv="X-UA-Compatible"%20content="IE=edge"%20/>
- %20%20%20%20<meta%20name="viewport"%20content="width=device-width,%20initial-scale=1.0"%20/>
- %20%20%20%20<title>读取文件内容</title>
- %20%20</head>
- %20%20<body>
- %20%20%20%20<input%20type="file"%20id="fileInput"%20/>
- %20%20%20%20<div%20id="fileContent">文件类型</div>
- %20
- %20%20%20%20<script>
- %20%20%20%20%20%20document
- %20%20%20%20%20%20%20%20.getElementById("fileInput")
- %20%20%20%20%20%20%20%20.addEventListener("change",%20function%20(event)%20{
- %20%20%20%20%20%20%20%20%20%20const%20file%20=%20event.target.files[0];
- %20%20%20%20%20%20%20%20%20%20if%20(!file)%20{
- %20%20%20%20%20%20%20%20%20%20%20%20document.getElementById("fileContent").textContent%20=
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20"没有文件被选中";
- %20%20%20%20%20%20%20%20%20%20%20%20return;
- %20%20%20%20%20%20%20%20%20%20}
- %20
- %20%20%20%20%20%20%20%20%20%20const%20reader%20=%20new%20FileReader();
- %20
- %20%20%20%20%20%20%20%20%20%20reader.onloadend%20=%20function%20(e)%20{
- %20%20%20%20%20%20%20%20%20%20%20%20const%20arr%20=%20new%20Uint8Array(e.target.result).subarray(0,%204);
- %20%20%20%20%20%20%20%20%20%20%20%20let%20header%20=%20"";
- %20%20%20%20%20%20%20%20%20%20%20%20for%20(let%20i%20=%200;%20i%20<%20arr.length;%20i++)%20{
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20header%20+=%20arr[i].toString(16).padStart(2,%20"0");
- %20%20%20%20%20%20%20%20%20%20%20%20}
- %20
- %20%20%20%20%20%20%20%20%20%20%20%20let%20fileType%20=%20"未知";
- %20%20%20%20%20%20%20%20%20%20%20%20switch%20(header)%20{
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20case%20"89504e47":
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fileType%20=%20"图片%20(PNG)";
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break;
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20case%20"47494638":
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fileType%20=%20"图片%20(GIF)";
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break;
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20case%20"ffd8ffe0":
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20case%20"ffd8ffe1":
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20case%20"ffd8ffe2":
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fileType%20=%20"图片%20(JPEG)";
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break;
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20case%20"25504446":
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fileType%20=%20"文档%20(PDF)";
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break;
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20更多文件类型...
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20default:
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fileType%20=%20"未知";
- %20%20%20%20%20%20%20%20%20%20%20%20}
- %20%20%20%20%20%20%20%20%20%20%20%20document.getElementById("fileContent").textContent%20=
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20"文件类型:%20"%20+%20fileType;
- %20%20%20%20%20%20%20%20%20%20};
- %20
- %20%20%20%20%20%20%20%20%20%20reader.onerror%20=%20function%20()%20{
- %20%20%20%20%20%20%20%20%20%20%20%20document.getElementById("fileContent").textContent%20=%20"文件读取出错";
- %20%20%20%20%20%20%20%20%20%20};
- %20
- %20%20%20%20%20%20%20%20%20%20reader.readAsArrayBuffer(file);
- %20%20%20%20%20%20%20%20});
- %20%20%20%20</script>
- %20%20</body>
- </html>
在上面的代码中读取了文件的前四个字节来判断文件类型。它包含了用于标识文件格式的特定模式或“魔术数字”。
%20文件类型被正确输出。
%20HTML5%20File%20API
%20使用%20HTML5%20File%20API%20可以读取用户在浏览器中选择的文件的信息,包括文件类型。这个%20API%20提供了一个标准的方式来获取关于文件的信息,如文件名、大小以及%20MIME%20类型。
%20- document
- %20%20.getElementById("fileInput")
- %20%20.addEventListener("change",%20function%20(event)%20{
- %20%20%20%20const%20file%20=%20event.target.files[0];
- %20%20%20%20if%20(!file)%20{
- %20%20%20%20%20%20document.getElementById("fileInfo").textContent%20=%20"没有选择文件";
- %20%20%20%20%20%20return;
- %20%20%20%20}
- %20
- %20%20%20%20const%20fileInfo%20=%20`文件名:%20${file.name}<br>文件大小:%20${file.size}%20字节<br>文件类型:%20${file.type}`;
- %20%20%20%20document.getElementById("fileInfo").innerHTML%20=%20fileInfo;
- %20%20});
最终输出效果如下图所示:
%20 %20 %20装%20X%20必备,WebAssembly
%20使用%20WebAssembly%20(WASM)%20对文件进行识别通常涉及到较为复杂的操作,因为你需要将文件处理逻辑编译为%20WASM%20模块,然后在%20JavaScript%20中调用这个模块来处理文件。
%20第一步,我们以%20C%20为例子,接下来我们编写一个%20C%20代码,如下:
%20- #include%20<string.h>
- #include%20<emscripten.h>
- %20
- //%20检查%20PNG
- int%20is_png(const%20unsigned%20char%20*buffer)%20{
- %20%20%20%20const%20unsigned%20char%20png_signature[8]%20=%20{0x89,%20'P',%20'N',%20'G',%200x0D,%200x0A,%200x1A,%200x0A};
- %20%20%20%20return%20memcmp(buffer,%20png_signature,%208)%20==%200;
- }
- %20
- //%20检查%20JPEG
- int%20is_jpeg(const%20unsigned%20char%20*buffer)%20{
- %20%20%20%20return%20buffer[0]%20==%200xFF%20&&%20buffer[1]%20==%200xD8%20&&%20buffer[2]%20==%200xFF;
- }
- %20
- //%20检查%20GIF
- int%20is_gif(const%20unsigned%20char%20*buffer)%20{
- %20%20%20%20return%20strncmp((const%20char%20*)buffer,%20"GIF",%203)%20==%200;
- }
- %20
- //%20检查%20PDF
- int%20is_pdf(const%20unsigned%20char%20*buffer)%20{
- %20%20%20%20return%20strncmp((const%20char%20*)buffer,%20"%PDF-",%205)%20==%200;
- }
- %20
- //%20主函数,用于检测文件类型
- EMSCRIPTEN_KEEPALIVE
- int%20check_file_type(const%20unsigned%20char%20*buffer,%20int%20length)%20{
- %20%20%20%20if%20(is_pdf(buffer))%20{
- %20%20%20%20%20%20%20%20return%201;
- %20%20%20%20}%20else%20if%20(is_png(buffer))%20{
- %20%20%20%20%20%20%20%20return%202;
- %20%20%20%20}%20else%20if%20(is_jpeg(buffer))%20{
- %20%20%20%20%20%20%20%20return%203;
- %20%20%20%20}%20else%20if%20(is_gif(buffer))%20{
- %20%20%20%20%20%20%20%20return%204;
- %20%20%20%20}
- %20%20%20%20return%200;%20//%20未知类型
- }
在上面的这些代码中,通过比较输入流的前 8 个字节与这个序列来判断是否为某个文件。
代码编写完成之后,我们要在终端执行一行命令如下所示:
emcc index.c -s WASM=1 -o index.js -s EXPORTED_FUNCTIONS='["_check_file_type", "_malloc", "_free"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'最终会生成这两个文件:
%20这个时候我们就可以在我们前端中使用了,编写如下代码:
%20- <!DOCTYPE%20html>
- <html%20lang="en">
- %20%20<head>
- %20%20%20%20<meta%20charset="UTF-8"%20/>
- %20%20%20%20<title>文件类型识别</title>
- %20%20%20%20<script%20src="./index.js"></script>
- %20%20</head>
- %20%20<body>
- %20%20%20%20<input%20type="file"%20id="fileInput"%20/>
- %20
- %20%20%20%20<script>
- %20%20%20%20%20%20const%20fileInput%20=%20document.getElementById("fileInput");
- %20
- %20%20%20%20%20%20Module.onRuntimeInitialized%20=%20()%20=>%20{
- %20%20%20%20%20%20%20%20fileInput.addEventListener("change",%20(event)%20=>%20{
- %20%20%20%20%20%20%20%20%20%20const%20file%20=%20event.target.files[0];
- %20%20%20%20%20%20%20%20%20%20if%20(!file)%20{
- %20%20%20%20%20%20%20%20%20%20%20%20return;
- %20%20%20%20%20%20%20%20%20%20}
- %20
- %20%20%20%20%20%20%20%20%20%20const%20reader%20=%20new%20FileReader();
- %20%20%20%20%20%20%20%20%20%20reader.onload%20=%20(e)%20=>%20{
- %20%20%20%20%20%20%20%20%20%20%20%20const%20buffer%20=%20new%20Uint8Array(e.target.result);
- %20
- %20%20%20%20%20%20%20%20%20%20%20%20//%20分配内存并将数据复制到%20WebAssembly%20的内存空间
- %20%20%20%20%20%20%20%20%20%20%20%20const%20dataPtr%20=%20Module._malloc(buffer.length);
- %20%20%20%20%20%20%20%20%20%20%20%20Module.HEAPU8.set(buffer,%20dataPtr);
- %20
- %20%20%20%20%20%20%20%20%20%20%20%20//%20调用%20WebAssembly%20函数
- %20%20%20%20%20%20%20%20%20%20%20%20const%20fileType%20=%20Module.ccall(
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20"check_file_type",%20//%20C%20函数名
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20"number",%20//%20返回值类型
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20["number",%20"number"],%20//%20参数类型
- %20%20%20%20%20%20%20%20%20%20%20%20%20%20[dataPtr,%20buffer.length]%20//%20参数
- %20%20%20%20%20%20%20%20%20%20%20%20);
- %20
- %20%20%20%20%20%20%20%20%20%20%20%20//%20输出文件类型到控制台
- %20%20%20%20%20%20%20%20%20%20%20%20console.log("文件类型%20ID:",%20fileType);
- %20
- %20%20%20%20%20%20%20%20%20%20%20%20//%20释放内存
- %20%20%20%20%20%20%20%20%20%20%20%20Module._free(dataPtr);
- %20%20%20%20%20%20%20%20%20%20};
- %20%20%20%20%20%20%20%20%20%20reader.readAsArrayBuffer(file);
- %20%20%20%20%20%20%20%20});
- %20%20%20%20%20%20};
- %20%20%20%20</script>
- %20%20</body>
- </html>
这样,我们就可以根据不同的 id 来返回不同的文件类型了:
通过以上步骤,我们实现了一个使用 WebAssembly 来识别文件类型并在浏览器控制台上输出结果的功能。
总结
除了这些之外,我们还可以使用第三方库 file-type 来实现文件类型检测,这里我们就不再进行 demo 演示了,感兴趣的可以去官方文档中进行查阅。
另外最近对脚手架的仓库代码进行了重构,之后会越来越规范,规模会越来越大,感兴趣的小伙伴可以加入来一起开发,春招没有项目的朋友也可以以此作为春招的项目:
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |