JavaScript 文件上传与下载

  • JavaScript 文件上传与下载已关闭评论
  • 83 次浏览
  • A+
所属分类:Web前端
摘要

一、文件上传 1、普通文件上传 JavaScript 可以使用表单提交来实现文件上传。首先,在 HTML 中创建一个文件输入框:

一、文件上传

1、普通文件上传

JavaScript 可以使用表单提交来实现文件上传。首先,在 HTML 中创建一个文件输入框:

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

然后,在 JavaScript 中获取文件输入框的引用,并在其上设置事件监听器,如下所示:

var fileInput = document.getElementById('fileInput'); fileInput.addEventListener('change', function () {   // 在这里处理选择的文件 });

在事件监听器中,可以使用 fileInput.files[0] 属性获取选择的文件,然后对文件进行处理。

接下来可以使用 XMLHttpRequestfetch API 来上传文件。

使用 XMLHttpRequest

var file = fileInput.files[0]; var formData = new FormData(); formData.append('file', file);  var xhr = new XMLHttpRequest(); xhr.open('POST', 'url', true); xhr.onload = function () {   if (xhr.status === 200) {     console.log('upload success');   } }; xhr.send(formData);

使用 fetch

var file = fileInput.files[0]; var formData = new FormData(); formData.append('file', file);  fetch('url', {   method: 'POST',   body: formData }).then(response => {   if (response.ok) {     console.log('upload success');   } });

另外还可以使用第三方库如 axios 来实现文件上传,具体实现方法可以参考相关文档。

2、大文件上传

2.1、前端实现代码

在上传大文件时,通常采用分块上传的方式。将大文件分成若干个块,每块一个 HTTP 请求上传。

实现大文件上传的步骤如下:

  1. 用户选择文件。
  2. 将文件分成若干块。
  3. 对于每一块,向服务器发送 HTTP 请求上传。
  4. 服务器接收到文件块后,将其存储在服务器上。
  5. 在所有块上传完成后,服务器将所有块合并成一个完整的文件。

JavaScript 可以使用 File API(File 和 Blob 对象)来实现文件的读取和上传。

下面是一个使用 JavaScript 实现大文件上传的简单实例,使用分块上传的方法。

<input type="file" id="file-input">

 

// 上传文件块 function uploadChunk(file, start, end, chunk) {     var xhr = new XMLHttpRequest();     xhr.open('POST', '/upload', true);     xhr.setRequestHeader('Content-Type', 'application/octet-stream');     xhr.setRequestHeader('Content-Range', 'bytes ' + start + '-' + end + '/' + file.size);     xhr.send(chunk); }  // 上传文件 function uploadFile(file) {     var chunkSize = 1 * 1024 * 1024; // 分块大小为1MB     var chunks = Math.ceil(file.size / chunkSize); // 计算分块数     var currentChunk = 0; // 当前分块     var start, end;     while (currentChunk < chunks) {         start = currentChunk * chunkSize;         end = start + chunkSize >= file.size ? file.size : start + chunkSize;         var chunk = file.slice(start, end);         uploadChunk(file, start, end, chunk);         currentChunk++;     } }  // 监听文件选择事件 document.getElementById('file-input').addEventListener('change', function(e) {     var file = e.target.files[0];     if (file) {         uploadFile(file);     } });

在这个实例中,我们使用了 XMLHttpRequest 对象上传文件,并设置了 Content-Type 和 Content-Range 消息头。Content-Type 消息头表示上传的数据类型是二进制数据,Content-Range 消息头表示上传的文件块的范围。

在这个示例中,我们将文件分成若干块,每块大小为 1MB。我们使用 File API 中的 slice 方法截取文件块,并使用 XMLHttpRequest 将文件块上传到服务器。

注意,这只是一个简单的实例,代码仅供参考,在实际应用中还需要考在考虑以下几点:

  • 如果服务器端支持断点续传,可以在服务器端记录已经上传的文件块,避免重复上传。
  • 需要考虑如何处理上传失败的文件块,是否需要重试。
  • 在上传过程中需要提供进度条,让用户了解上传进度。
  • 在上传完成后需要有反馈,告知用户上传是否成功。
  • 服务器端如何处理上传的文件块,将其合并成一个完整的文件。
  • 服务器端存储空间的问题。可以使用分布式文件系统(如 HDFS)或云存储(如 Amazon S3)来存储上传的文件。
  • 文件块上传顺序、文件块校验、断点续传等问题。

通过分块上传的方式,我们可以将大文件分成若干块上传,避免一次性上传大文件造成的超时或者内存不足的问题,同时也方便实现断点续传和上传进度的显示。

除了上面提到的方法外,还可以使用第三方库来实现大文件上传。常见的第三方库有:

  • resumable.js
  • plupload
  • fine-uploader
  • tus-js-client

这些库都提供了文件分块、断点续传、上传进度等功能,可以让你更快捷地实现大文件上传。

不过要注意的是,使用第三方库可能会增加代码的复杂性和对第三方库的依赖。在选择使用第三方库时需要权衡其优缺点,并确保它满足你的需求。

2.2、后端实现代码

Java 后端代码示例:

import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap;  import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;  import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.IOUtils;  public class FileUploadServlet extends HttpServlet {     private static final long serialVersionUID = 1L;      // 保存所有分块数据,使用ConcurrentHashMap保证线程安全     private Map<String, byte[]> chunks = new ConcurrentHashMap<>();      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         if (!ServletFileUpload.isMultipartContent(request)) {             response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Not a multipart request");             return;         }          ServletFileUpload upload = new ServletFileUpload();         try {             FileItemIterator iter = upload.getItemIterator(request);             while (iter.hasNext()) {                 FileItemStream item = iter.next();                 if (!item.isFormField()) {                     // 处理文件分块                     processFilePart(item);                 }             }         } catch (Exception e) {             e.printStackTrace();         }     }      private void processFilePart(FileItemStream item) throws Exception {         String index = item.getFieldName();         byte[] data = IOUtils.toByteArray(item.openStream());         chunks.put(index, data);          // 如果所有分块都已经上传完成,合并所有分块并保存文件         if (isAllChunksUploaded()) {             // 合并所有分块并保存文件             mergeAndSaveFile("/path/filename.suffix");         }     }      private boolean isAllChunksUploaded() {         // 判断是否所有分块都已经上传完成         int totalChunks = getTotalChunks();         for (int i = 0; i < totalChunks; i++) {             if (!chunks.containsKey(String.valueOf(i))) {                 return false;             }         }         return true;     }          public void mergeAndSaveFile(String fileName) throws Exception {         int totalChunks = getTotalChunks();         int totalFileSize = getTotalFileSize();         byte[] mergedFile = new byte[totalFileSize];         int index = 0;         for (int i = 0; i < totalChunks; i++) {             byte[] chunkData = chunks.get(String.valueOf(i));             System.arraycopy(chunkData, 0, mergedFile, index, chunkData.length);             index += chunkData.length;         }         saveFileToLocal(mergedFile, fileName);     }          private void saveFileToLocal(byte[] fileData, String filePath) throws Exception {         try (FileOutputStream fos = new FileOutputStream(filePath)) {             fos.write(fileData);         }     }      private int getTotalChunks() {         // You need to implement this method         return 0;     }      private int getTotalFileSize() {         // You need to implement this method         return 0;     } }

这只是一个示例代码,不是完整的项目。该代码使用了 Apache Commons FileUpload 库,在运行该代码之前请确保已经引入了该库。该代码实现了分块上传的主要逻辑,包括存储分块数据,合并所有分块并保存文件,以及判断是否所有分块都已经上传。

请注意,上面的代码中的 getTotalChunksgetTotalFileSize 方法需要您自行实现。它们将分别用于获取总分块数和总文件大小,这些信息可以通过前端预先发送给后端或从数据库中查询获得。

 

关于文件上传需要了解的知识点:

  • HTML5 文件上传
  • 文件上传技术
  • 文件上传安全性
  • 分块上传
  • 断点续传
  • 云存储

二、文件下载

在 JavaScript 中实现文件下载,常见的方法如下:

1、使用 window.location 实现:通过更改当前页面的 URL 为文件下载地址,从而实现下载。

window.location = 'file-download-url';

2、使用 a 标签实现:通过创建一个 a 标签并设置其 href 和 download 属性,从而实现下载。

var link = document.createElement("a"); link.download = "filename"; link.href = "file-download-url"; link.click();

3、使用 fetch API 实现:通过使用 fetch API 获取文件内容,并将其写入 Blob 对象,最后利用 URL.createObjectURL 将其下载。

fetch('file-download-url')   .then(response => response.blob())   .then(blob => {     const url = URL.createObjectURL(blob);     const link = document.createElement('a');     link.href = url;     link.download = 'filename';     link.click();     URL.revokeObjectURL(url);     document.body.removeChild(link);   });