React實現(xiàn)文件分片上傳和下載的方法詳解
前言
在當今的前端開發(fā)中,處理文件流操作已經(jīng)成為一個常見的需求。無論是上傳、下載、讀取、展示還是其他的文件處理操作,都需要高效且可靠地處理二進制數(shù)據(jù)。而隨著文件大小的增加和網(wǎng)絡傳輸?shù)南拗?,文件分片上傳和下載逐漸成為了提升性能和用戶體驗的必備技術。
文件分片上傳和下載通過將大文件拆分成多個小片段,以及利用斷點續(xù)傳的特性,使得文件的傳輸更為可靠和高效。在這個過程中,前端開發(fā)者需要熟悉 Blob 對象和 ArrayBuffer,這些工具可以幫助我們處理和操控二進制數(shù)據(jù)。而使用 React 框架可以更加方便地管理和操作文件對象,并輕松實現(xiàn)文件的分片上傳和下載功能。
本文將深入探討如何使用 React 實現(xiàn)文件分片上傳和下載,并介紹相關的基本概念和技術。我們將重點關注如何有效地處理文件的二進制數(shù)據(jù),以及如何利用文件流操作優(yōu)化前端開發(fā)中的文件處理任務。通過學習本文,您將能夠掌握一套高效處理文件流操作的方法,為您的前端開發(fā)工作提供更好的解決方案。讓我們一起開始探索吧!

文件傳輸是一個常見的需求。對于大文件的下載和上傳,直接使用傳統(tǒng)的方式可能會遇到性能和用戶體驗方面的問題。
幸運的是,前端技術提供了一些高效的解決方案:文件流操作和切片下載與上傳。本文將深入探討這些技術,幫助你理解它們的原理和實現(xiàn)方法,以優(yōu)化文件傳輸效率和提升用戶體驗。
一、前端文件流操作
在前端開發(fā)中,文件流操作是指通過數(shù)據(jù)流的方式處理文件,對文件進行讀取 、 寫入和展示等操作。下面詳細介紹了前端文件流操作的幾個基本概念和技術。
數(shù)據(jù)流和文件處理的基本概念
數(shù)據(jù)流是指連 續(xù)的數(shù)據(jù)序列 ,可以從一個源傳輸?shù)搅硪粋€目的地。在前端開發(fā)中,文件可以被看作數(shù)據(jù)流的一種形式,可以通過數(shù)據(jù)流的方式進行處理。 文件處理涉及讀取和寫入文件的操作,包括讀取文件的內容、寫入數(shù)據(jù)到文件,以及對文件進行刪除、重命名等操作。
Blob 對象和 ArrayBuffer:處理二進制數(shù)據(jù)
在前端處理文件時,經(jīng)常需要處理二進制數(shù)據(jù)。 Blob (Binary Large Object)對象是用來表示二進制數(shù)據(jù)的一個接口,可以存儲大量的二進制數(shù)據(jù)。Blob 對象可以通過構造函數(shù)進行創(chuàng)建,也可以通過其他 API 生成,例如通過 FormData 對象獲取上傳的文件。 而 ArrayBuffer 是 JavaScript 中的一個對象類型,用于表示一個通用的、固定長度的二進制數(shù)據(jù)緩沖區(qū)。我們可以通過 ArrayBuffer 來操作和處理文件的二進制數(shù)據(jù)。
代碼如下:
import React, { useState } from 'react';
function FileInput() {
const [fileContent, setFileContent] = useState('');
// 讀取文件內容到ArrayBuffer
function readFileToArrayBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
// 注冊文件讀取完成后的回調函數(shù)
reader.onload = function(event) {
const arrayBuffer = event.target.result;
resolve(arrayBuffer);
};
// 讀取文件內容到ArrayBuffer
reader.readAsArrayBuffer(file);
});
}
// 將ArrayBuffer轉為十六進制字符串
function arrayBufferToHexString(arrayBuffer) {
const uint8Array = new Uint8Array(arrayBuffer);
let hexString = '';
for (let i = 0; i < uint8Array.length; i++) {
const hex = uint8Array[i].toString(16).padStart(2, '0');
hexString += hex;
}
return hexString;
}
// 處理文件選擇事件
function handleFileChange(event) {
const file = event.target.files[0]; // 獲取選中的文件
if (file) {
readFileToArrayBuffer(file)
.then(arrayBuffer => {
const hexString = arrayBufferToHexString(arrayBuffer);
setFileContent(hexString);
})
.catch(error => {
console.error('文件讀取失敗:', error);
});
} else {
setFileContent('請選擇一個文件');
}
}
return (
<div>
<input type="file" onChange={handleFileChange} />
<div>
<h4>文件內容:</h4>
<pre>{fileContent}</pre>
</div>
</div>
);
}
export default FileInput;
上面代碼里,我們創(chuàng)建了一個名為FileInput的函數(shù)式組件。該組件包含一個文件選擇框和一個用于顯示文件內容的<pre>元素。當用戶選擇文件時,通過 FileReader 將文件內容讀取為ArrayBuffer,然后將ArrayBuffer轉換為十六進制字符串,并將結果顯示在頁面上。
使用 FileReader 進行文件讀取
FileReader是前端瀏覽器提供的一個 API,用于讀取文件內容。通過 FileReader,我們可以通過異步方式讀取文件,并將文件內容轉換為可用的數(shù)據(jù)形式,比如文本數(shù)據(jù)或二進制數(shù)據(jù)。 FileReader 提供了一些讀取文件的方法,例如 readAsText()、readAsArrayBuffer()等,可以根據(jù)需要選擇合適的方法來讀取文件內容。
將文件流展示在前端頁面中
一旦我們成功地讀取了文件的內容,就可以將文件流展示在前端頁面上。具體的展示方式取決于文件的類型。例如,對于文本文件,可以直接將其內容顯示在頁面的文本框或區(qū)域中;對于圖片文件,可以使用
<img>標簽展示圖片;對于音視頻文件,可以使用<video>或<audio>標簽來播放。 通過將文件流展示在前端頁面上,我們可以實現(xiàn)在線預覽和查看文件內容的功能。
好的,這一部分就基本介紹完畢,總結一下。前端文件操作流是處理
大型文件的一種常見方式,他可以通過數(shù)據(jù)流的方式對文件進行操作。Blob對象 和ArrayBuffer是處理二進制數(shù)據(jù)的重要工具。而FileReader則是讀取文件內容的的關鍵組件。通過這些技術,我們可以方便的在前端頁面上進行操作或者文件展示。
二、文件切片下載
這一步就進入到我們今天文章主題了,先來主要的看下流程
graph LR
A(開始) --> B{選擇文件}
B -- 用戶選擇文件 --> C[切割文件為多個切片]
C --> D{上傳切片}
D -- 上傳完成 --> E[合并切片為完整文件]
E -- 文件合并完成 --> F(上傳成功)
D -- 上傳中斷 --> G{保存上傳進度}
G -- 上傳恢復 --> D
G -- 取消上傳 --> H(上傳取消)傳統(tǒng)文件下載的性能問題
文件切片下載是一種提升文件下載效率的技術,通過將大文件分割成多個小片段(切片),并使用多個并發(fā)請求同時下載這些切片,從而加快整體下載速度。
傳統(tǒng)的文件下載方式對于大文件來說存在性能問題。當用戶請求下載一個大文件時,服務器需要將整個文件發(fā)送給客戶端。這會導致以下幾個問題:
較長的等待時間:大文件需要較長的時間來傳輸?shù)娇蛻舳耍脩粜枰却荛L時間才能開始使用文件。
網(wǎng)絡阻塞:由于下載過程中占用了網(wǎng)絡帶寬,其他用戶可能會遇到下載速度慢的問題。
斷點續(xù)傳困難:如果下載過程中出現(xiàn)網(wǎng)絡故障或者用戶中斷下載,需要重新下載整個文件,無法繼續(xù)之前的下載進度。
利用文件切片提升下載效率

文件切片下載通過將文件分割成多個小片段,每個片段大小通常在幾百KB到幾MB之間。然后客戶端通過多個并發(fā)請求同時下載這些片段。這樣做的好處是:
快速啟動:客戶端可以快速開始下載,因為只需要下載第一個切片即可。
并發(fā)下載:通過使用多個并發(fā)請求下載切片,可以充分利用帶寬,并提高整體下載速度。
斷點續(xù)傳:如果下載中斷,客戶端只需要重新下載中斷的切片,而不需要重新下載整個文件。
切片上傳代碼示例:
const [selectedFile, setSelectedFile] = useState(null);
const [progress, setProgress] = useState(0);
// 處理文件選擇事件
function handleFileChange(event) {
setSelectedFile(event.target.files[0]);
}
// 處理文件上傳事件
function handleFileUpload() {
if (selectedFile) {
// 計算切片數(shù)量和每個切片的大小
const fileSize = selectedFile.size;
const chunkSize = 1024 * 1024; // 設置切片大小為1MB
const totalChunks = Math.ceil(fileSize / chunkSize);
// 創(chuàng)建FormData對象,并添加文件信息
const formData = new FormData();
formData.append('file', selectedFile);
formData.append('totalChunks', totalChunks);
// 循環(huán)上傳切片
for (let chunkNumber = 0; chunkNumber < totalChunks; chunkNumber++) {
const start = chunkNumber * chunkSize;
const end = Math.min(start + chunkSize, fileSize);
const chunk = selectedFile.slice(start, end);
formData.append(`chunk-${chunkNumber}`, chunk, selectedFile.name);
}
// 發(fā)起文件上傳請求
axios.post('/upload', formData, {
onUploadProgress: progressEvent => {
const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
setProgress(progress);
}
})
.then(response => {
console.log('文件上傳成功:', response.data);
})
.catch(error => {
console.error('文件上傳失敗:', error);
});
}
}當涉及到切片上傳和下載時,前端使用的技術通常是基于前端庫或框架提供的文件處理功能,結合后端服務實現(xiàn)。
上面代碼里我們提到了文件如何切片上傳。
- 當用戶選擇文件后,通過 handleFileChange 函數(shù)處理文件選擇事件,將選擇的文件保存在 selectedFile 狀態(tài)中。
- 當用戶點擊上傳按鈕時,通過 handleFileUpload 函數(shù)處理文件上傳事件。
- 在 handleFileUpload 函數(shù)中,計算切片數(shù)量和每個切片的大小,并創(chuàng)建一個FormData對象用于存儲文件信息和切片數(shù)據(jù)。
實現(xiàn)客戶端切片下載的方案
實現(xiàn)客戶端切片下載的基本方案如下:
- 服務器端將大文件切割成多個切片,并為每個切片生成唯一的標識符。
- 客戶端發(fā)送請求獲取切片列表,同時開始下載第一個切片。
- 客戶端在下載過程中,根據(jù)切片列表發(fā)起并發(fā)請求下載其他切片,并逐漸拼接合并下載的數(shù)據(jù)。
- 當所有切片都下載完成后,客戶端將下載的數(shù)據(jù)合并為完整的文件。
代碼示例:
function downloadFile() {
// 發(fā)起文件下載請求
fetch('/download', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(data => {
const totalSize = data.totalSize;
const totalChunks = data.totalChunks;
let downloadedChunks = 0;
let chunks = [];
// 下載每個切片
for (let chunkNumber = 0; chunkNumber < totalChunks; chunkNumber++) {
fetch(`/download/${chunkNumber}`, {
method: 'GET',
})
.then(response => response.blob())
.then(chunk => {
downloadedChunks++;
chunks.push(chunk);
// 當所有切片都下載完成時
if (downloadedChunks === totalChunks) {
// 合并切片
const mergedBlob = new Blob(chunks);
// 創(chuàng)建對象 URL,生成下載鏈接
const downloadUrl = window.URL.createObjectURL(mergedBlob);
// 創(chuàng)建 <a> 元素并設置屬性
const link = document.createElement('a');
link.href = downloadUrl;
link.setAttribute('download', 'file.txt');
// 模擬點擊下載
link.click();
// 釋放資源
window.URL.revokeObjectURL(downloadUrl);
}
});
}
})
.catch(error => {
console.error('文件下載失敗:', error);
});
}
我們看下代碼,首先使用 BLOB 對象創(chuàng)建一共對象URL,用于生成下載連接,然后創(chuàng)建 a 標簽并且設置 href 的屬性為剛剛創(chuàng)建的對象URL,繼續(xù)設置 a 標簽的 download 屬性是文件名,方便點擊的時候自動下載文件。
顯示下載進度和完成狀態(tài)
為了顯示下載進度和完成狀態(tài),可以在客戶端實現(xiàn)以下功能:
- 顯示進度條:客戶端可以通過監(jiān)聽每個切片的下載進度來計算整體下載進度,并實時更新進度條的顯示。
- 顯示完成狀態(tài):當所有切片都下載完成后,客戶端可以顯示下載完成的狀態(tài),例如顯示一個完成的圖標或者文本。
這里我們可以繼續(xù)接著切片上傳代碼示例里的繼續(xù)寫。
代碼示例:
// 處理文件下載事件
function handleFileDownload() {
axios.get('/download', {
responseType: 'blob',
onDownloadProgress: progressEvent => {
const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
setProgress(progress);
}
})
.then(response => {
// 創(chuàng)建一個臨時的URL對象用于下載
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.txt');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch(error => {
console.error('文件下載失敗:', error);
});
}
<button onClick={handleFileDownload}>下載文件</button>
<div>進度:{progress}%</div>當用戶點擊下載按鈕時,通過 handleFileDownload 函數(shù)處理文件下載事件。
在 handleFileDownload 函數(shù)中,使用 axios 庫發(fā)起文件下載請求,并設置 responseType: 'blob' 表示返回二進制數(shù)據(jù)。
通過監(jiān)聽 onDownloadProgress 屬性獲取下載進度,并更新進度條的顯示。
下載完成后,創(chuàng)建一個臨時的 URL 對象用于下載,并通過動態(tài)創(chuàng)建 <a> 元素模擬點擊下載。
三、大文件上傳的問題與解決方案
傳統(tǒng)的文件上傳方式存在的問題
大文件上傳耗時長,容易導致請求超時。
占用服務器和網(wǎng)絡帶寬資源,可能影響其他用戶的訪問速度。
如果上傳中斷,需要重新上傳整個文件,效率低下。
難以實現(xiàn)上傳進度的顯示和控制。
前端文件切片上傳的優(yōu)勢
將大文件分割為更小的文件切片,分多次上傳,提高上傳效率和穩(wěn)定性。
提供上傳進度的監(jiān)控和展示,提高用戶體驗。
充分利用瀏覽器的并發(fā)上傳能力,減輕服務器負擔。
實現(xiàn)斷點續(xù)傳功能,避免重復上傳已上傳的部分。
實現(xiàn)前端切片上傳的方法
- 使用 JavaScript 的 `File API` 獲取文件對象,并使用 `Blob.prototype.slice()` 方法將文件切割為多個切片。
- 使用
FormData對象將切片數(shù)據(jù)通過 AJAX 或 Fetch API 發(fā)送到服務器。 - 在后端服務器上接收切片并保存到臨時存儲中,等待后續(xù)合并。
- 在客戶端通過監(jiān)聽上傳進度事件,在進度條或提示中展示上傳進度。
代碼示例
const [file, setFile] = useState(null); //用來存放我本地上傳的文件
const chunkSize = 1024 * 1024; // 1MB 切片大小
const upload = () => {
if (!file) {
alert("請選擇要上傳的文件!");
return;
}
const chunkSize = 1024 * 1024; // 1MB
let start = 0;
let end = Math.min(chunkSize, file.size);
while (start < file.size) {
const chunk = file.slice(start, end);
// 創(chuàng)建FormData對象
const formData = new FormData();
formData.append('file', chunk);
// 發(fā)送切片到服務器
fetch('上傳接口xxxx', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
console.log(data);
// 處理響應結果
})
.catch(error => {
console.error(error);
// 處理錯誤
});
start = end;
end = Math.min(start + chunkSize, file.size);
}
};
return (
<div>
<input type="file" onChange={handleFileChange} />
<button onClick={upload}>上傳</button>
</div>
);
}在上面的代碼中,創(chuàng)建了一個名為 Upload 的函數(shù)組件。它使用了 React 的 useState 鉤子來管理選中的文件。
通過 onChange 事件監(jiān)聽文件輸入框的變化,并在 handleFileChange 函數(shù)中獲取選擇的文件,并更新 file 狀態(tài)。
點擊“上傳”按鈕時,調用 upload 函數(shù)。它與之前的示例代碼類似,將文件切割為多個大小相等的切片,并使用 FormData 對象和 fetch 函數(shù)發(fā)送切片數(shù)據(jù)到服務器。
實現(xiàn)斷點續(xù)傳的技術:記錄和恢復上傳狀態(tài)
在前端,可以使用 localStorage 或 sessionStorage 來存儲已上傳的切片信息,包括已上傳的切片索引、切片大小等。
每次上傳前,先檢查本地存儲中是否存在已上傳的切片信息,若存在,則從斷點處繼續(xù)上傳。
在后端,可以使用一個臨時文件夾或數(shù)據(jù)庫來記錄已接收到的切片信息,包括已上傳的切片索引、切片大小等。
在上傳完成前,保存上傳狀態(tài),以便在上傳中斷后能夠恢復上傳進度。
import React, { useState, useRef, useEffect } from 'react';
function Upload() {
const [file, setFile] = useState(null);
const [uploadedChunks, setUploadedChunks] = useState([]);
const [uploading, setUploading] = useState(false);
const uploadRequestRef = useRef();
const handleFileChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
};
const uploadChunk = (chunk) => {
// 創(chuàng)建FormData對象
const formData = new FormData();
formData.append('file', chunk);
// 發(fā)送切片到服務器
return fetch('your-upload-url', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
console.log(data);
// 處理響應結果
return data;
});
};
const upload = async () => {
if (!file) {
alert("請選擇要上傳的文件!");
return;
}
const chunkSize = 1024 * 1024; // 1MB
const totalChunks = Math.ceil(file.size / chunkSize);
let start = 0;
let end = Math.min(chunkSize, file.size);
setUploading(true);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(start, end);
const uploadedChunkIndex = uploadedChunks.indexOf(i);
if (uploadedChunkIndex === -1) {
try {
const response = await uploadChunk(chunk);
setUploadedChunks((prevChunks) => [...prevChunks, i]);
// 保存已上傳的切片信息到本地存儲
localStorage.setItem('uploadedChunks', JSON.stringify(uploadedChunks));
} catch (error) {
console.error(error);
// 處理錯誤
}
}
start = end;
end = Math.min(start + chunkSize, file.size);
}
setUploading(false);
// 上傳完畢,清除本地存儲的切片信息
localStorage.removeItem('uploadedChunks');
};
useEffect(() => {
const storedUploadedChunks = localStorage.getItem('uploadedChunks');
if (storedUploadedChunks) {
setUploadedChunks(JSON.parse(storedUploadedChunks));
}
}, []);
return (
<div>
<input type="file" onChange={handleFileChange} />
<button onClick={upload} disabled={uploading}>
{uploading ? '上傳中...' : '上傳'}
</button>
</div>
);
}
首先,使用 useState 鉤子創(chuàng)建了一個 uploadedChunks 狀態(tài)來保存已上傳的切片索引數(shù)組。初始值為空數(shù)組。
然后,我們使用 useRef 鉤子創(chuàng)建了一個 uploadRequestRef 引用,用于存儲當前的上傳請求。
在 handleFileChange 函數(shù)中,我們更新了 file 狀態(tài)以選擇要上傳的文件。
在 uploadChunk 函數(shù)中,我們發(fā)送切片到服務器,并返回一個 Promise 對象來處理響應結果。
在 upload 函數(shù)中,我們添加了斷點續(xù)傳的邏輯。首先,我們獲取切片的總數(shù),并設置 uploading 狀態(tài)為 true 來禁用上傳按鈕。
然后,我們使用 for 循環(huán)遍歷所有切片。對于每個切片,我們檢查 uploadedChunks 數(shù)組中是否已經(jīng)包含該索引,如果不包含,則進行上傳操作。
在上傳切片之后,我們將已上傳的切片索引添加到 uploadedChunks 數(shù)組,并使用 localStorage 保存已上傳的切片信息。
最后,在上傳完畢后,我們將 uploading 狀態(tài)設為 false ,并清除本地存儲的切片信息。
在實現(xiàn)大文件上傳時要考慮服務器端的處理能力和存儲空間,以及安全性問題。同時,為了保障斷點續(xù)傳的準確性,應該盡量避免并發(fā)上傳相同文件的情況,可以采用文件唯一標識符或用戶會話標識符進行區(qū)分。
四、優(yōu)化用戶體驗:切片下載與上傳的應用場景
后臺管理系統(tǒng)中的文件下載和上傳:
文件下載:在后臺管理系統(tǒng)中,用戶可能需要下載大型文件,如報表、日志文件、數(shù)據(jù)庫備份等。通過將文件切片下載,可以提高下載速度和穩(wěn)定性,同時允許用戶中斷下載并從中斷處繼續(xù)下載。
文件上傳:后臺管理系統(tǒng)中,用戶可能需要上傳大型文件,如數(shù)據(jù)導入、文件備份等。使用切片上傳可以提高上傳效率,分批上傳文件切片,并顯示上傳進度,使用戶能夠了解上傳的狀態(tài)。
圖片/視頻上傳和預覽:
圖片上傳和預覽:在圖片上傳場景中,用戶可以選擇多張圖片進行上傳。通過切片上傳,可以加快圖片上傳速度,并實時顯示上傳進度。同時,在上傳完成后,可以提供預覽功能,讓用戶可以立即查看上傳的圖片。
視頻上傳和預覽:對于較大的視頻文件,切片上傳可以確保上傳過程可靠且高效。同時,可以實現(xiàn)上傳進度的實時展示。上傳完成后,通過切片下載技術,用戶可以流暢地觀看視頻,無需等待整個文件下載完成。
云存儲和云盤應用中的文件操作:
文件分塊上傳:云存儲和云盤應用通常需要處理大量文件的上傳。通過切片上傳可以提高上傳速度和穩(wěn)定性,并允許用戶中斷并繼續(xù)上傳。
文件分塊下載:當用戶需要下載云存儲或云盤中的大型文件時,可以使用切片下載技術,加快下載速度并提供中斷恢復功能。
文件預覽和在線編輯:通過將文件切片并進行預覽,在線編輯,可以提供更好的用戶體驗。用戶可以在不需完全下載文件的情況下,直接預覽和編輯文件。
寫在最后
文件分片上傳和下載是一種優(yōu)化前端文件流操作的有效方案。通過將大文件拆分成多個小片段,并利用斷點續(xù)傳的特性,我們可以提升文件傳輸?shù)目煽啃院托省?/p>
在這個過程中,使用 React 框架可以方便地管理和操作文件對象,提供了更便捷的編程方式。同時,熟悉 Blob 對象和 ArrayBuffer 這些工具也是處理和操作二進制數(shù)據(jù)的關鍵。
通過本文的學習,我們深入了解了文件流操作的基本概念和技術,以及如何使用 React 實現(xiàn)文件分片上傳和下載。我們掌握了處理二進制數(shù)據(jù)的方法,并了解了如何利用流式傳輸和斷點續(xù)傳的技術優(yōu)化文件傳輸?shù)男阅芎陀脩趔w驗。
文件分片上傳和下載的實現(xiàn),不僅為前端開發(fā)提供了高效的文件處理方式,還能夠應對網(wǎng)絡限制和大文件傳輸?shù)奶魬?zhàn)。掌握這些知識和技術,將為我們在前端開發(fā)中處理文件流操作提供一個強大的工具箱。
總之,通過合理運用文件分片上傳和下載以及相關的前端技術,我們可以優(yōu)化文件傳輸?shù)男阅?,提升用戶體驗,并為前端開發(fā)帶來更好的解決方案。
以上就是React實現(xiàn)文件分片上傳和下載的方法詳解的詳細內容,更多關于React文件分片上傳和下載的資料請關注腳本之家其它相關文章!
相關文章
React組件中使用JSON數(shù)據(jù)文件的方法詳解
要在 React 組件中使用 JSON 數(shù)據(jù),有多種方法,這篇文章主要為大家詳細介紹了五個常見的方法,文中的示例代碼講解詳細,有需要的小伙伴可以了解下2024-01-01

