使用 JavaScript 读取文件

在用户本地设备上选择文件并与之互动是 最常用的网络功能它允许用户选择文件和 将其上传到服务器,例如在分享照片或提交税费信息时 文档。它还允许网站无需 通过网络传输数据本页将介绍如何使用 与文件交互的 JavaScript。

现代 File System Access API

File System Access API 提供了一种在文件内读写文件的方法, 用户本地系统上的目录。适用于大多数基于 Chromium 的 例如 Chrome 和 Edge。如需了解详情,请参阅 File System Access API

File System Access API 并非与所有浏览器都兼容 建议使用 browser-fs-access 帮助程序库,该库在适用情况下使用新的 API,并且 需要重新采用旧方法。

以传统方式处理文件

本指南将向您介绍如何使用旧版 JavaScript 方法与文件交互。

选择文件

选择文件主要有以下两种方式: HTML 输入元素,并使用 拖放区域

HTML 输入元素

用户选择文件的最简单方法是使用 <input type="file"> 元素,所有主流浏览器都支持这种样式。点击后,用户可以 选择一个或多个文件 multiple 属性。 界面。当用户选择完一个或多个文件后,元素的 change 事件触发。您可以从event.target.files访问文件列表, 是 FileList 对象。 FileList 中的每一项都是一个 File 对象。

<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
  const fileSelector = document.getElementById('file-selector');
  fileSelector.addEventListener('change', (event) => {
    const fileList = event.target.files;
    console.log(fileList);
  });
</script>

以下示例可让用户使用 系统内置文件选择界面,然后将每个选定文件记录到 控制台。

限制用户可以选择的文件类型

在某些情况下,您可能希望限制用户可以选择的文件类型。对于 例如,图片编辑应用应仅接受图片,而不接受文本文件。设置 文件类型限制、添加 accept 属性指定系统接受的文件类型:

<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">

自定义拖放

在某些浏览器中,<input type="file"> 元素也是拖放目标, 让用户能够将文件拖放到您的应用中。不过,这个拖放目标 体积较小,可能难以使用。相反,在您使用 <input type="file"> 元素,您可以提供一个大型自定义拖放 。

选择送餐区

拖放 surface 取决于应用的设计。您可能只想使用 将部分窗口设置为落下表面,但您也可以使用整个窗口。

<ph type="x-smartling-placeholder">
</ph> Squoosh(一款图像压缩 Web 应用)的屏幕截图。 <ph type="x-smartling-placeholder">
</ph> Squoosh 将整个窗口变成落差区。

通过图片压缩应用 Squoosh,用户可以将图片拖动到 窗口,然后点击 select an image 以调用 <input type="file"> 元素。无论您选择什么作为放置区域,都要确保用户清楚知道 将文件拖动到该表面上。

定义拖放区

要将某个元素启用为拖放区域,请为 两个事件:dragoverdropdragover 事件会更新浏览器界面,以直观地指示 即可创建文件的副本drop 事件会触发 当用户将文件拖放到界面上后。与输入元素一样, 可以访问 event.dataTransfer.files 中的文件列表,该文件是 FileList 对象。每个 FileList 中的项是 File 对象。

const dropArea = document.getElementById('drop-area');

dropArea.addEventListener('dragover', (event) => {
  event.stopPropagation();
  event.preventDefault();
  // Style the drag-and-drop as a "copy file" operation.
  event.dataTransfer.dropEffect = 'copy';
});

dropArea.addEventListener('drop', (event) => {
  event.stopPropagation();
  event.preventDefault();
  const fileList = event.dataTransfer.files;
  console.log(fileList);
});

event.stopPropagation()event.preventDefault() 停止浏览器的默认行为,让代码运行。如果没有它们, 否则浏览器就会离开您的网页并打开这些文件 进入浏览器窗口的用户

如需查看现场演示,请参阅自定义拖放

那目录呢?

遗憾的是,使用 JavaScript 访问目录并没有一种好方法。

webkitdirectory <input type="file"> 元素上的属性可让用户选择目录, 或目录大多数主流浏览器都支持 但 Android 版 Firefox 和 iOS 版 Safari 除外。

如果启用了拖放功能,用户可能会尝试将某个目录拖到 放置区域当拖放事件触发时,它会为File 目录,但不提供对该目录中任何文件的访问权限。

读取文件元数据

File 对象包含有关文件的元数据。大多数浏览器 文件名、文件大小和 MIME 类型 不同的浏览器可能会提供不同或额外的 信息。

function getMetadataForFileList(fileList) {
  for (const file of fileList) {
    // Not supported in Safari for iOS.
    const name = file.name ? file.name : 'NOT SUPPORTED';
    // Not supported in Firefox for Android or Opera for Android.
    const type = file.type ? file.type : 'NOT SUPPORTED';
    // Unknown cross-browser support.
    const size = file.size ? file.size : 'NOT SUPPORTED';
    console.log({file, name, type, size});
  }
}

您可以在 input-type-file 中查看实际操作示例。 演示。

读取文件的内容

使用 FileReader 执行以下操作: 将 File 对象的内容读取到内存中。您可以让FileReader执行以下操作: 将文件读取为数组缓冲区数据网址; 或文本

function readImage(file) {
  // Check if the file is an image.
  if (file.type && !file.type.startsWith('image/')) {
    console.log('File is not an image.', file.type, file);
    return;
  }

  const reader = new FileReader();
  reader.addEventListener('load', (event) => {
    img.src = event.target.result;
  });
  reader.readAsDataURL(file);
}

此示例会读取用户提供的 File,然后将其转换为数据 网址,并使用该数据网址在 img 元素中显示图片。 要了解如何验证用户是否已选择图片文件,请参阅 read-image-file 演示。

监控文件读取进度

读取大型文件时,提供一些用户体验告诉用户会很有帮助 读取的进度为此,请使用 progress 事件,由 FileReader 提供。progress 事件有两个属性: loaded(读取量)和 total(读取量)。

function readFile(file) {
  const reader = new FileReader();
  reader.addEventListener('load', (event) => {
    const result = event.target.result;
    // Do something with result
  });

  reader.addEventListener('progress', (event) => {
    if (event.loaded && event.total) {
      const percent = (event.loaded / event.total) * 100;
      console.log(`Progress: ${Math.round(percent)}`);
    }
  });
  reader.readAsDataURL(file);
}

Vincent Botta 的主打图片,来自 Unspin