Hadoop 分散式檔案系統(HDFS)是大數據生態系統的核心儲存層。本文提供使用 Java API 對 HDFS 執行上傳、下載、刪除檔案的完整可執行程式碼,適用於 Hadoop 2.x/3.x 環境。
核心依賴
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.3.4</version> <!-- 對應叢集版本 -->
</dependency>
完整工具類實作
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import java.io.IOException;
import java.io.File;
public class HadoopFile {
private Configuration conf;
public HadoopFile() {
this.conf = new Configuration();
// 載入核心站點配置(含 fs.defaultFS 等)
conf.addResource(new Path("/etc/hadoop/core-site.xml"));
}
public HadoopFile(Configuration conf) {
this.conf = conf;
}
/** 上傳本地檔案到 HDFS */
public boolean uploadFile(String hdfsPath, String localFilePath) {
File localFile = new File(localFilePath);
if (!localFile.isFile()) {
System.err.println("本地檔案不存在: " + localFilePath);
return false;
}
try (FileSystem localFS = FileSystem.getLocal(conf);
FileSystem hdfsFS = FileSystem.get(conf)) {
Path hdfsDir = new Path(hdfsPath);
Path hdfsFile = new Path(hdfsDir, localFile.getName());
// 確保目標目錄存在
if (!hdfsFS.exists(hdfsDir)) {
hdfsFS.mkdirs(hdfsDir);
}
try (FSDataInputStream in = localFS.open(new Path(localFilePath));
FSDataOutputStream out = hdfsFS.create(hdfsFile)) {
byte[] buffer = new byte[8192]; // 8KB 緩衝區
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
}
// 列印上傳後目錄內容確認
FileStatus[] files = hdfsFS.listStatus(hdfsDir);
for (FileStatus fs : files) {
System.out.println(fs.getPath() + " [" + fs.getLen() + " bytes]");
}
return true;
} catch (IOException e) {
System.err.println("上傳失敗: " + e.getMessage());
e.printStackTrace();
return false;
}
}
/** 刪除 HDFS 上的檔案或目錄 */
public boolean deleteFile(String hdfsPath) {
try (FileSystem hdfsFS = FileSystem.get(conf)) {
Path path = new Path(hdfsPath);
boolean deleted = hdfsFS.delete(path, true); // true = 遞迴刪除
if (deleted) {
System.out.println("刪除成功: " + hdfsPath);
} else {
System.out.println("刪除失敗或路徑不存在: " + hdfsPath);
}
// 列印父目錄內容確認
FileStatus[] files = hdfsFS.listStatus(path.getParent());
for (FileStatus fs : files) {
System.out.println(fs.getPath());
}
return deleted;
} catch (IOException e) {
System.err.println("刪除異常: " + e.getMessage());
e.printStackTrace();
return false;
}
}
/** 從 HDFS 下載檔案到本地 */
public boolean downloadFile(String hdfsFilePath, String localDirPath) {
try (FileSystem localFS = FileSystem.getLocal(conf);
FileSystem hdfsFS = FileSystem.get(conf)) {
Path hdfsPath = new Path(hdfsFilePath);
Path localPath = new Path(localDirPath, hdfsPath.getName());
try (FSDataInputStream in = hdfsFS.open(hdfsPath);
FSDataOutputStream out = localFS.create(localPath)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
}
System.out.println("下載完成: " + localPath);
return true;
} catch (IOException e) {
System.err.println("下載失敗: " + e.getMessage());
e.printStackTrace();
return false;
}
}
public static void main(String[] args) {
HadoopFile hdfs = new HadoopFile();
// 上傳測試
hdfs.uploadFile("/user/hadoop/input", "/local/path/data.txt");
// 下載測試
hdfs.downloadFile("/user/hadoop/output/part-r-00000", "/local/download");
// 刪除測試
hdfs.deleteFile("/user/hadoop/temp");
}
}
關鍵 API 對照
| 操作 | 核心類別/方法 | 說明 |
| 取得 FileSystem | FileSystem.get(Configuration) | 需正確配置 core-site.xml 中的 fs.defaultFS |
| 建立輸出流 | FSDataOutputStream create(Path) | 覆寫模式,支援 append 需用 append(Path) |
| 建立輸入流 | FSDataInputStream open(Path) | 支援 seek 定位讀取 |
| 刪除 | boolean delete(Path, boolean recursive) | recursive=true 遞迴刪除目錄 |
| 列出目錄 | FileStatus[] listStatus(Path) | 取得檔案中繼資料 |
| 建立目錄 | mkdirs(Path) | 遞迴建立多層目錄 |
進階用法與最佳實務
大檔案上傳優化
- 增加緩衝區大小(64KB-256KB)
- 啟用壓縮:
conf.set("mapreduce.output.fileoutputformat.compress", "true")
- 使用
DistCp (Distributed Copy) 進行叢集間大量資料遷移
Kerberos 安全叢集認證
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
UserGroupInformation.loginUserFromKeytab("user@REALM", "/path/to/keytab");
FileSystem fs = FileSystem.get(conf);
HDFS HA (High Availability) 配置
conf.set("fs.defaultFS", "hdfs://nameservice1");
conf.set("dfs.nameservices", "nameservice1");
conf.set("dfs.ha.namenodes.nameservice1", "nn1,nn2");
conf.set("dfs.namenode.rpc-address.nameservice1.nn1", "host1:8020");
conf.set("dfs.namenode.rpc-address.nameservice1.nn2", "host2:8020");
conf.set("dfs.client.failover.proxy.provider.nameservice1",
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
常見錯誤排查
| 錯誤現象 | 可能原因 | 解決方向 |
| Connection refused | NameNode 地址/埠錯誤、防火牆阻擋 | 檢查 core-site.xml、telnet 測試連通性 |
| AccessControlException | 權限不足、Kerberos 未認證 | 檢查 HDFS 權限、keytab 設定 |
| FileAlreadyExistsException | 上傳目標檔案已存在 | 先刪除或使用 append 模式 |
| LeaseExpiredException | 寫入過程中租約過期 | 增加 dfs.lease.soft/hard.limit 參數 |
- 上一篇文章: Java 呼叫淘寶 IP 地址庫 API 查詢地理位置
- 下一篇文章: Java 讀寫 CSV 檔案實作範例
Copyright ©
程式碼之家 All Rights Reserved