首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 多執行緒檔案複製實現:RandomAccessFile 隨機存取與檔案指標控制

     編輯:Java 綜合教學

Java 多執行緒檔案複製實現:RandomAccessFile 隨機存取與檔案指標控制

大檔案複製若能利用多核 CPU 並行讀寫,效能提升顯著。RandomAccessFile 支援隨機定位讀寫,是實現多執行緒分段複製的核心工具。本文展示兩種分段策略的完整實現代碼。

核心原理

  1. 計算檔案總長度,按執行緒數均分 (向上取整)
  2. 每個執行緒負責一個連續區段:[start, end)
  3. 使用 seek(start) 定位讀寫指標
  4. 緩衝區讀寫循環,到達 end 結束

方案一:固定區段範圍 (推薦)

測試類:Test.java

package com.dragon.java.multithreadcopy;

import java.io.File;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("請輸入檔案路徑:");
        File srcFile = new File(scanner.next());
        System.out.print("請輸入執行緒數:");
        int n = scanner.nextInt();
        
        if (!srcFile.exists()) {
            System.out.println("檔案不存在!");
            return;
        }
        
        File desFile = new File(srcFile.getParent(), "copy_" + srcFile.getName());
        long partLength = srcFile.length() / n + 1; // 向上取整
        
        for (int i = 1; i <= n; i++) {
            long start = partLength * (i - 1);
            long end = partLength * i;
            new MyThread(srcFile, desFile, start, end).start();
        }
    }
}

執行緒類:MyThread.java

package com.dragon.java.multithreadcopy;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class MyThread extends Thread {
    private File srcFile, desFile;
    private long start, end;
    
    public MyThread(File srcFile, File desFile, long start, long end) {
        this.srcFile = srcFile;
        this.desFile = desFile;
        this.start = start;
        this.end = end;
    }
    
    @Override
    public void run() {
        try (RandomAccessFile rafSrc = new RandomAccessFile(srcFile, "r");
             RandomAccessFile rafDes = new RandomAccessFile(desFile, "rw")) {
            
            rafSrc.seek(start);
            rafDes.seek(start);
            
            byte[] buffer = new byte[8192]; // 8KB 緩衝區
            int len;
            while ((len = rafSrc.read(buffer)) != -1) {
                rafDes.write(buffer, 0, len);
                
                // 關鍵:檢查是否超出負責區段
                if (rafSrc.getFilePointer() >= end) break;
            }
            System.out.println(getName() + " 複製完成區段 [" + start + ", " + end + ")");
        } catch (IOException e) {
            System.err.println(getName() + " 異常:" + e.getMessage());
        }
    }
}

方案二:共享指標 (不推薦,僅供理解)

使用 static long pointer 共享進度,每個執行緒一次複製固定長度。缺點:需同步控制指標更新,易產生競爭條件;區段邊界不精確,最後一段可能重複或遺漏。

執行緒類 (共享指標版)

public class MyThread extends Thread {
    private File srcFile, desFile;
    private long partLength;
    private static long pointer = 0; // 共享指標
    
    public MyThread(File srcFile, File desFile, long partLength) {
        this.srcFile = srcFile;
        this.desFile = desFile;
        this.partLength = partLength;
    }
    
    @Override
    public void run() {
        synchronized (MyThread.class) { // 需同步
            long myStart = pointer;
            pointer += partLength;
            long myEnd = Math.min(pointer, srcFile.length());
            
            try (RandomAccessFile rafSrc = new RandomAccessFile(srcFile, "r");
                 RandomAccessFile rafDes = new RandomAccessFile(desFile, "rw")) {
                rafSrc.seek(myStart);
                rafDes.seek(myStart);
                
                byte[] buffer = new byte[(int) Math.min(partLength, myEnd - myStart)];
                int len = rafSrc.read(buffer);
                rafDes.write(buffer, 0, len);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

兩種方案對比

維度固定區段 (方案一)共享指標 (方案二)
同步開銷無 (各執行緒獨立區段)需 synchronized 鎖
負載均衡靜態均分,可能不均動態領取,相對均衡
邊界精確精確控制邊界模糊,需額外處理
代碼複雜度簡單清晰較複雜
推薦度⭐⭐⭐⭐⭐⭐⭐

效能優化建議

  • 緩衝區大小:8KB~64KB,平衡記憶體與系統呼叫 (方案一已用 8KB)
  • 執行緒數:CPU 核心數 × 1~2,過多反而增加上下文切換
  • NIO FileChannel:transferTo/transferFrom 零拷貝,大檔案更快
  • 記憶體映射:MappedByteBuffer 將檔案映射至記憶體,極速隨機存取
方案一為生產環境推薦做法:簡單、無鎖、邊界可控。方案二僅作為理解共享狀態同步問題的教學範例。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved