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

Java 檔案複製進度條實戰:ProgressMonitorInputStream + 多執行緒完整實現

     編輯:Java 程式設計入門

專案概述

大檔案複製若無進度回饋,使用者體驗極差。Swing 提供 ProgressMonitorInputStream 內建進度監視對話框,配合多執行緒避免 UI 凍結,即可實現專業級複製體驗。本範例完整展示「選檔案 → 選目標資料夾 → 開啟新執行緒複製 → 自動彈出進度條」全流程。

核心類別架構

// 進度監視邏輯封裝
public class ProgressMonitorTest {
    public void useProgressMonitor(JFrame parent, String srcPath, String destPath) { ... }
}

// 主視窗:實作 Runnable,負責 UI 與啟動複製執行緒
public class UserMonitorFrame extends JFrame implements Runnable {
    private JTextField textField;      // 來源檔案
    private JTextField textField_1;    // 目標資料夾
    ...
}

關鍵實現細節

1. ProgressMonitorInputStream 使用

public void useProgressMonitor(JFrame frame, String copyPath, String newPath) {
    try {
        File src = new File(copyPath);
        File dest = new File(newPath);
        try (FileInputStream fis = new FileInputStream(src);
             FileOutputStream fos = new FileOutputStream(dest);
             // 關鍵:包裝輸入流,超過 2 秒自動彈出進度對話框
             ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(
                     frame, "文件讀取中,請稍後...", fis)) {

            byte[] buf = new byte[1024];
            int len;
            while ((len = pmis.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}
機制:ProgressMonitorInputStream 內部計時,若預估總耗時 > 2 秒(預設閾值),自動顯示 JOptionPane 風格進度對話框,含進度列、已讀取位元組、預估剩餘時間、取消按鈕。

2. 主視窗 UI 佈局

  • 來源檔案:JTextField + 「選擇檔案」按鈕(JFileChooser.FILES_ONLY)。
  • 目標資料夾:JTextField + 「選擇資料夾」按鈕(JFileChooser.DIRECTORIES_ONLY)。
  • 「開始複製」按鈕:觸發 new Thread(this).start()。

3. 多執行緒啟動複製

// 按鈕事件
protected void do_copyButton_actionPerformed(ActionEvent e) {
    new Thread(this).start(); // 關鍵:開啟新執行緒,避免阻塞 EDT
}

@Override
public void run() {
    ProgressMonitorTest test = new ProgressMonitorTest();
    String src = textField.getText();
    String destDir = textField_1.getText();
    // 目標檔案 = 目標資料夾 + 原檔名(含副檔名)
    String destFile = destDir + src.substring(src.lastIndexOf("."));
    test.useProgressMonitor(this, src, destFile);
}

為什麼必須多執行緒?

Swing 是單執行緒模型(Event Dispatch Thread, EDT)。若在 EDT 執行耗時 I/O:

  • UI 完全凍結,無法移動視窗、點擊取消、甚至重繪進度條本身。
  • ProgressMonitorInputStream 內部計時器也跑在 EDT,導致進度條根本不會顯示或顯示後立即卡死。

解法:new Thread(runnable).start() 將 I/O 移出 EDT,EDT 保持響應,進度對話框正常運作。

進階改進建議

功能實現方式
取消複製輪詢 pmis.getProgressMonitor().isCanceled(),中斷迴圈並刪除半成品檔
進度百分比精確預先 src.length() 取總大小,寫入時累加 bytesWritten,手動 monitor.setProgress()
多檔案批次複製外層迴圈遍歷檔案清單,內層複製單檔,總進度 = (已完成檔案大小 + 當前檔案進度) / 總大小
速度顯示System.nanoTime() 計算位元組/秒,格式化為 MB/s
異常處理友善化捕獲 IOException,用 SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(...)) 回 EDT 顯示錯誤
現代化替代JavaFX Task + ProgressBar、Swing SwingWorker + 自定義 JDialog 進度條

完整程式碼結構

// ProgressMonitorTest.java
package cn.edu.xidian.crytoll;
import java.io.*;
import javax.swing.*;

public class ProgressMonitorTest {
    public void useProgressMonitor(JFrame frame, String copyPath, String newPath) {
        // ... 如上所示
    }
}

// UserMonitorFrame.java
package cn.edu.xidian.crytoll;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class UserMonitorFrame extends JFrame implements Runnable {
    // ... UI 初始化、檔案選擇器、按鈕事件、run() 方法 ...
}

總結

  • ProgressMonitorInputStream 是 Swing 內建的「零配置」進度條方案,適合中小檔案快速整合。
  • 多執行緒是硬性要求:I/O 必須離開 EDT,否則進度條失效、UI 凍結。
  • 生產環境建議遷移至 SwingWorker(自帶 publish/process 進度回調)或 JavaFX Task,獲得更靈活的控制與現代化 UI。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved