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

Java FTP 客戶端遠程文件管理模塊深度解析

     編輯:Java 相關知識

在 FTP 客戶端開發中,遠程文件管理模塊是核心功能區,直接決定用戶操作體驗。本文將詳細剖析基於 Java Swing 實現的遠程面板,涵蓋文件列表渲染、目錄刷新、新建/刪除/重命名文件夾等關鍵操作的完整實現邏輯與代碼細節。

界面效果預覽

遠程文件管理界面

核心功能實現

1. 遠程文件列表顯示與解析

遠程面板通過 JTable 展示文件屬性(名稱、大小、日期),數據模型採用 DefaultTableModel。關鍵方法 listFtpFiles(TelnetInputStream list) 負責解析服務器返回的原始目錄流:

public synchronized void listFtpFiles(final TelnetInputStream list) {
    final DefaultTableModel model = (DefaultTableModel) ftpDiskTable.getModel();
    model.setRowCount(0);

    Runnable runnable = new Runnable() {
        public synchronized void run() {
            ftpDiskTable.clearSelection();
            try {
                String pwd = getPwd(); // 獲取當前遠程路徑
                // 添加 "." 與 ".." 虛擬目錄項
                model.addRow(new Object[] { new FtpFile(".", pwd, true), "", "" });
                model.addRow(new Object[] { new FtpFile("..", pwd, true), "", "" });

                byte[] names = new byte[2048];
                int bufsize = list.read(names, 0, names.length);
                int i = 0, j = 0;
                while (i < bufsize) {
                    // 二進制模式下換行符為 13 (CR)
                    if (names[i] == 13) {
                        String fileMessage = new String(names, j, i - j);
                        if (fileMessage.length() == 0) break;

                        String[] parts = fileMessage.split("\\s+");
                        if (!parts[8].equals(".") && !parts[8].equals("..")) {
                            String sizeOrDir = parts[0].startsWith("d") ? "<DIR>" : parts[4];
                            String fileName = parts[8];
                            String dateStr = parts[5] + " " + parts[6] + " " + parts[7];

                            FtpFile ftpFile = new FtpFile();
                            ftpFile.setLastDate(dateStr);
                            ftpFile.setSize(sizeOrDir);
                            ftpFile.setName(fileName);
                            ftpFile.setPath(pwd);
                            model.addRow(new Object[] { ftpFile, ftpFile.getSize(), dateStr });
                        }
                        j = i + 2; // CR+LF 兩字節
                    }
                    i++;
                }
                list.close();
            } catch (IOException ex) {
                Logger.getLogger(FTPClientFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    };

    if (SwingUtilities.isEventDispatchThread()) runnable.run();
    else SwingUtilities.invokeLater(runnable);
}

解析要點:

  • 服務器返回目錄列表通常為類 Unix `ls -l` 格式,需按空白字符分割提取權限、大小、日期、文件名等字段。
  • 區分文件與目錄:權限字符串首字符 `d` 表示目錄,`-` 表示文件。
  • 雙緩衝更新:先清空模型,再批量添加行,最後在 EDT 線程刷新 UI,避免界面閃爍。

2. 刷新當前目錄

刷新操作鏈路極短:按鈕觸發 RefreshAction → 調用 FtpPanel.refreshCurrentFolder() → 發送 `LIST` 命令並重用上述解析邏輯。

// RefreshAction
@Override public void actionPerformed(ActionEvent e) {
    ftpPanel.refreshCurrentFolder();
}

// FtpPanel
public void refreshCurrentFolder() {
    try {
        TelnetInputStream list = ftpClient.list();
        listFtpFiles(list);
    } catch (IOException e) { e.printStackTrace(); }
}

3. 新建遠程文件夾

發送 `MKD` 命令,根據返回碼 257 判斷成功,並自動刷新列表。

@Override public void actionPerformed(ActionEvent e) {
    String folderName = JOptionPane.showInputDialog("請輸入文件夾名稱:");
    if (folderName == null) return;
    int read = -1;
    try {
        ftpPanel.ftpClient.sendServer("MKD " + folderName + "\r\n");
        read = ftpPanel.ftpClient.readServerResponse();
    } catch (IOException e1) { e1.printStackTrace(); }

    if (read == 257) {
        JOptionPane.showMessageDialog(ftpPanel, folderName + " 文件夾創建成功。", "創建文件夾", JOptionPane.INFORMATION_MESSAGE);
    } else {
        JOptionPane.showMessageDialog(ftpPanel, folderName + " 文件夾無法創建。", "創建文件夾", JOptionPane.ERROR_MESSAGE);
    }
    ftpPanel.refreshCurrentFolder();
}

4. 刪除遠程文件/文件夾(遞歸刪除)

刪除邏輯較為複雜,需區分文件與目錄:文件直接發 `DELE`;目錄需先進入遞歸刪除內容,再退回發 `RMD`。整個操作放在獨立線程避免阻塞 UI。

public void actionPerformed(ActionEvent e) {
    final int[] selRows = ftpPanel.ftpDiskTable.getSelectedRows();
    if (selRows.length < 1) return;
    if (JOptionPane.showConfirmDialog(ftpPanel, "確定要刪除嗎?") != JOptionPane.YES_OPTION) return;

    Runnable runnable = new Runnable() {
        private void delFile(FtpFile file) {
            try {
                if (file.isFile()) {
                    ftpClient.sendServer("DELE " + file.getName() + "\r\n");
                    ftpClient.readServerResponse();
                } else if (file.isDirectory()) {
                    ftpClient.cd(file.getName());
                    TelnetInputStream stream = ftpClient.list();
                    // 解析子項並遞歸調用 delFile(ftpFile) ...
                    ftpClient.cdUp();
                    ftpClient.sendServer("RMD " + file.getName() + "\r\n");
                    ftpClient.readServerResponse();
                }
            } catch (Exception ex) { Logger.getLogger(LocalPanel.class.getName()).log(Level.SEVERE, null, ex); }
        }

        public void run() {
            for (int i = 0; i < selRows.length; i++) {
                FtpFile file = (FtpFile) ftpPanel.ftpDiskTable.getValueAt(selRows[i], 0);
                if (file != null) delFile(file);
            }
            ftpPanel.refreshCurrentFolder();
            JOptionPane.showMessageDialog(ftpPanel, "刪除成功。");
        }
    };
    new Thread(runnable).start();
}

5. 重命名遠程文件/文件夾

利用 FTP `RNFR`(重命名來源)與 `RNTO`(重命名目標)命令對完成原子操作。

@Override public void actionPerformed(ActionEvent e) {
    int selRow = ftpPanel.ftpDiskTable.getSelectedRow();
    if (selRow < 0) return;
    FtpFile file = (FtpFile) ftpPanel.ftpDiskTable.getValueAt(selRow, 0);
    String newName = JOptionPane.showInputDialog(ftpPanel, "請輸入新名稱。");
    if (file.getName().equals(".") || file.getName().equals("..") || newName == null) return;

    try {
        ftpPanel.ftpClient.sendServer("RNFR " + file.getName() + "\r\n");
        ftpPanel.ftpClient.readServerResponse();
        ftpPanel.ftpClient.sendServer("RNTO " + newName + "\r\n");
        ftpPanel.ftpClient.readServerResponse();
        ftpPanel.refreshCurrentFolder();
    } catch (IOException e1) { e1.printStackTrace(); }
}

總結與最佳實踐

  1. 線程隔離:所有耗時網絡操作(列表解析、遞歸刪除)均放入後台線程,通過 SwingUtilities.invokeLater 回調 UI 更新,保證界面響應流暢。
  2. 錯誤處理:統一捕獲 IOException 並記錄日誌,用戶端以對話框友好提示,避免崩潰。
  3. 協議遵循:嚴格遵循 RFC 959 命令序列(如 `MKD`/`RMD`/`RNFR`/`RNTO`),確保與標準 FTP 服務器兼容。
  4. 數據模型封裝:FtpFile 封裝文件元數據,作為表格模型行對象,實現數據與視圖解耦。

這套遠程管理模塊為 FTP 客戶端提供了完整的文件操作閉環,結合前文的主界面框架,已具備一個可用工具的雛形。下一步可進一步優化大文件傳輸斷點續傳、並發隊列調度等高級特性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved