首页
/ MDN Web API 文件操作指南:在网页应用中处理本地文件

MDN Web API 文件操作指南:在网页应用中处理本地文件

2025-07-07 00:50:28作者:丁柯新Fawn

前言

在现代网页应用中,处理用户本地文件是一个常见需求。MDN Web API 提供了完整的文件操作接口,让开发者能够安全地访问用户选择的文件内容。本文将全面介绍如何使用这些 API 实现文件选择、预览和上传等功能。

基础文件选择

通过 input 元素获取文件

最简单的文件选择方式是使用 HTML 的 <input type="file"> 元素:

<input type="file" id="fileInput" multiple>

通过 JavaScript 可以访问用户选择的文件:

const fileInput = document.getElementById('fileInput');
const selectedFiles = fileInput.files; // 获取 FileList 对象

multiple 属性允许用户选择多个文件。每个文件都是一个 File 对象,包含以下重要属性:

  • name: 文件名(不包含路径)
  • size: 文件大小(字节)
  • type: 文件 MIME 类型

监听文件选择变化

可以监听 input 元素的 change 事件来实时获取文件:

fileInput.addEventListener('change', function(e) {
  const files = e.target.files;
  // 处理文件...
});

文件信息展示

计算文件总大小

以下示例展示如何计算并格式化多个文件的总大小:

function formatFileSize(bytes) {
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  let unitIndex = 0;
  
  while (bytes >= 1024 && unitIndex < units.length - 1) {
    bytes /= 1024;
    unitIndex++;
  }
  
  return `${bytes.toFixed(2)} ${units[unitIndex]}`;
}

const totalSize = Array.from(selectedFiles)
  .reduce((sum, file) => sum + file.size, 0);

console.log(`总大小: ${formatFileSize(totalSize)}`);

优化用户体验

自定义文件选择按钮

原生文件选择控件样式受限,可以通过以下方式美化:

<button id="customButton">选择文件</button>
<input type="file" id="hiddenInput" style="display:none">

<script>
document.getElementById('customButton').addEventListener('click', () => {
  document.getElementById('hiddenInput').click();
});
</script>

无障碍文件选择

对于无障碍访问,推荐使用 label 元素关联隐藏的 input:

<input type="file" id="fileInput" class="visually-hidden">
<label for="fileInput" class="custom-file-button">选择文件</label>

<style>
.visually-hidden {
  position: absolute;
  clip: rect(0 0 0 0);
  width: 1px;
  height: 1px;
  margin: -1px;
}
.custom-file-button {
  /* 自定义按钮样式 */
}
</style>

拖放文件操作

现代浏览器支持通过拖放 API 获取文件:

const dropZone = document.getElementById('dropZone');

dropZone.addEventListener('dragover', (e) => {
  e.preventDefault();
  e.stopPropagation();
  dropZone.classList.add('dragover');
});

dropZone.addEventListener('drop', (e) => {
  e.preventDefault();
  e.stopPropagation();
  dropZone.classList.remove('dragover');
  
  const files = e.dataTransfer.files;
  // 处理拖放的文件...
});

文件预览技术

图片预览实现

使用 FileReader API 可以实现图片预览:

function previewImage(file) {
  const reader = new FileReader();
  
  reader.onload = function(e) {
    const img = document.createElement('img');
    img.src = e.target.result;
    document.body.appendChild(img);
  };
  
  reader.readAsDataURL(file);
}

更高效的 Object URL 方案

对于大型文件,使用 Object URL 更高效:

function previewImage(file) {
  const img = document.createElement('img');
  img.src = URL.createObjectURL(file);
  
  img.onload = function() {
    URL.revokeObjectURL(this.src); // 释放内存
  };
  
  document.body.appendChild(img);
}

文件上传实践

基础文件上传

使用 XMLHttpRequest 上传文件:

function uploadFile(file) {
  const xhr = new XMLHttpRequest();
  const formData = new FormData();
  
  formData.append('file', file);
  
  xhr.open('POST', '/upload', true);
  
  xhr.upload.onprogress = function(e) {
    if (e.lengthComputable) {
      const percent = Math.round((e.loaded / e.total) * 100);
      console.log(`${percent}% 已上传`);
    }
  };
  
  xhr.onload = function() {
    if (xhr.status === 200) {
      console.log('上传成功');
    }
  };
  
  xhr.send(formData);
}

多文件上传队列

实现带进度显示的多文件上传:

class UploadQueue {
  constructor() {
    this.queue = [];
    this.activeUploads = 0;
    this.maxConcurrent = 3;
  }
  
  add(file) {
    this.queue.push(file);
    this.processQueue();
  }
  
  processQueue() {
    while (this.activeUploads < this.maxConcurrent && this.queue.length) {
      const file = this.queue.shift();
      this.upload(file);
      this.activeUploads++;
    }
  }
  
  upload(file) {
    const xhr = new XMLHttpRequest();
    const formData = new FormData();
    formData.append('file', file);
    
    xhr.open('POST', '/upload', true);
    
    xhr.upload.onprogress = (e) => {
      if (e.lengthComputable) {
        const percent = Math.round((e.loaded / e.total) * 100);
        this.updateProgress(file, percent);
      }
    };
    
    xhr.onload = () => {
      this.activeUploads--;
      this.processQueue();
    };
    
    xhr.send(formData);
  }
  
  updateProgress(file, percent) {
    console.log(`${file.name}: ${percent}%`);
  }
}

安全注意事项

  1. 始终验证文件类型,不要仅依赖文件扩展名或 MIME 类型
  2. 对上传文件大小设置合理限制
  3. 在服务器端进行二次验证
  4. 处理上传错误和中断情况
  5. 考虑使用 CSP 增加安全性

总结

MDN Web API 提供了完整的文件操作解决方案,从基础的文件选择到高级的拖放操作和上传管理。通过合理利用这些 API,开发者可以创建功能丰富且用户友好的文件处理功能。记住始终考虑性能和安全性,特别是在处理大型文件或多文件上传时。