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

Java 實現 USB 隨插即用偵測(輪詢法)

     編輯:Java 程式設計入門

Java 標準 API 無直接支援硬體裝置插拔事件監聽。在 Windows 平台,常見替代方案是輪詢檢測磁碟機代號變化來偵測 USB 隨身碟插入/移除。本文提供一個基於輪詢的簡易實作,適用於桌面應用程式。

核心邏輯

  • Windows 磁碟機代號固定為 C: 到 Z:
  • 定期檢查各磁碟機 new File("X:\\").exists() 狀態
  • 比對上一次狀態,發現 從不存在→存在 即判定為 USB 插入
  • 同理 存在→不存在 判定為移除

完整實作程式碼

package org.load.u;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;

public class UsbDetector {
    // 記錄各磁碟機狀態:true=存在, false=不存在
    private static final Map<String, Boolean> driveStatus = new LinkedHashMap<>();
    
    // 監測的磁碟機代號 (通常 C: 為系統碟,D: 起為資料/可移動碟)
    private static final String[] DRIVES = {"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
    
    // 輪詢間隔 (毫秒)
    private static final long POLL_INTERVAL_MS = 5000;

    public static void main(String[] args) {
        System.out.println("USB 偵測服務啟動,輪詢間隔: " + POLL_INTERVAL_MS + "ms");
        initialize();
        startMonitoring();
    }

    /** 初始化各磁碟機初始狀態 */
    private static void initialize() {
        for (String drive : DRIVES) {
            File root = new File(drive + ":\\");
            driveStatus.put(drive, root.exists());
            System.out.printf("[初始] %s: -> %s%n", drive, root.exists() ? "存在" : "不存在");
        }
    }

    /** 開始輪詢監控 */
    private static void startMonitoring() {
        while (true) {
            for (String drive : DRIVES) {
                File root = new File(drive + ":\\");
                boolean currentExists = root.exists();
                Boolean previousExists = driveStatus.get(drive);
                
                // 偵測到插入:之前不存在,現在存在
                if (currentExists && (previousExists == null || !previousExists)) {
                    onUsbInserted(drive);
                }
                // 偵測到移除:之前存在,現在不存在
                else if (!currentExists && previousExists != null && previousExists) {
                    onUsbRemoved(drive);
                }
                
                // 更新狀態
                if (currentExists != (previousExists != null && previousExists)) {
                    driveStatus.put(drive, currentExists);
                }
            }
            
            try {
                Thread.sleep(POLL_INTERVAL_MS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("偵測執行緒被中斷,服務停止。");
                break;
            }
        }
    }

    /** USB 插入事件處理 */
    private static void onUsbInserted(String drive) {
        System.out.printf(">>> [偵測] USB 裝置插入: %s:\\%n", drive);
        // 這裡可觸發業務邏輯:掃描檔案、自動備份、病毒掃描等
    }

    /** USB 移除事件處理 */
    private static void onUsbRemoved(String drive) {
        System.out.printf("<<< [偵測] USB 裝置移除: %s:\\%n", drive);
        // 這裡可觸發清理邏輯:釋放檔案鎖、更新 UI 等
    }
}

關鍵設計說明

設計點說明
LinkedHashMap保持插入順序,方便日誌輸出閱讀
DRIVES 陣列涵蓋 C-Z 所有可能代號,避免遺漏
狀態比對邏輯嚴格判斷「狀態翻轉」而非單純「當前存在」
null 安全檢查初始化前 get() 回傳 null,需防禦性程式設計
執行緒中斷處理捕捉 InterruptedException 並重設中斷旗標,優雅停止

限制與改進方向

進階:使用 oshi-core 取得詳細裝置資訊

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>6.2.2</version>
</dependency>

import oshi.SystemInfo;
import oshi.hardware.HWDiskStore;

SystemInfo si = new SystemInfo();
for (HWDiskStore disk : si.getHardware().getDiskStores()) {
    System.out.printf("裝置: %s, 型號: %s, 序號: %s, 大小: %d GB, 類型: %s, 可移動: %b%n",
        disk.getName(), disk.getModel(), disk.getSerial(),
        disk.getSize() / 1_000_000_000, disk.getType(), disk.isRemovable());
}

生產環境建議

  • 將偵測邏輯封裝為 UsbDetectorService 介面,支援 Spring `@PostConstruct`/`@PreDestroy` 生命週期管理
  • 事件通知採用 ApplicationEventPublisher 或 Guava EventBus 解耦業務邏輯
  • 配置檔化輪詢間隔、監測磁碟機清單、事件處理器
  • 加入日誌框架記錄偵測歷程,支援稽核追蹤
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
限制改進方案
僅偵測磁碟機代號出現/消失,無法區分 USB/光碟/網路磁碟配合 WMI (wmic logicaldisk get caption,drivetype) 判斷 drivetype=2 (可移動碟)
輪詢有延遲 (預設 5 秒)縮短間隔至 1-2 秒,或使用 JNI 呼叫 Windows RegisterDeviceNotification API
跨平台相容性差 (Linux/macOS 掛載點不同)抽象介面,各平台實作不同策略 (Linux 監聽 /media, /mnt; macOS 監聽 /Volumes)
無法取得裝置詳細資訊 (廠商、序號、容量)整合oshi-core 函式庫或 JNA 呼叫系統 API