使用Python 遞迴合併不同目錄下小檔案
阿新 • • 發佈:2019-02-20
背景
專案中, 由網路爬蟲爬取的日誌檔案, 需要匯入到 hive 資料倉庫中, 但日誌檔案包含很多的小檔案, 散落在許多子資料夾下.
總所周知, 當 hive 的輸入端如果由許多小檔案組成的話, 每個小檔案都會啟動一個 map 任務, 如果檔案多而小, 會造成 map 任務啟動和初始化的時間遠大於邏輯處理的時間, 造成資料處理時間大大增加, 甚至會造成 OOM的後果.
鑑於此, 當我們執行一個hive任務時, 當發現數據量不大, 但任務數巨多時, 就要考慮是不是小檔案在作祟. 如果是, 請在 Map 前進行輸入的合併.
hive 通過設定啟動引數的方式, 社群有很多文章介紹, 這裡引用一下這篇文章:
Hive小檔案合併
以下主要介紹程式設計方式合併.
程式碼
話不多少, 直接上 python 程式碼:
#!/usr/bin/python
# -*- coding:utf8 -*-
import os
allFileNum = 0
def merge_small_file(level, path):
global allFileNum
'''''
列印一個目錄下的所有資料夾和檔案
'''
# 所有資料夾,第一個欄位是次目錄的級別
dirList = []
# 所有檔案
fileList = []
# 返回一個列表,其中包含在目錄條目的名稱(google翻譯)
files = os.listdir(path)
# 先新增目錄級別
dirList.append(str(level))
for f in files:
targetFile = "/data/admin/dong_bao_spider/merge_json_files.json"
output_json_file = open(targetFile,'a')
if(os.path.isdir(path + '/' + f)):
# 排除隱藏資料夾。因為隱藏資料夾過多
if (f[0] == '.'):
pass
else:
# 新增非隱藏資料夾
dirList.append(f)
getJsonFilePath(level, path+'/'+f)
if(os.path.isfile(path + '/' + f)):
# 判斷檔案是以".json"結尾的
if str(f).endswith('.json'):
# 新增檔案
fileList.append(path + '/' + f)
allFileNum += 1
with open(str(path + '/' + f)) as input_json_file:
for r in input_json_file.readlines():
# 去掉每一行後面的換行符,先加換行符
output_json_file.write(r.strip('\n') + '\n')
output_json_file.close()
# 以下程式碼為演示程式掃描過的資料夾, 分層顯示
# 當一個標誌使用,資料夾列表第一個級別不列印
# i_dl = 0
# for dl in dirList:
# if(i_dl == 0):
# i_dl = i_dl + 1
# else:
# # 列印至控制檯,不是第一個的目錄
# print '-' * (int(dirList[0])), dl
# # 列印目錄下的所有資料夾和檔案,目錄級別+1
# printPath((int(dirList[0]) + 1), path + '/' + dl)
# for fl in fileList:
# if str(fl).endswith(".json"):
# # 列印檔案
# print '-' * (int(dirList[0])), fl
# # 隨便計算一下有多少個檔案
# allFileNum = allFileNum + 1
# for file in fileList:
# print file
if __name__ == '__main__':
merge_small_file(1, '/Users/david/Downloads/dong_bao_output/')
print 'Files in total =', allFileNum