input file之后为什么可以展示图片呢?
- 一般的答案都是说浏览器读取了文件,返回了一个dataType的对象,对象里有个
buffer[],这样就可以取出来数据展示了。 - 更有甚至处理方式是读取之后上传到服务器返回url,然后展示url。
- 这样的解释未免太不严谨。
我们可以从浏览器的角度来思考
- 浏览器需要对操作系统发送读取请求,操作系统切换特权级进入文件系统,查找文件,通过内存置换算法把文件加载到物理内存中。
- 操作系统的浏览器线程所包含的虚拟内存会连接到物理内存,操作系统会把文件的内存地址返回给浏览器。
- 浏览器拿到了文件的内存地址,通过地址访问内存,拿到数据。这时候数据是个
buffer[]或者说我们把内存start到start+file.length之间的内存页帧中 存储着文件的二进制数据加载到了缓冲区中。 - 但是现在的数据是二进制数据,没办法直接用。需要我们进行针对的处理。
- 这里参照浏览器平台的实现,创建一个dom对象。使用URL.createObjectURL()来吧buffer[]转换成url(注意处理时,需要指定file type)1。
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = () => {
const buffer = reader.result;
// 这里可以对 buffer 进行处理
console.log('ArrayBuffer:', buffer);
// 示例:将 ArrayBuffer 转换为 Uint8Array 并打印前 10 个字节
const uint8Array = new Uint8Array(buffer);
console.log('First 10 bytes:', uint8Array.slice(0, 10));
// 示例:如果是图片文件,可以将其显示出来
if (file.type.includes('image')) {
const blob = new Blob([buffer], { type: file.type });
const url = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = url;
output.appendChild(img);
}
};
reader.onerror = () => {
console.error('Error reading file:', reader.error);
};
}
});- 之后修改dom对象的数据属性和插入到dom tree太过简单,这里就不展开了。
为什么要指定file type
- 有朋友会很自然的说,你不指定,浏览器怎么知道是什么类型。
- 这话虽然没错,但是计算机中的一切都是人定义的,没有天经地义的东西。
- 完全可以在设计的时候指定文件u8[]的前十个字节存储文件类型。 为什么不呢?
文件为什么是无状态数据流
展开查看
点击展开答案...
Footnotes
-
这里说到底还是浏览器的实现太过粗糙,参照其他软件的设计,我们完全可以直接对u8[]进行处理而不需要转为url ↩