1 - 為什么要合並小文件
HDFS 擅長存儲大文件:
我們知道,HDFS 中,每個文件都有各自的元數據信息,如果 HDFS 中有大量的小文件,就會導致元數據爆炸,集群管理的元數據的內存壓力會非常大。
所以在項目中,把小文件合並成大文件,是一種很有用也很常見的優化方法。
2 - 合並本地的小文件,上傳到 HDFS
將本地的多個小文件,上傳到 HDFS,可以通過 HDFS 客戶端的 appendToFile
命令對小文件進行合並。
在本地准備2個小文件:
# user1.txt 內容如下:
1,tom,male,16
2,jerry,male,10
# user2.txt 內容如下:
101,jack,male,19
102,rose,female,18
合並方式:
hdfs dfs -appendToFile user1.txt user2.txt /test/upload/merged_user.txt
合並后的文件內容:

3 - 合並 HDFS 的小文件,下載到本地
可以通過 HDFS 客戶端的 getmerge
命令,將很多小文件合並成一個大文件,然后下載到本地。
# 先上傳小文件到 HDFS:
hdfs dfs -put user1.txt user2.txt /test/upload
# 下載,同時合並:
hdfs dfs -getmerge /test/upload/user*.txt ./merged_user.txt
下載、合並后的文件內容:

4 - 通過 Java API 實現文件合並和上傳
代碼如下(具體測試項目,可到 我的 GitHub 查看):
@Test
public void testMergeFile() throws Exception {
// 獲取分布式文件系統
FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop:9000"), new Configuration(), "healchow");
FSDataOutputStream outputStream = fileSystem.create(new Path("/test/upload/merged_by_java.txt"));
// 獲取本地文件系統
LocalFileSystem local = FileSystem.getLocal(new Configuration());
// 通過本地文件系統獲取文件列表,這里必須指定路徑
FileStatus[] fileStatuses = local.listStatus(new Path("file:/Users/healchow/bigdata/test"));
for (FileStatus fileStatus : fileStatuses) {
// 創建輸入流,操作完即關閉
if (fileStatus.getPath().getName().contains("user")) {
FSDataInputStream inputStream = local.open(fileStatus.getPath());
IOUtils.copy(inputStream, outputStream);
IOUtils.closeQuietly(inputStream);
}
}
// 關閉輸出流和文件系統
IOUtils.closeQuietly(outputStream);
local.close();
fileSystem.close();
}
合並的結果,和通過命令合並的完全一致:

版權聲明
出處:博客園-瘦風的南牆(https://www.cnblogs.com/shoufeng)
感謝閱讀,公眾號 「瘦風的南牆」 ,手機端閱讀更佳,還有其他福利和心得輸出,歡迎掃碼關注🤝
本文版權歸博主所有,歡迎轉載,但 [必須在頁面明顯位置標明原文鏈接],否則博主保留追究相關人士法律責任的權利。