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)
感謝閱讀,公眾號 「瘦風的南牆」 ,手機端閱讀更佳,還有其他福利和心得輸出,歡迎掃碼關注?
本文版權歸博主所有,歡迎轉載,但 [必須在頁面明顯位置標明原文連結],否則博主保留追究相關人士法律責任的權利。