注意:我在答案的最后写了这些函数,所以请随意跳转到那个 – 但是为了更好地理解,我仍然希望逐个部分地运行代码.
将用于解释的示例方案
假设您在此文件夹中有12个名为test的文件,其中10个是.txt文件:
.../
test/
01.txt
02.txt
03.txt
04.txt
05.txt
06.txt
07.txt
08.txt
09.txt
10.txt
random_file.py
this_shouldnt_be_here.sh
每个.txt文件的第一行作为相应的数字,如
> 01.txt包含第一行01,
> 02.txt包含第一行02,
>等……
列出指定目录中的所有文本文件
您可以通过两种方式执行此操作:
方法1:os模块
您可以导入模块os并使用方法listdir列出该目录中的所有文件.请务必注意,列表中的所有文件都是相对文件名:
>>> import os
>>> all_files = os.listdir("test/") # imagine you're one directory above test dir
>>> print(all_files) # won't necessarily be sorted
['08.txt', '02.txt', '09.txt', '04.txt', '05.txt', '06.txt', '07.txt', '03.txt', '06.txt', '01.txt', 'this_shouldnt_be_here.sh', '10.txt', 'random_file.py']
现在,您只需要.txt文件,因此使用过滤器函数和匿名函数进行一些函数式编程,您可以轻松地过滤掉它们而无需使用标准的for循环:
>>> txt_files = filter(lambda x: x[-4:] == '.txt', all_files)
>>> print(txt_files) # only text files
['08.txt', '02.txt', '09.txt', '04.txt', '05.txt', '06.txt', '07.txt', '03.txt', '06.txt', '01.txt', '10.txt']
方法2:glob模块
类似地,您可以使用glob模块并使用glob.glob函数列出目录中的所有文本文件,而无需使用上述任何函数编程!唯一的区别是glob会输出一个带有前缀路径的列表,但是你输入了它.
>>> import glob
>>> txt_files = glob.glob("test/*.txt")
['test/08.txt', 'test/02.txt', 'test/09.txt', 'test/04.txt', 'test/05.txt', 'test/06.txt', 'test/07.txt', 'test/03.txt', 'test/06.txt', 'test/01.txt', 'test/10.txt']
我通过输入相对路径或完整路径来输出列表的意思是什么 – 例如,如果你在测试目录中并且你调用了glob.glob("./*.txt’),你会得到一个类似的列表:
>>> glob.glob('./*.txt')
['./08.txt', './02.txt', './09.txt', ... ]
顺便说一句,./表示在同一目录中.或者,你可以不加前缀./ – 但字符串表示将相应地改变:
>>> glob.glob("*.txt") # already in directory containing the text files
['08.txt', '02.txt', '09.txt', ... ]
使用文件上下文管理器对文件执行某些操作
好吧,现在你的代码的问题是你打开这些连接到所有这些文件而不关闭它们.通常,在python中对文件执行某些操作的过程如下:
fd = open(filename, mode)
fd.method # could be write(), read(), readline(), etc...
fd.close()
现在,问题在于,如果在文件中调用方法的第二行出现问题,文件将永远不会关闭,并且您遇到了大麻烦.
为了防止这种情况,我们使用with关键字在Python中使用我们所谓的文件上下文管理器.这可确保文件在发生或不发生故障时关闭.
with open(filename, mode) as fd:
fd.method
用readline()读取文件的第一行
您可能已经知道,要提取文件的第一行,您只需打开它并调用readline()方法即可.我们希望对txt_files中列出的所有文本文件执行此操作,但是 – 您可以使用函数式编程映射函数执行此操作,但这次我们不会编写匿名函数(为了便于阅读):
>>> def read_first_line(file):
... with open(file, 'rt') as fd:
... first_line = fd.readline()
... return first_line
...
>>> output_strings = map(read_first_line, txt_files) # apply read first line function all text files
>>> print(output_strings)
['08 ', '02 ', '09 ', '04 ', '05 ', '06 ', '07 ', '03 ', '06 ', '01 ', '10 ']
如果要对output_list进行排序,只需事先对txt_files进行排序,或者只对output_list本身进行排序.两者都有效:
> output_strings = map(read_first_line,sorted(txt_files))
> output_strings = sorted(map(read_first_line,txt_files))
连接输出字符串并将它们写入输出文件
所以现在你有一个输出字符串列表,你要做的最后一件事是组合它们:
>>> output_content = "".join(sorted(output_strings)) # sort join the output strings without separators
>>> output_content # as a string
'01 02 03 04 05 06 07 08 09 10 '
>>> print(output_content) # print as formatted
01
02
03
04
05
06
07
08
09
10
现在只需将这个巨大的字符串写入输出文件即可!我们称之为outfile.txt:
>>> with open('outfile.txt', 'wt') as fd:
... fd.write(output_content)
...
那你就完成了!你们都准备好了!让我们确认一下:
>>> with open('outfile.txt', 'rt') as fd:
... print fd.readlines()
...
['01 ', '02 ', '03 ', '04 ', '05 ', '06 ', '07 ', '08 ', '09 ', '10 ']
以上所有功能
我将使用glob模块,以便它总是知道我将访问我的路径的目录,而无需使用os模块和诸如此类的绝对路径的麻烦.
import glob
def read_first_line(file):
"""Gets the first line from a file.
Returns
-------
str
the first line text of the input file
"""
with open(file, 'rt') as fd:
first_line = fd.readline()
return first_line
def merge_per_folder(folder_path, output_filename):
"""Merges first lines of text files in one folder, and
writes combined lines into new output file
Parameters
----------
folder_path : str
String representation of the folder path containing the text files.
output_filename : str
Name of the output file the merged lines will be written to.
"""
# make sure there's a slash to the folder path
folder_path += "" if folder_path[-1] == "/" else "/"
# get all text files
txt_files = glob.glob(folder_path + "*.txt")
# get first lines; map to each text file (sorted)
output_strings = map(read_first_line, sorted(txt_files))
output_content = "".join(output_strings)
# write to file
with open(folder_path + output_filename, 'wt') as outfile:
outfile.write(output_content)