偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

SpringBoot大文件上傳卡死?分塊切割術(shù)搞定GB級傳輸,速度飆升!?。?/h1>

開發(fā) 前端
分塊上傳就像把大文件運(yùn)輸變成一場接力賽,每個分片都是一個選手,各司其職,共同完成任務(wù)。通過分塊切割、斷點(diǎn)續(xù)傳、并行加速和安全防護(hù),我們不僅解決了大文件上傳的卡死問題,還提升了用戶體驗(yàn)和系統(tǒng)性能?,F(xiàn)在,你可以自信地對用戶說:不管多大的文件,我們都能輕松搞定!

兄弟們,當(dāng)你正在開發(fā)一個視頻網(wǎng)站,用戶要上傳一個 5GB 的 4K 視頻。傳統(tǒng)的 SpringBoot 單文件上傳就像開著一輛裝滿貨物的三輪車爬坡 ——內(nèi)存爆炸、超時崩潰、網(wǎng)絡(luò)波動分分鐘讓你前功盡棄。這時候,分塊切割術(shù)就像給三輪車裝上渦輪增壓,把大文件切成小塊分批運(yùn)輸,讓上傳過程變得像高鐵一樣平穩(wěn)高效。

一、傳統(tǒng)上傳的「死亡陷阱」

1. 內(nèi)存黑洞

SpringBoot 默認(rèn)用MultipartFile接收文件,大文件會直接加載到內(nèi)存。5GB 的文件相當(dāng)于把一頭大象塞進(jìn)小轎車,內(nèi)存直接溢出,服務(wù)器瞬間卡死。

2. 超時魔咒

HTTP 請求有默認(rèn)超時時間(Tomcat 默認(rèn) 60 秒),上傳一個 5GB 文件需要至少 10 分鐘,超時是必然的。用戶只能眼睜睜看著進(jìn)度條卡在 99%,然后重新再來。

3. 網(wǎng)絡(luò)過山車

上傳到一半突然斷網(wǎng),傳統(tǒng)方案只能從頭再來。用戶可能已經(jīng)等了半小時,結(jié)果竹籃打水一場空,這種體驗(yàn)簡直讓人想砸電腦。

二、分塊切割術(shù)的「九陽神功」

1. 分而治之的智慧

把大文件切成 20MB 的小塊,就像把大象拆成零件運(yùn)輸。每個小塊獨(dú)立上傳,失敗了只需要重傳那一塊,大大降低風(fēng)險。

2. 斷點(diǎn)續(xù)傳的魔法

記錄已經(jīng)上傳的分片,網(wǎng)絡(luò)恢復(fù)后從斷點(diǎn)繼續(xù)。用戶可以暫停、重啟上傳,甚至關(guān)閉電腦第二天接著傳,就像下載電影一樣方便。

3. 并行加速的奧義

同時上傳多個分片,充分利用帶寬。就像多條車道同時通車,上傳速度直接翻倍。

三、后端實(shí)現(xiàn):打造「文件運(yùn)輸線」

1. 數(shù)據(jù)庫設(shè)計(jì):記錄運(yùn)輸狀態(tài)

CREATE TABLE file_upload (
    id VARCHAR(36) PRIMARY KEY, -- 文件唯一標(biāo)識
    total_size BIGINT NOT NULL, -- 文件總大小
    total_chunks INT NOT NULL, -- 總分片數(shù)
    uploaded_chunks INT DEFAULT 0, -- 已上傳分片數(shù)
    status INT DEFAULT 0 -- 0-進(jìn)行中,1-完成,2-失敗
);

2. 分片上傳接口:接收零件

@PostMapping("/upload/chunk")
public ResponseEntity<?> uploadChunk(
    @RequestParam("file") MultipartFile chunk,
    @RequestParam("fileId") String fileId,
    @RequestParam("chunkIndex") int chunkIndex) {
    
    // 檢查分片是否已存在
    if (chunkRepository.existsByFileIdAndChunkIndex(fileId, chunkIndex)) {
        return ResponseEntity.ok("分片已存在");
    }
    
    // 保存分片到臨時目錄
    String chunkPath = Paths.get(uploadDir, fileId, chunkIndex + ".part").toString();
    chunk.transferTo(Paths.get(chunkPath));
    
    // 更新數(shù)據(jù)庫狀態(tài)
    chunkRepository.save(new Chunk(fileId, chunkIndex, chunk.getSize()));
    
    return ResponseEntity.ok("分片上傳成功");
}

3. 合并接口:組裝零件

@PostMapping("/upload/merge")
public ResponseEntity<?> mergeChunks(@RequestParam("fileId") String fileId) {
    // 查詢所有分片
    List<Chunk> chunks = chunkRepository.findByFileId(fileId);
    
    // 按順序合并
    try (RandomAccessFile target = new RandomAccessFile(Paths.get(uploadDir, fileId).toFile(), "rw")) {
        for (Chunk chunk : chunks) {
            try (FileInputStream in = new FileInputStream(Paths.get(uploadDir, fileId, chunk.getChunkIndex() + ".part").toFile())) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    target.write(buffer, 0, bytesRead);
                }
            }
        }
    }
    
    // 刪除臨時分片
    chunks.forEach(chunk -> {
        try {
            Files.delete(Paths.get(uploadDir, fileId, chunk.getChunkIndex() + ".part"));
        } catch (IOException e) {
            log.error("刪除分片失敗", e);
        }
    });
    
    // 更新文件狀態(tài)
    fileUploadRepository.updateStatus(fileId, 1);
    
    return ResponseEntity.ok("文件合并成功");
}

四、前端實(shí)現(xiàn):「零件加工廠」

1. 分片切割:拆大象

function splitFile(file, chunkSize = 20 * 1024 * 1024) {
    const chunks = [];
    let current = 0;
    while (current < file.size) {
        const chunk = file.slice(current, current + chunkSize);
        chunks.push(chunk);
        current += chunkSize;
    }
    return chunks;
}

2. 并行上傳:多條車道

async function uploadChunks(chunks, fileId) {
    const promises = chunks.map((chunk, index) => {
        const formData = new FormData();
        formData.append("file", chunk);
        formData.append("fileId", fileId);
        formData.append("chunkIndex", index);
        
        return fetch("/upload/chunk", {
            method: "POST",
            body: formData
        });
    });
    
    await Promise.all(promises);
}

3. 進(jìn)度條:實(shí)時反饋

<div class="progress">
    <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<script>
function updateProgress(uploaded, total) {
    const progressBar = document.querySelector('.progress-bar');
    progressBar.style.width = `${(uploaded / total) * 100}%`;
    progressBar.setAttribute('aria-valuenow', `${(uploaded / total) * 100}`);
}
</script>

五、斷點(diǎn)續(xù)傳:「失敗重來」的勇氣

1. 記錄上傳狀態(tài)

localStorage.setItem('uploadStatus', JSON.stringify({
    fileId: '123',
    uploadedChunks: [0, 1, 3]
}));

2. 恢復(fù)上傳

async function resumeUpload(file) {
    const status = JSON.parse(localStorage.getItem('uploadStatus'));
    const chunks = splitFile(file);
    
    // 找出未上傳的分片
    const remainingChunks = chunks.filter((_, index) => !status.uploadedChunks.includes(index));
    
    await uploadChunks(remainingChunks, status.fileId);
}

六、性能優(yōu)化:「速度與激情」

1. 異步處理:解放線程

@Async("fileUploadExecutor")
public CompletableFuture<?> asyncMerge(String fileId) {
    return CompletableFuture.runAsync(() -> {
        // 合并文件邏輯
    });
}

2. 動態(tài)分塊:適應(yīng)路況

function calculateChunkSize(bandwidth) {
    // 根據(jù)網(wǎng)絡(luò)帶寬動態(tài)調(diào)整分片大小
    return Math.max(10 * 1024 * 1024, Math.min(50 * 1024 * 1024, bandwidth * 0.8));
}

3. 多線程合并:同時組裝

ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<?>> futures = new ArrayList<>();

for (int i = 0; i < chunks.size(); i += 4) {
    final int start = i;
    futures.add(executor.submit(() -> {
        for (int j = start; j < Math.min(start + 4, chunks.size()); j++) {
            // 合并分片
        }
    }));
}

futures.forEach(future -> {
    try {
        future.get();
    } catch (Exception e) {
        log.error("合并失敗", e);
    }
});

七、安全防護(hù):「文件運(yùn)輸?shù)谋kU」

1. MD5 校驗(yàn):防篡改

@PostMapping("/upload/check")
public ResponseEntity<?> checkFile(@RequestParam("file") MultipartFile file) {
    String md5 = calculateMD5(file.getInputStream());
    FileUpload fileUpload = fileUploadRepository.findByMd5(md5);
    
    if (fileUpload != null && fileUpload.getStatus() == 1) {
        return ResponseEntity.ok("文件已存在");
    }
    
    return ResponseEntity.ok("文件不存在");
}

2. 文件類型驗(yàn)證:防病毒

@PostMapping("/upload/chunk")
public ResponseEntity<?> uploadChunk(@RequestParam("file") MultipartFile chunk) {
    String contentType = chunk.getContentType();
    if (!contentType.startsWith("image/") && !contentType.startsWith("video/")) {
        return ResponseEntity.badRequest().body("不支持的文件類型");
    }
    
    // 其他邏輯
}

3. 權(quán)限控制:防越權(quán)

@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/upload/merge")
public ResponseEntity<?> mergeChunks(@RequestParam("fileId") String fileId) {
    // 合并邏輯
}

八、實(shí)戰(zhàn)案例:「5GB 視頻上傳的逆襲」

1. 傳統(tǒng)方案

  • 上傳時間:15 分鐘
  • 內(nèi)存占用:800MB
  • 失敗率:30%(網(wǎng)絡(luò)波動)

2. 分塊方案

  • 上傳時間:4 分鐘(并行上傳)
  • 內(nèi)存占用:50MB(流式處理)
  • 失敗率:2%(斷點(diǎn)續(xù)傳)

九、總結(jié):「分塊切割術(shù)」的終極奧義

分塊上傳就像把大文件運(yùn)輸變成一場接力賽,每個分片都是一個選手,各司其職,共同完成任務(wù)。通過分塊切割、斷點(diǎn)續(xù)傳、并行加速和安全防護(hù),我們不僅解決了大文件上傳的卡死問題,還提升了用戶體驗(yàn)和系統(tǒng)性能?,F(xiàn)在,你可以自信地對用戶說:不管多大的文件,我們都能輕松搞定!

責(zé)任編輯:武曉燕 來源: 石杉的架構(gòu)筆記
相關(guān)推薦

2025-06-27 02:32:00

2025-04-10 08:03:31

Spring系統(tǒng)

2020-08-14 11:01:32

數(shù)據(jù)Pandas文件

2024-09-26 09:28:06

內(nèi)存Spring

2021-11-26 22:01:26

Linux傳輸網(wǎng)絡(luò)

2021-06-07 00:03:31

HTTP大文件方案

2009-11-16 11:41:19

PHP上傳大文件

2022-06-13 14:06:33

大文件上傳前端

2025-05-06 01:21:00

C#內(nèi)存SIMD

2022-08-16 16:00:05

Python

2010-09-07 16:11:55

CSS Sprites

2009-07-21 15:38:31

2021-01-15 11:40:44

文件Java秒傳

2011-12-14 09:57:17

最快網(wǎng)絡(luò)傳輸速度186GB

2021-06-10 09:05:43

Linux命令大文件切割

2014-03-10 17:17:53

西數(shù)My Passport試用

2022-08-12 22:53:32

HadoopHDFS分布式

2024-07-02 10:18:18

2013-05-29 09:59:20

Java-RMI遠(yuǎn)程調(diào)用

2009-12-07 09:45:23

PHP上傳大文件設(shè)置
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號