我写了一个脚本,它接受一个文件夹,并使用python的多处理池库将它们组合成最大大小为500MB的文件。该脚本获取文件夹中的文件列表,并将其分为16个列表,每个列表都映射到一个进程。在每个进程中,使用每个列表中的一组文件组合临时文件。在获得所有这16个文件之后,我依次组合这16个文件并删除临时文件。 我在带有ext4文件系统的CentOS系统上运行它,我传递了一个大小为930 MB的文件夹,其中186147个文件分布在50个子文件夹中,它给了我一个文件作为输出,大小为346 MB。我很困惑文件大小如何减少这么多。
请注意,这些186147文件中的每个文件在开始时都有一个额外的标头,在最终组合文件创建期间会被忽略,但只有标题的文件只有233个字节。
为了检查我的脚本是否正确,我检查了合并文件中的总行数(3083015),它与186147文件中的行数之和(3269162)相匹配 - 标题数(186147) 。我也尝试捕获单个文件,并且线条看起来是完整的,但我没有浏览整个文件。
我在这里缺少什么?
这是我使用的并行化函数:
curr_write_file_name = os.path.join(output_folder, str(list_index) + '_' + "00000.flows")
curr_write_file = open(curr_write_file_name, 'w')
curr_write_file.write(header)
curr_write_count = 1
for curr_file in file_list:
print('Processing', curr_file)
netflow_read = open(curr_file, 'r')
for index, line in enumerate(netflow_read):
if index == 0:
continue
else:
curr_write_file.write(line)
if os.stat(curr_file).st_size >= 500000000:
curr_write_file.close()
curr_write_file_name = os.path.join(output_folder, str(list_index) + '_' + str(curr_write_count).zfill(5) + '.flows')
curr_write_file = open(curr_write_file_name, 'w')
curr_write_count = curr_write_count + 1
curr_write_file.write(header)
netflow_read.close()
这是相应的主要内容:
if __name__=='__main__'
dataFileList = []
for dirPath, dirNames, fileNames in os.walk(str(sys.argv[1])):
# Since the filtering occurs parallel, sorting the files has no benefit
dirNames.sort()
fileNames.sort()
dataFileList = dataFileList + [os.path.join(dirPath, fileName) for fileName in fileNames if fileName.endswith('.flows')]
noOfProcesses = os.cpu_count()*2 # To create a maximum of no_of_cores*2 processes
process_pool = mp.Pool(noOfProcesses) # To create a parallel pool of noOfProcesses processes
file_split_number = int(len(dataFileList)/noOfProcesses)
dataFile_list_of_lists = [(dataFileList[x:x+file_split_number], x) for x in range(0, len(dataFileList), file_split_number)]
process_pool.map(worker_process_combine_set, dataFile_list_of_lists) # To map the processes to the files in the list and split them
stage_1 = time.time()
print('Completed first stage combining successfully in', stage_1 - start_time, 'seconds')
process_pool.close()
process_pool.join()
# sequential combining
finalFiles = combine_final()
print('Completed combining files successfully in', time.time() - start_time, 'seconds')
答案 0 :(得分:2)
你的文件系统的块大小是多少?因为,你看,在最后一个块的末尾有一些未使用的空间,平均是半个块,如果你将它乘以文件数(186147),这可能达到几百兆......
答案 1 :(得分:2)
对于 ext4 filesystem ,在linux上,您可以使用以下命令检查:
df -T / | awk '{print $2}' | tail -1
磁盘存储的统一性是文件系统的块大小。使用一定数量的块存储每个文件。但是最后一个块并不总是满的,您的文件系统完成此空间以遵守磁盘存储的此规则。这就是为什么如果通过连接将多个文件转换为单个文件,则可以节省磁盘的空间。
对于您的情况,将186147
个文件转换为单个文件。你最多保存
186147*sizeof(block)
个字节。如果您认为未真正使用的最后一个块中的字节数是统一定律,则平均可以节省sizeof(block)/2
个字节。
对于大多数文件系统,块的大小为4KB,即4096字节。在这里,您最多可以节省4096*186147//(1024**2) = 727MB
,平均(4096/2)*186147//(1024**2) = 363MB
以root用户身份查看文件系统的块大小:
device=`df -T / | awk '{print $1}' | tail -1`
dumpe2fs $device | grep 'Block size
在bash或zsh控制台中测试:
echo 'a' > filea.txt; echo 'b' > fileb.txt; more *; ls -sh *
输出:
::::::::::::::
filea.txt
::::::::::::::
a
::::::::::::::
fileb.txt
::::::::::::::
b
4,0K filea.txt 4,0K fileb.txt
然后:
cat * > file.txt; more *; ls -sh *
输出:
::::::::::::::
filea.txt
::::::::::::::
a
::::::::::::::
fileb.txt
::::::::::::::
b
::::::::::::::
file.txt
::::::::::::::
a
b
4,0K filea.txt 4,0K fileb.txt 4,0K file.txt
file.txt
的尺寸为4KB
而不是8KB = sizeof(fileb.txt) + sizeof(filea.txt)
。
如果您创建一个4097字节的文件,将分配2个文件系统的块。参见:
dd if=/dev/zero of=file.txt bs=1 count=4097 &> /dev/null
ls -s --block-size=1 file.txt
输出:
8192 file.txt
file.txt的大小为8192 = 2*sizeof(filesystem_block) bytes
而不是4097
字节。
尝试:
files = ['file1.txt', 'file2.txt', 'file3.txt']
def cut(files, n_chunks):
size_chunk = len(files)//n_chunks
for i in range(0, len(files), size_chunk):
yield files[i:i + size_chunk]
def merge(files):
for _file in files:
...