如何在python中读取文件夹中的txt文件列表

时间:2016-02-27 17:14:28

标签: python

我是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")

4 个答案:

答案 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
  • 等...

列出指定目录中的所有文本文件

您可以通过两种方式执行此操作:

方法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个文件,因此通过使用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']

方法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通过输入相对路径或完整路径来输出列表 - 例如,如果您在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,因为它试图打开多次而不关闭前一个