一、文件上传
1、普通文件上传
JavaScript 可以使用表单提交来实现文件上传。首先,在 HTML 中创建一个文件输入框:
<input type="file" >
然后,在 JavaScript 中获取文件输入框的引用,并在其上设置事件监听器,如下所示:
var fileInput = ('fileInput');
('change', function () {
// 在这里处理选择的文件
});
在事件监听器中,可以使用 [0]
属性获取选择的文件,然后对文件进行处理。
接下来可以使用 XMLHttpRequest
或 fetch
API 来上传文件。
使用 XMLHttpRequest
:
var file = [0];
var formData = new FormData();
('file', file);
var xhr = new XMLHttpRequest();
('POST', 'url', true);
= function () {
if ( === 200) {
('upload success');
}
};
(formData);
使用 fetch
:
var file = [0];
var formData = new FormData();
('file', file);
fetch('url', {
method: 'POST',
body: formData
}).then(response => {
if () {
('upload success');
}
});
另外还可以使用第三方库如 axios
来实现文件上传,具体实现方法可以参考相关文档。
2、大文件上传
2.1、前端实现代码
在上传大文件时,通常采用分块上传的方式。将大文件分成若干个块,每块一个 HTTP 请求上传。
实现大文件上传的步骤如下:
- 用户选择文件。
- 将文件分成若干块。
- 对于每一块,向服务器发送 HTTP 请求上传。
- 服务器接收到文件块后,将其存储在服务器上。
- 在所有块上传完成后,服务器将所有块合并成一个完整的文件。
JavaScript 可以使用 File API(File 和 Blob 对象)来实现文件的读取和上传。
下面是一个使用 JavaScript 实现大文件上传的简单实例,使用分块上传的方法。
<input type="file" >
// 上传文件块
function uploadChunk(file, start, end, chunk) {
var xhr = new XMLHttpRequest();
('POST', '/upload', true);
('Content-Type', 'application/octet-stream');
('Content-Range', 'bytes ' + start + '-' + end + '/' + );
(chunk);
}
// 上传文件
function uploadFile(file) {
var chunkSize = 1 * 1024 * 1024; // 分块大小为1MB
var chunks = ( / chunkSize); // 计算分块数
var currentChunk = 0; // 当前分块
var start, end;
while (currentChunk < chunks) {
start = currentChunk * chunkSize;
end = start + chunkSize >= ? : start + chunkSize;
var chunk = (start, end);
uploadChunk(file, start, end, chunk);
currentChunk++;
}
}
// 监听文件选择事件
('file-input').addEventListener('change', function(e) {
var file = [0];
if (file) {
uploadFile(file);
}
});
在这个实例中,我们使用了 XMLHttpRequest 对象上传文件,并设置了 Content-Type 和 Content-Range 消息头。Content-Type 消息头表示上传的数据类型是二进制数据,Content-Range 消息头表示上传的文件块的范围。
在这个示例中,我们将文件分成若干块,每块大小为 1MB。我们使用 File API 中的 slice 方法截取文件块,并使用 XMLHttpRequest 将文件块上传到服务器。
注意,这只是一个简单的实例,代码仅供参考,在实际应用中还需要考在考虑以下几点:
- 如果服务器端支持断点续传,可以在服务器端记录已经上传的文件块,避免重复上传。
- 需要考虑如何处理上传失败的文件块,是否需要重试。
- 在上传过程中需要提供进度条,让用户了解上传进度。
- 在上传完成后需要有反馈,告知用户上传是否成功。
- 服务器端如何处理上传的文件块,将其合并成一个完整的文件。
- 服务器端存储空间的问题。可以使用分布式文件系统(如 HDFS)或云存储(如 Amazon S3)来存储上传的文件。
- 文件块上传顺序、文件块校验、断点续传等问题。
通过分块上传的方式,我们可以将大文件分成若干块上传,避免一次性上传大文件造成的超时或者内存不足的问题,同时也方便实现断点续传和上传进度的显示。
除了上面提到的方法外,还可以使用第三方库来实现大文件上传。常见的第三方库有:
- plupload
- fine-uploader
- tus-js-client
这些库都提供了文件分块、断点续传、上传进度等功能,可以让你更快捷地实现大文件上传。
不过要注意的是,使用第三方库可能会增加代码的复杂性和对第三方库的依赖。在选择使用第三方库时需要权衡其优缺点,并确保它满足你的需求。
2.2、后端实现代码
Java 后端代码示例:
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
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 (!(request)) {
(HttpServletResponse.SC_BAD_REQUEST, "Not a multipart request");
return;
}
ServletFileUpload upload = new ServletFileUpload();
try {
FileItemIterator iter = (request);
while (()) {
FileItemStream item = ();
if (!()) {
// 处理文件分块
processFilePart(item);
}
}
} catch (Exception e) {
();
}
}
private void processFilePart(FileItemStream item) throws Exception {
String index = ();
byte[] data = (());
(index, data);
// 如果所有分块都已经上传完成,合并所有分块并保存文件
if (isAllChunksUploaded()) {
// 合并所有分块并保存文件
mergeAndSaveFile("/path/");
}
}
private boolean isAllChunksUploaded() {
// 判断是否所有分块都已经上传完成
int totalChunks = getTotalChunks();
for (int i = 0; i < totalChunks; i++) {
if (!((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 = ((i));
(chunkData, 0, mergedFile, index, );
index += ;
}
saveFileToLocal(mergedFile, fileName);
}
private void saveFileToLocal(byte[] fileData, String filePath) throws Exception {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
(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 库,在运行该代码之前请确保已经引入了该库。该代码实现了分块上传的主要逻辑,包括存储分块数据,合并所有分块并保存文件,以及判断是否所有分块都已经上传。
请注意,上面的代码中的 getTotalChunks
和 getTotalFileSize
方法需要您自行实现。它们将分别用于获取总分块数和总文件大小,这些信息可以通过前端预先发送给后端或从数据库中查询获得。
关于文件上传需要了解的知识点:
- HTML5 文件上传
- 文件上传技术
- 文件上传安全性
- 分块上传
- 断点续传
- 云存储
二、文件下载
在 JavaScript 中实现文件下载,常见的方法如下:
1、使用 实现:通过更改当前页面的 URL 为文件下载地址,从而实现下载。
= 'file-download-url';
2、使用 a 标签实现:通过创建一个 a 标签并设置其 href 和 download 属性,从而实现下载。
var link = ("a");
= "filename";
= "file-download-url";
();
3、使用 fetch API 实现:通过使用 fetch API 获取文件内容,并将其写入 Blob 对象,最后利用 将其下载。
fetch('file-download-url')
.then(response => ())
.then(blob => {
const url = (blob);
const link = ('a');
= url;
= 'filename';
();
(url);
(link);
});