我是python的新手,我写了一个算法来读取文件夹中的10个txt文件,然后在一个txt outfile中写下每个文件的第一行。但它不起作用。我的意思是在我运行它之后,我既不会遇到任何错误也不会得到outfile。
def MergePerFolder(path):
path1=listdir_fullpath(path)
for i in path1:
infile=open(i)
outfile=open('F:// merge1.txt', 'w')
a=infile.readline().split('.')
for k in range (len(a)):
print(a[0], file=outfile, end='')
infile.close()
outfile.close
print("done")
答案 0 :(得分:19)
假设您在此文件夹中有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
,您可以通过两种方式执行此操作:
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
个文件,因此通过使用filter
函数和匿名函数进行一些函数式编程,您可以轻松地过滤掉它们,而无需使用标准的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']
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
通过输入相对路径或完整路径来输出列表 - 例如,如果您在test
目录中并且调用了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
中列出的所有文本文件执行此操作,但是 - 您可以使用函数式编程map
函数执行此操作,但这次我们不会编写匿名函数(为了便于阅读) ):
>>> 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\n', '02\n', '09\n', '04\n', '05\n', '06\n', '07\n', '03\n', '06\n', '01\n', '10\n']
如果您希望对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\n02\n03\n04\n05\n06\n07\n08\n09\n10\n'
>>> 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\n', '02\n', '03\n', '04\n', '05\n', '06\n', '07\n', '08\n', '09\n', '10\n']
我将使用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)
答案 1 :(得分:2)
让我们假设您在文件夹路径中有文件
path = /home/username/foldername/
所以你拥有路径文件夹中的所有文件,读取你应该使用os
或`glob'的文件夹中的所有文件。
import os
path = "/home/username/foldername/"
savepath = "/home/username/newfolder/"
for dir,subdir,files in os.walk(path):
infile = open(path+files)
outfile = open(savepath,'w')
a = infile.readline().split('.')
for k in range (0,len(a)):
print(a[0], file=outfile, end='')
infile.close()
outfile.close
print "done"
或使用glob你可以做更少的代码。
import glob
path = "/home/username/foldername/"
savepath = "/home/username/newfolder/"
for files in glob.glob(path +"*.txt"):
infile = open(files)
outfile = open(savepath,'w')
a = infile.readline().split('.')
for k in range (0,len(a)):
print(a[0], file=outfile, end='')
infile.close()
outfile.close
print "done"
希望它可能适合你。
答案 2 :(得分:1)
感谢Eddo Hintoso的详细回答,我对它进行了微调,使其使用yield
而不是return
,因此不需要进行映射。我将其发布在这里,以防其他人找到该帖子。
import glob
files = glob.glob("data/*.txt")
def map_first_lines(file_list):
for file in file_list:
with open(file, 'r') as fd:
yield fd.readline()
[print(f) for f in map_first_lines(files)]
解决这个特殊问题的另一种方法:
import glob
def map_first_lines(file_list):
for file in file_list:
with open(file, 'rt') as fd:
yield fd.readline()
def merge_first_lines(file_list, filename='first_lines.txt'):
with open(filename, 'w') as f:
for line in map_first_lines(file_list):
f.write("%s\n" % line)
files = glob.glob("data/*.txt")
merge_first_lines(files)
答案 3 :(得分:-1)
可能是你应该在循环中关闭outfile,因为它试图打开多次而不关闭前一个