背景
项目中用到了一个上传文件的组件,项目要求只能上传特定格式的文件,该功能可以使用上传文件的组件或者html input中的accept属性来限制,其原理是判断文件的后缀名。 使用input的方法如下:
<input type="file"
id="avatar" name="avatar"
accept="image/png, image/jpeg"
>
但是,这就会造成一个问题,如何直接修改了文件的后缀名,那么组件这个时候是会认为上传的文件的类型是符合要求的。
问题及解决方法
那么,当用户将文件类型修改了之后,如何在前端处理呢?
另一个方法就是读取文件的内容。将文件内容读取之后转换为 16 进制,相同类型的文件开头的内容是一样的, 就可以根据文件开头的内容来判断文件原本的类型,而不是修改之后的类型。
我在react项目中是这样写的:
var blob = files[i];
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
var arr = (new Uint8Array(e.target.result)).subarray(0, 4);
var header = "";
for(var i = 0; i < arr.length; i++) {
header += arr[i].toString(16);
}
console.log(header);
//(这里根据header变量的内容判断是什么类型的文件)
};
fileReader.readAsArrayBuffer(blob);
注意事项
- 上面这段代码中,第一行的file如果使用了上传文件组件,一般是可以直接获取到的;但是如果使用的是input组件,可以参考下面的方法来获取:
<input type="file" id="your-files" multiple>
<script>
var control = document.getElementById("your-files");
control.addEventListener("change", function(event) {
// When the control has changed, there are new files
var files = control.files,
for (var i = 0; i < files.length; i++) {
console.log("Filename: " + files[i].name);
console.log("Type: " + files[i].type);
console.log("Size: " + files[i].size + " bytes");
}
}, false);
</script>
因为 input 设置了multiple,因此可以上传多个文件,那么files对象也有多个,如果设置为只可以上传一个文件,那么取files[0]即可。
- 如果用了ts,还需要修改一下类型的报错,我是通过把e.target.result的类型设置为any解决的,如果有更好的方法欢迎交流。
3.有几个文件虽然文件类型不同,但文件内容开头的内容却是一样的,比如docx文件和xlsx文件的开头内容就是一样的。这种情况我还没有找到判断的方法,只能把这种情况交给后端处理了。后端如果无法读取文件内容,那么就在前端报错。
参考: