一、文件上傳
1、普通文件上傳
JavaScript 可以使用表單提交來(lái)實(shí)現(xiàn)文件上傳。首先,在 HTML 中創(chuàng)建一個(gè)文件輸入框:
<input type="file" id="fileInput">
?然后,在 JavaScript 中獲取文件輸入框的引用,并在其上設(shè)置事件監(jiān)聽(tīng)器,如下所示:
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function () {
// 在這里處理選擇的文件
});
?
在事件監(jiān)聽(tīng)器中,可以使用 fileInput.files[0]
屬性獲取選擇的文件,然后對(duì)文件進(jìn)行處理。
接下來(lái)可以使用 XMLHttpRequest
或 fetch
API 來(lái)上傳文件。
使用 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');
}
});
?
另外還可以使用第三方庫(kù)如 axios
來(lái)實(shí)現(xiàn)文件上傳,具體實(shí)現(xiàn)方法可以參考相關(guān)文檔。
2、大文件上傳
2.1、前端實(shí)現(xiàn)代碼
在上傳大文件時(shí),通常采用分塊上傳的方式。將大文件分成若干個(gè)塊,每塊一個(gè) HTTP 請(qǐng)求上傳。
實(shí)現(xiàn)大文件上傳的步驟如下:
- 用戶選擇文件。
- 將文件分成若干塊。
- 對(duì)于每一塊,向服務(wù)器發(fā)送 HTTP 請(qǐng)求上傳。
- 服務(wù)器接收到文件塊后,將其存儲(chǔ)在服務(wù)器上。
- 在所有塊上傳完成后,服務(wù)器將所有塊合并成一個(gè)完整的文件。
JavaScript 可以使用 File API(File 和 Blob 對(duì)象)來(lái)實(shí)現(xiàn)文件的讀取和上傳。
下面是一個(gè)使用 JavaScript 實(shí)現(xiàn)大文件上傳的簡(jiǎn)單實(shí)例,使用分塊上傳的方法。
<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); // 計(jì)算分塊數(shù)
var currentChunk = 0; // 當(dāng)前分塊
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++;
}
}
// 監(jiān)聽(tīng)文件選擇事件
document.getElementById('file-input').addEventListener('change', function(e) {
var file = e.target.files[0];
if (file) {
uploadFile(file);
}
});
在這個(gè)實(shí)例中,我們使用了 XMLHttpRequest 對(duì)象上傳文件,并設(shè)置了 Content-Type 和 Content-Range 消息頭。Content-Type 消息頭表示上傳的數(shù)據(jù)類型是二進(jìn)制數(shù)據(jù),Content-Range 消息頭表示上傳的文件塊的范圍。
在這個(gè)示例中,我們將文件分成若干塊,每塊大小為 1MB。我們使用 File API 中的 slice 方法截取文件塊,并使用 XMLHttpRequest 將文件塊上傳到服務(wù)器。
注意,這只是一個(gè)簡(jiǎn)單的實(shí)例,代碼僅供參考,在實(shí)際應(yīng)用中還需要考在考慮以下幾點(diǎn):
- 如果服務(wù)器端支持?jǐn)帱c(diǎn)續(xù)傳,可以在服務(wù)器端記錄已經(jīng)上傳的文件塊,避免重復(fù)上傳。
- 需要考慮如何處理上傳失敗的文件塊,是否需要重試。
- 在上傳過(guò)程中需要提供進(jìn)度條,讓用戶了解上傳進(jìn)度。
- 在上傳完成后需要有反饋,告知用戶上傳是否成功。
- 服務(wù)器端如何處理上傳的文件塊,將其合并成一個(gè)完整的文件。
- 服務(wù)器端存儲(chǔ)空間的問(wèn)題??梢允褂梅植际轿募到y(tǒng)(如 HDFS)或云存儲(chǔ)(如 Amazon S3)來(lái)存儲(chǔ)上傳的文件。
- 文件塊上傳順序、文件塊校驗(yàn)、斷點(diǎn)續(xù)傳等問(wèn)題。
通過(guò)分塊上傳的方式,我們可以將大文件分成若干塊上傳,避免一次性上傳大文件造成的超時(shí)或者內(nèi)存不足的問(wèn)題,同時(shí)也方便實(shí)現(xiàn)斷點(diǎn)續(xù)傳和上傳進(jìn)度的顯示。
除了上面提到的方法外,還可以使用第三方庫(kù)來(lái)實(shí)現(xiàn)大文件上傳。常見(jiàn)的第三方庫(kù)有:
- resumable.js
- plupload
- fine-uploader
- tus-js-client
這些庫(kù)都提供了文件分塊、斷點(diǎn)續(xù)傳、上傳進(jìn)度等功能,可以讓你更快捷地實(shí)現(xiàn)大文件上傳。
不過(guò)要注意的是,使用第三方庫(kù)可能會(huì)增加代碼的復(fù)雜性和對(duì)第三方庫(kù)的依賴。在選擇使用第三方庫(kù)時(shí)需要權(quán)衡其優(yōu)缺點(diǎn),并確保它滿足你的需求。
2.2、后端實(shí)現(xiàn)代碼
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;
// 保存所有分塊數(shù)據(jù),使用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);
// 如果所有分塊都已經(jīng)上傳完成,合并所有分塊并保存文件
if (isAllChunksUploaded()) {
// 合并所有分塊并保存文件
mergeAndSaveFile("/path/filename.suffix");
}
}
private boolean isAllChunksUploaded() {
// 判斷是否所有分塊都已經(jīng)上傳完成
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;
}
}
?
這只是一個(gè)示例代碼,不是完整的項(xiàng)目。該代碼使用了 Apache Commons FileUpload 庫(kù),在運(yùn)行該代碼之前請(qǐng)確保已經(jīng)引入了該庫(kù)。該代碼實(shí)現(xiàn)了分塊上傳的主要邏輯,包括存儲(chǔ)分塊數(shù)據(jù),合并所有分塊并保存文件,以及判斷是否所有分塊都已經(jīng)上傳。
請(qǐng)注意,上面的代碼中的 getTotalChunks
和 getTotalFileSize
方法需要您自行實(shí)現(xiàn)。它們將分別用于獲取總分塊數(shù)和總文件大小,這些信息可以通過(guò)前端預(yù)先發(fā)送給后端或從數(shù)據(jù)庫(kù)中查詢獲得。
關(guān)于文件上傳需要了解的知識(shí)點(diǎn):
- HTML5 文件上傳
- 文件上傳技術(shù)
- 文件上傳安全性
- 分塊上傳
- 斷點(diǎn)續(xù)傳
- 云存儲(chǔ)
二、文件下載
在 JavaScript 中實(shí)現(xiàn)文件下載,常見(jiàn)的方法如下:
1、使用 window.location 實(shí)現(xiàn):通過(guò)更改當(dāng)前頁(yè)面的 URL 為文件下載地址,從而實(shí)現(xiàn)下載。
window.location = 'file-download-url';
?2、使用 a 標(biāo)簽實(shí)現(xiàn):通過(guò)創(chuàng)建一個(gè) a 標(biāo)簽并設(shè)置其 href 和 download 屬性,從而實(shí)現(xiàn)下載。
var link = document.createElement("a");
link.download = "filename";
link.href = "file-download-url";
link.click();
?3、使用 fetch API 實(shí)現(xiàn):通過(guò)使用 fetch API 獲取文件內(nèi)容,并將其寫(xiě)入 Blob 對(duì)象,最后利用 URL.createObjectURL 將其下載。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-458859.html
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);
});
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-458859.html
到了這里,關(guān)于用JavaScript實(shí)現(xiàn)文件的上傳與下載的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!