【问题标题】:How to read a file line-by-line into a list?如何将文件逐行读入列表?
【发布时间】:2011-03-17 16:34:33
【问题描述】:

如何在 Python 中读取文件的每一行并将每一行作为一个元素存储在列表中?

我想逐行读取文件并将每一行附加到列表的末尾。

【问题讨论】:

    标签: python string file readlines


    【解决方案1】:

    这段代码会将整个文件读入内存:

    with open(filename) as file:
        lines = file.readlines()
    

    如果您想删除每行末尾的所有空白字符(换行符和空格),请改用:

    with open(filename) as file:
        lines = [line.rstrip() for line in file]
    

    (这样可以避免从file.readlines() 分配额外的列表。)

    如果您正在处理一个大文件,那么您应该逐行读取和处理它:

    with open(filename) as file:
        for line in file:
            print(line.rstrip())
    

    在 Python 3.8 及更高版本中,您可以使用带有 walrus operator 的 while 循环,如下所示:

    with open(filename) as file:
        while line := file.readline():
            print(line.rstrip())
    

    【讨论】:

    • 如果您使用readlines() 处理大数据,效率不高,因为它可能导致MemoryError。在这种情况下,最好使用for line in f: 遍历文件并使用每个line 变量。
    • 我使用here 提到的过程检查了答案中给出的不同方式的内存配置文件。正如@DevShark here 所建议的那样,从文件中读取每一行并进行处理时,内存使用情况要好得多。如果内存受限或文件很大,则将所有行保存在集合对象中不是一个好主意。两种方法的执行时间相似。
    • 另外,.rstrip() 的工作速度会稍微快一些,如果您从行尾去除空格。
    • Oneliner:with open(filename) as f: content = [i.strip() for i in f.readlines()]
    • @只写[x.strip() for x in f] 而不要调用readlines()。这样您就不必分配额外的列表。
    【解决方案2】:

    Input and Ouput:

    with open('filename') as f:
        lines = f.readlines()
    

    或者去掉换行符:

    with open('filename') as f:
        lines = [line.rstrip('\n') for line in f]
    

    【讨论】:

    • 更好,使用f.read().splitlines(),它会删除换行符
    • 第二个版本,for line in open(filename) 安全吗?也就是文件会自动关闭吗?
    • 最好一次读取一行文件,而不是一次将整个文件读入内存。这样做不适用于大型输入文件。请参阅以下罗伯特的回答。
    • lines = [x.rstrip('\n') for x in open('data\hsf.txt','r')]这样写的话,怎么才能看完后关闭文件呢?
    • 是的,其他人在这里提出的观点,虽然在没有上下文管理器(或其他有保证的方式来关闭它)的情况下使用 open 不是“最佳实践”,但这并不是真正的一个在这些情况下 - 当对象不再引用它时,它将被垃圾收集并关闭文件,当列表理解完成处理时,这应该立即发生错误与否。
    【解决方案3】:

    这比必要的更明确,但可以满足您的需求。

    with open("file.txt") as file_in:
        lines = []
        for line in file_in:
            lines.append(line)
    

    【讨论】:

    • 我更喜欢这个答案,因为它不需要将整个文件加载到内存中(在这种情况下,它仍然附加到array,但可能还有其他情况)。当然,对于大文件,这种方法可能会缓解问题。
    • 追加到数组很慢。我想不出这是最佳解决方案的用例。
    • 注意:此解决方案不会删除换行符。
    • 此解决方案确实将整个文件加载到内存中。我不知道为什么人们认为它没有。
    • @andrebrait 它可以选择将整个文件加载到行[]中,但可以逐行加载。
    【解决方案4】:

    这将从文件中产生一个“数组”行。

    lines = tuple(open(filename, 'r'))
    

    open 返回一个可以迭代的文件。当您遍历文件时,您会从该文件中获取行。 tuple 可以获取一个迭代器并从您提供的迭代器中为您实例化一个元组实例。 lines 是从文件的行创建的元组。

    【讨论】:

    • @MarshallFarrier 请改用lines = open(filename).read().split('\n')
    • 它会关闭文件吗?
    • @Vanuan 由于该行运行后没有剩余的对该文件的引用,因此析构函数应该自动关闭该文件。
    • @NoctisSkytower 我觉得lines = open(filename).read().splitlines() 更干净一些,而且我相信它也能更好地处理 DOS 行尾。
    • @mklement0 假设文件有 1000 行,list 占用的空间比 tuple 多 13.22%。结果来自from sys import getsizeof as g; i = [None] * 1000; round((g(list(i)) / g(tuple(i)) - 1) * 100, 2)。创建tuple 比创建list 花费的时间大约多4.17%(标准差为0.16%)。结果来自运行from timeit import timeit as t; round((t('tuple(i)', 'i = [None] * 1000') / t('list(i)', 'i = [None] * 1000') - 1) * 100, 2) 30 次。当对可变性的需求未知时,我的解决方案更倾向于空间而不是速度。
    【解决方案5】:

    如果您希望包含\n

    with open(fname) as f:
        content = f.readlines()
    

    如果您不希望包含\n

    with open(fname) as f:
        content = f.read().splitlines()
    

    【讨论】:

    • 太好了,每行之间都包含空字符串。 '1\n2\n3\n' => [ '1', '', '2', '', '3', '' ]
    • @Joke 你一定是做错了什么(无意冒犯)。使用s = '1\n2\n3\n's.splitlines() 返回['1', '2', '3']。也许您的输入实际上包含空行? s = '1\n\n2\n\n3\n\n'
    【解决方案6】:

    根据Python的Methods of File Objects,将文本文件转换为list的最简单方法是:

    with open('file.txt') as f:
        my_list = list(f)
        # my_list = [x.rstrip() for x in f] # remove line breaks
    

    如果你只需要遍历文本文件行,你可以使用:

    with open('file.txt') as f:
        for line in f:
           ...
    

    旧答案:

    使用withreadlines()

    with open('file.txt') as f:
        lines = f.readlines()
    

    如果您不关心关闭文件,则此单行代码有效:

    lines = open('file.txt').readlines()
    

    传统的方式:

    f = open('file.txt') # Open file on read mode
    lines = f.read().splitlines() # List with stripped line-breaks
    f.close() # Close file
    

    【讨论】:

    • 第一个示例中的注释行 # my_list = [x.rstrip() for x in f] # remove line breaks 应该改为 # my_list = [x.rstrip() for x in my_list] # remove line breaks
    • @oneturkmen 不,他是对的。他正在遍历文件中的行。如果该行在'with'子句之后,你会是正确的
    【解决方案7】:

    按照建议,您可以简单地执行以下操作:

    with open('/your/path/file') as f:
        my_lines = f.readlines()
    

    请注意,这种方法有两个缺点:

    1) 您将所有行存储在内存中。在一般情况下,这是一个非常糟糕的主意。该文件可能非常大,您可能会耗尽内存。就算不大,也只是浪费内存。

    2) 这不允许在您阅读每一行时对其进行处理。因此,如果您在此之后处理您的线路,则效率不高(需要两次而不是一次)。

    一般情况下更好的方法如下:

    with open('/your/path/file') as f:
        for line in f:
            process(line)
    

    您可以在其中以任何您想要的方式定义您的流程功能。例如:

    def process(line):
        if 'save the world' in line.lower():
             superman.save_the_world()
    

    Superman 类的实现留给您作为练习)。

    这适用于任何文件大小,您只需 1 次即可浏览您的文件。这通常是通用解析器的工作方式。

    【讨论】:

    • 这正是我所需要的——感谢您解释缺点。作为 Python 的初学者,理解为什么解决方案就是解决方案真是太棒了。干杯!
    • 多想想科里。您是否真的希望您的计算机读取每一行,而不对这些行做任何事情?当然,您可以意识到您总是需要以一种或另一种方式处理它们。
    • 你总是需要对线条做一些事情。它可以像打印线条或计算线条一样简单。让您的进程读取内存中的行没有任何价值,但不对其进行任何操作。
    • 你总是需要和他们做点什么。我认为您要表达的观点是您可能希望一次将一个函数应用于所有这些函数,而不是一个一个地应用。有时确实是这样。但是从内存的角度来看这样做是非常低效的,并且如果文件的占用空间大于您的 Ram,则会阻止您读取文件。这就是为什么通常通用解析器以我描述的方式运行的原因。
    • @PierreOcinom 是正确的。鉴于文件以只读模式打开,您无法使用上面的代码修改原始文件。要打开文件进行读写,请使用open('file_path', 'r+')
    【解决方案8】:

    拥有文本文件内容:

    line 1
    line 2
    line 3
    

    我们可以在上面的txt同目录下使用这个Python脚本

    >>> with open("myfile.txt", encoding="utf-8") as file:
    ...     x = [l.rstrip("\n") for l in file]
    >>> x
    ['line 1','line 2','line 3']
    

    使用追加:

    x = []
    with open("myfile.txt") as file:
        for l in file:
            x.append(l.strip())
    

    或者:

    >>> x = open("myfile.txt").read().splitlines()
    >>> x
    ['line 1', 'line 2', 'line 3']
    

    或者:

    >>> x = open("myfile.txt").readlines()
    >>> x
    ['linea 1\n', 'line 2\n', 'line 3\n']
    

    或者:

    def print_output(lines_in_textfile):
        print("lines_in_textfile =", lines_in_textfile)
    
    y = [x.rstrip() for x in open("001.txt")]
    print_output(y)
    
    with open('001.txt', 'r', encoding='utf-8') as file:
        file = file.read().splitlines()
        print_output(file)
    
    with open('001.txt', 'r', encoding='utf-8') as file:
        file = [x.rstrip("\n") for x in file]
        print_output(file)
    

    输出:

    lines_in_textfile = ['line 1', 'line 2', 'line 3']
    lines_in_textfile = ['line 1', 'line 2', 'line 3']
    lines_in_textfile = ['line 1', 'line 2', 'line 3']
    

    【讨论】:

    • 是否需要encoding="utf-8"
    • read().splitlines() 是由 Python 提供给你的:它只是 readlines()(这可能更快,因为它不那么浪费)。
    • @EricOLebigot 从显示的示例中,看起来 read().splitlines()readlines() 不会产生相同的输出。你确定它们是等价的吗?
    • 如果你只使用readlines,你需要使用strip方法去掉文本中的\n,所以我用列表推导改变了最后的例子,在两种情况下都有相同的输出.因此,如果您使用 read().readlines() 您将拥有一个“干净”的项目,其中包含该行且没有换行符,否则,您必须执行您在上面代码中看到的操作。
    • 确实如此。请注意,在上面的所有代码中,strip() 应该是rstrip("\n"),否则将删除一行周围的空格。此外,在列表理解中执行 readlines() 毫无意义:简单地迭代文件会更好,因为它不会通过创建行的中间列表来浪费时间和内存。
    【解决方案9】:

    要将文件读入列表,您需要做三件事:

    • 打开文件
    • 读取文件
    • 将内容存储为列表

    幸运的是 Python 让这些事情变得非常容易,因此将文件读入列表的最短方法是:

    lst = list(open(filename))
    

    不过我会添加更多解释。

    打开文件

    我假设您想要打开一个特定的文件,并且您不直接处理文件句柄(或类似文件的句柄)。在 Python 中打开文件最常用的函数是 open,在 Python 2.7 中它需要一个强制参数和两个可选参数:

    • 文件名
    • 模式
    • 缓冲(我将在此答案中忽略此论点)

    文件名应该是一个字符串,表示文件的路径。例如:

    open('afile')   # opens the file named afile in the current working directory
    open('adir/afile')            # relative path (relative to the current working directory)
    open('C:/users/aname/afile')  # absolute path (windows)
    open('/usr/local/afile')      # absolute path (linux)
    

    请注意,需要指定文件扩展名。这对于 Windows 用户来说尤其重要,因为在资源管理器中查看时,.txt.doc 等文件扩展名在默认情况下是隐藏的

    第二个参数是mode,默认是r,意思是“只读”。这正是您所需要的。

    但如果你真的想创建一个文件和/或写入一个文件,你需要一个不同的参数。 There is an excellent answer if you want an overview.

    要读取文件,您可以省略 mode 或显式传递:

    open(filename)
    open(filename, 'r')
    

    两者都将以只读模式打开文件。如果你想在 Windows 上读取二进制文件,你需要使用模式rb

    open(filename, 'rb')
    

    在其他平台上,'b'(二进制模式)会被忽略。


    现在我已经展示了如何open 文件,让我们谈谈您总是需要再次close 的事实。否则,它将保留文件的打开文件句柄,直到进程退出(或 Python 垃圾文件句柄)。

    虽然你可以使用:

    f = open(filename)
    # ... do stuff with f
    f.close()
    

    openclose 之间的某些东西抛出异常时,将无法关闭文件。你可以通过使用tryfinally 来避免这种情况:

    f = open(filename)
    # nothing in between!
    try:
        # do stuff with f
    finally:
        f.close()
    

    但是 Python 提供的上下文管理器具有更漂亮的语法(但对于 open,它几乎与上面的 tryfinally 相同):

    with open(filename) as f:
        # do stuff with f
    # The file is always closed after the with-scope ends.
    

    最后一种方法是推荐在 Python 中打开文件的方法!

    读取文件

    好的,你已经打开了文件,现在如何读取它?

    open 函数返回一个file 对象,它支持 Python 的迭代协议。每次迭代都会给你一行:

    with open(filename) as f:
        for line in f:
            print(line)
    

    这将打印文件的每一行。但是请注意,每行最后都会包含一个换行符 \n(您可能需要检查您的 Python 是否使用 universal newlines support 构建 - 否则您也可以在 Windows 上使用 \r\n 或在 Mac 上使用 \r 作为换行符)。如果您不希望这样,您可以简单地删除最后一个字符(或 Windows 上的最后两个字符):

    with open(filename) as f:
        for line in f:
            print(line[:-1])
    

    但最后一行不一定有尾随换行符,所以不应该使用它。可以检查它是否以尾随换行符结尾,如果是,则将其删除:

    with open(filename) as f:
        for line in f:
            if line.endswith('\n'):
                line = line[:-1]
            print(line)
    

    但是您可以简单地从字符串的 结尾 中删除所有空格(包括 \n 字符),这也将删除所有其他 尾随 空格,因此您有如果这些很重要,请小心:

    with open(filename) as f:
        for line in f:
            print(f.rstrip())
    

    但是,如果行以\r\n(Windows“换行符”)结尾,那么.rstrip() 也会处理\r

    将内容存储为列表

    现在您已经知道如何打开和阅读文件,是时候将内容存储在列表中了。最简单的选择是使用list 函数:

    with open(filename) as f:
        lst = list(f)
    

    如果您想去除尾随换行符,您可以使用列表推导:

    with open(filename) as f:
        lst = [line.rstrip() for line in f]
    

    或者更简单:file 对象的.readlines() 方法默认返回list 行:

    with open(filename) as f:
        lst = f.readlines()
    

    这也将包括尾随换行符,如果您不想要它们,我会推荐 [line.rstrip() for line in f] 方法,因为它避免了在内存中保留两个包含所有行的列表。

    还有一个额外的选项可以获得所需的输出,但它相当“次优”:read 将完整的文件放在一个字符串中,然后在换行符处拆分:

    with open(filename) as f:
        lst = f.read().split('\n')
    

    或:

    with open(filename) as f:
        lst = f.read().splitlines()
    

    这些会自动处理尾随换行符,因为不包含 split 字符。但是它们并不理想,因为您将文件保存为字符串和内存中的行列表!

    总结

    • 打开文件时使用with open(...) as f,因为您不需要自己关闭文件,即使发生异常也会关闭文件。
    • file 对象支持迭代协议,因此逐行读取文件就像 for line in the_file_object: 一样简单。
    • 始终浏览可用函数/类的文档。大多数时候,任务有一个完美的匹配,或者至少有一两个好的匹配。在这种情况下,显而易见的选择是 readlines(),但如果您想在将这些行存储到列表之前对其进行处理,我建议您使用简单的列表理解。

    【讨论】:

    • 最后一种方法是在 Python 中打开文件的推荐方法! 那为什么是最后一种呢?在继续之前,绝大多数人不会只看一下答案的前几行吗?
    • @AMC 我写答案时并没有考虑太多。你认为我应该把它放在答案的顶部吗?
    • 这可能是最好的,是的。我还刚刚注意到您提到了 Python 2,因此也可以对其进行更新。
    • 啊问题最初被标记为 python-2.x。更普遍地更新它可能是有意义的。我会看看我下次会不会来。感谢您的建议。非常感谢!
    【解决方案10】:

    将文件行读入列表的简洁和 Pythonic 方式


    首先,您应该专注于以高效且 Python 的方式打开文件并读取其内容。这是我个人不喜欢的方式的一个例子:

    infile = open('my_file.txt', 'r')  # Open the file for reading.
    
    data = infile.read()  # Read the contents of the file.
    
    infile.close()  # Close the file since we're done using it.
    

    相反,我更喜欢以下打开文件以进行读写的方法,因为它 非常干净,不需要关闭文件的额外步骤 一旦你完成使用它。在下面的语句中,我们打开文件 用于读取,并将其分配给变量“infile”。一旦里面的代码 该语句运行完毕,文件将自动关闭。

    # Open the file for reading.
    with open('my_file.txt', 'r') as infile:
    
        data = infile.read()  # Read the contents of the file into memory.
    

    现在我们需要专注于将这些数据放入 Python 列表,因为它们是可迭代的、高效的和灵活的。在您的情况下,所需的目标是将文本文件的每一行放入一个单独的元素中。为此,我们将使用 splitlines() 方法,如下所示:

    # Return a list of the lines, breaking at line boundaries.
    my_list = data.splitlines()
    

    最终产品:

    # Open the file for reading.
    with open('my_file.txt', 'r') as infile:
    
        data = infile.read()  # Read the contents of the file into memory.
    
    # Return a list of the lines, breaking at line boundaries.
    my_list = data.splitlines()
    

    测试我们的代码:

    • 文本文件的内容:
         A fost odatã ca-n povesti,
         A fost ca niciodatã,
         Din rude mãri împãrãtesti,
         O prea frumoasã fatã.
    
    • 出于测试目的打印语句:
        print my_list  # Print the list.
    
        # Print each line in the list.
        for line in my_list:
            print line
    
        # Print the fourth element in this list.
        print my_list[3]
    
    • 输出(由于 unicode 字符而看起来不同):
         ['A fost odat\xc3\xa3 ca-n povesti,', 'A fost ca niciodat\xc3\xa3,',
         'Din rude m\xc3\xa3ri \xc3\xaemp\xc3\xa3r\xc3\xa3testi,', 'O prea
         frumoas\xc3\xa3 fat\xc3\xa3.']
    
         A fost odatã ca-n povesti, A fost ca niciodatã, Din rude mãri
         împãrãtesti, O prea frumoasã fatã.
    
         O prea frumoasã fatã.
    

    【讨论】:

      【解决方案11】:

      在 Python 3.4 中引入,pathlib 提供了一种非常方便的从文件中读取文本的方法,如下所示:

      from pathlib import Path
      p = Path('my_text_file')
      lines = p.read_text().splitlines()
      

      splitlines 调用将其从包含文件全部内容的字符串转换为文件中的行列表)。

      pathlib 有很多方便的地方。 read_text 简洁明了,您不必担心打开和关闭文件。如果你需要对文件做的所有事情都是一口气读完,这是一个不错的选择。

      【讨论】:

        【解决方案12】:

        这是对文件使用列表推导的另一种选择;

        lines = [line.rstrip() for line in open('file.txt')]
        

        这应该是更有效的方式,因为大部分工作都是在 Python 解释器中完成的。

        【讨论】:

        • rstrip() 可能会删除 all 尾随空格,而不仅仅是 \n;使用.rstrip('\n')
        • 这也不能保证在读取所有 Python 实现后文件会被关闭(尽管在主要的 Python 实现 CPython 中会关闭)。
        • 这应该是更有效的方式,因为大部分工作都是在 Python 解释器中完成的。 这是什么意思?
        【解决方案13】:
        f = open("your_file.txt",'r')
        out = f.readlines() # will append in the list out
        

        现在变量 out 是您想要的列表(数组)。你可以这样做:

        for line in out:
            print (line)
        

        或者:

        for line in f:
            print (line)
        

        你会得到相同的结果。

        【讨论】:

          【解决方案14】:

          使用 Python 2 和 Python 3 读写文本文件;它适用于 Unicode

          #!/usr/bin/env python3
          # -*- coding: utf-8 -*-
          
          # Define data
          lines = ['     A first string  ',
                   'A Unicode sample: €',
                   'German: äöüß']
          
          # Write text file
          with open('file.txt', 'w') as fp:
              fp.write('\n'.join(lines))
          
          # Read text file
          with open('file.txt', 'r') as fp:
              read_lines = fp.readlines()
              read_lines = [line.rstrip('\n') for line in read_lines]
          
          print(lines == read_lines)
          

          注意事项:

          • with 就是所谓的context manager。它确保打开的文件再次关闭。
          • 此处所有仅生成 .strip().rstrip() 的解决方案都将无法重现 lines,因为它们还会去除空白。

          常用文件结尾

          .txt

          更高级的文件写入/读取

          对于您的应用程序,以下内容可能很重要:

          • 其他编程语言的支持
          • 读/写性能
          • 紧凑性(文件大小)

          另请参阅:Comparison of data serialization formats

          如果您正在寻找一种制作配置文件的方法,您可能需要阅读我的短文Configuration files in Python

          【讨论】:

            【解决方案15】:

            如果您想从命令行或标准输入读取文件,也可以使用fileinput 模块:

            # reader.py
            import fileinput
            
            content = []
            for line in fileinput.input():
                content.append(line.strip())
            
            fileinput.close()
            

            像这样将文件传递给它:

            $ python reader.py textfile.txt 
            

            在此处阅读更多信息:http://docs.python.org/2/library/fileinput.html

            【讨论】:

              【解决方案16】:

              另一个选项是numpy.genfromtxt,例如:

              import numpy as np
              data = np.genfromtxt("yourfile.dat",delimiter="\n")
              

              这将使data 成为一个 NumPy 数组,其中包含与文件中一样多的行。

              【讨论】:

                【解决方案17】:

                最简单的方法

                一个简单的方法是:

                1. 将整个文件作为字符串读取
                2. 逐行拆分字符串

                在一行中,这将给出:

                lines = open('C:/path/file.txt').read().splitlines()
                

                但是,这是一种非常低效的方法,因为这会将 2 个版本的内容存储在内存中(对于小文件来说可能不是大问题,但仍然如此)。 [感谢马克艾默里]。

                有两种更简单的方法:

                1. 将文件用作迭代器
                lines = list(open('C:/path/file.txt'))
                # ... or if you want to have a list without EOL characters
                lines = [l.rstrip() for l in open('C:/path/file.txt')]
                
                1. 如果您使用的是 Python 3.4 或更高版本,最好使用pathlib 为您的文件创建一个路径,以便您可以在程序中进行其他操作:
                from pathlib import Path
                file_path = Path("C:/path/file.txt") 
                lines = file_path.read_text().split_lines()
                # ... or ... 
                lines = [l.rstrip() for l in file_path.open()]
                

                【讨论】:

                • 这是一个糟糕的方法。一方面,调用.read().splitlines() 并不比调用.readlines() 更“简单”。另一方面,它的内存效率低;您无需同时在内存中存储两个版本的文件内容(.read() 返回的单个字符串和splitlines() 返回的字符串列表)。
                • @MarkAmery 真的。感谢您强调这一点。我已经更新了我的答案。
                【解决方案18】:

                只需使用 splitlines() 函数。这是一个例子。

                inp = "file.txt"
                data = open(inp)
                dat = data.read()
                lst = dat.splitlines()
                print lst
                # print(lst) # for python 3
                

                在输出中,您将获得行列表。

                【讨论】:

                • 与使用 .readlines() 相比,内存效率低。这会将文件内容的两个副本一次放入内存中(一个作为单个大字符串,一个作为行列表)。
                • 但是data.read().splitlines() 更容易阅读,与阅读代码相比,内存并不总是一个问题。
                【解决方案19】:

                如果您想面对非常大/巨大的文件并希望更快地阅读(想象一下您正在参加 Topcoder/Hackerrank 编码比赛),您可能一次将大量行读入内存缓冲区,而不是在文件级别逐行迭代。

                buffersize = 2**16
                with open(path) as f: 
                    while True:
                        lines_buffer = f.readlines(buffersize)
                        if not lines_buffer:
                            break
                        for line in lines_buffer:
                            process(line)
                

                【讨论】:

                • process(line) 是做什么的?我得到一个错误,没有定义这样的变量。我想有些东西需要导入,我尝试导入 multiprocessing.Process,但我猜不是这样。你能详细说明一下吗?谢谢
                • process(line) 是您需要实现以处理数据的函数。例如,如果您使用print(line),而不是该行,它将打印lines_buffer中的每一行。
                • f.readlines(buffersize) 返回一个不可变的缓冲区。如果要直接读入缓冲区,则需要使用 readinto() 函数。我会快得多。
                【解决方案20】:

                具有一些额外好处的最简单方法是:

                lines = list(open('filename'))
                

                lines = tuple(open('filename'))
                

                lines = set(open('filename'))
                

                set 的情况下,我们必须记住我们没有保留行顺序并删除重复的行。

                下面我添加了一个来自@MarkAmery的重要补充:

                由于您没有在文件对象上调用.close 也没有使用with 语句,在某些Python 实现中文件可能不会在读取后关闭,您的进程将泄漏打开的文件句柄

                CPython(大多数人使用的普通 Python 实现)中,这不是问题,因为文件对象会立即被垃圾收集并这将关闭文件,但通常认为最好的做法是执行类似

                with open('filename') as f: lines = list(f) 
                

                以确保无论您使用什么 Python 实现,文件都会关闭。

                【讨论】:

                • 由于您没有在文件对象上调用.close 也没有使用with 语句,在某些Python 实现中,文件可能不会在读取后关闭,并且您的进程将泄漏打开的文件句柄.在 CPython(大多数人使用的普通 Python 实现)中,这不是问题,因为文件对象将立即被垃圾收集,这将关闭文件,但通常认为最好的做法是执行 with open('filename') as f: lines = list(f) 之类的操作以确保无论您使用什么 Python 实现,文件都会被关闭。
                • 感谢您的精彩评论@MarkAmery!我真的很感激。
                • @simhumileco 为什么最好(正确)的解决方案最后?
                • @AMC 因为首先,我想展示最简单的方法和推理的一致性。
                • 另外,我希望我的回答简短易读。
                【解决方案21】:

                使用这个:

                import pandas as pd
                data = pd.read_csv(filename) # You can also add parameters such as header, sep, etc.
                array = data.values
                

                data 是一种数据帧类型,使用值来获取 ndarray。您也可以使用array.tolist()获取列表。

                【讨论】:

                • pandas.read_csv()是用来读取CSV数据的,这里怎么合适?
                【解决方案22】:

                大纲与总结

                使用filename,处理来自Path(filename) 对象的文件,或直接使用open(filename) as f,执行以下操作之一:

                • list(fileinput.input(filename))
                • 使用with path.open() as f,拨打f.readlines()
                • list(f)
                • path.read_text().splitlines()
                • path.read_text().splitlines(keepends=True)
                • 逐行迭代fileinput.inputflist.append
                • f 传递给绑定的list.extend 方法
                • 在列表理解中使用f

                我在下面解释每个用例。

                在 Python 中,如何逐行读取文件?

                这是一个很好的问题。首先,让我们创建一些示例数据:

                from pathlib import Path
                Path('filename').write_text('foo\nbar\nbaz')
                

                文件对象是惰性迭代器,因此只需对其进行迭代。

                filename = 'filename'
                with open(filename) as f:
                    for line in f:
                        line # do something with the line
                

                或者,如果您有多个文件,请使用 fileinput.input,另一个惰性迭代器。只有一个文件:

                import fileinput
                
                for line in fileinput.input(filename): 
                    line # process the line
                

                或者对于多个文件,传递一个文件名列表:

                for line in fileinput.input([filename]*2): 
                    line # process the line
                

                同样,ffileinput.input 以上都是/返回惰性迭代器。 您只能使用一次迭代器,因此为了提供功能代码同时避免冗长,我将使用更简洁的fileinput.input(filename) where apropos from here。

                在 Python 中,如何将文件逐行读入列表?

                啊,但出于某种原因,您希望将其列在列表中?如果可能的话,我会避免这种情况。但如果你坚持...只需将fileinput.input(filename) 的结果传递给list

                list(fileinput.input(filename))
                

                另一个直接的答案是调用f.readlines,它返回文件的内容(最多可选hint 字符数,因此您可以通过这种方式将其分解为多个列表)。

                您可以通过两种方式访问​​此文件对象。一种方法是将文件名传递给 open 内置函数:

                filename = 'filename'
                
                with open(filename) as f:
                    f.readlines()
                

                或使用来自pathlib 模块的新 Path 对象(我已经非常喜欢,并且将从这里开始使用):

                from pathlib import Path
                
                path = Path(filename)
                
                with path.open() as f:
                    f.readlines()
                

                list 也会使用文件迭代器并返回一个列表——也是一个非常直接的方法:

                with path.open() as f:
                    list(f)
                

                如果您不介意在拆分之前将整个文本作为单个字符串读取到内存中,您可以使用Path 对象和splitlines() 字符串方法将其作为单行来执行。默认情况下,splitlines 会删除换行符:

                path.read_text().splitlines()
                

                如果要保留换行符,请传递keepends=True:

                path.read_text().splitlines(keepends=True)
                

                我想逐行读取文件并将每一行附加到列表的末尾。

                考虑到我们已经用几种方法轻松地演示了最终结果,现在要求这个有点愚蠢。但是您可能需要在制作列表时对行进行过滤或操作,所以让我们满足这个要求吧。

                使用list.append 将允许您在附加前对每一行进行过滤或操作:

                line_list = []
                for line in fileinput.input(filename):
                    line_list.append(line)
                
                line_list
                

                使用list.extend 会更直接一些,如果您有一个预先存在的列表,可能会很有用:

                line_list = []
                line_list.extend(fileinput.input(filename))
                line_list
                

                或者更惯用的说法,我们可以改为使用列表推导,并在需要时在其中映射和过滤:

                [line for line in fileinput.input(filename)]
                

                或者更直接,要闭环,直接传给list就可以新建一个list,不用对行进行操作:

                list(fileinput.input(filename))
                

                结论

                您已经看到了许多将文件中的行获取到列表中的方法,但我建议您避免将大量数据具体化到列表中,而是尽可能使用 Python 的惰性迭代来处理数据。

                也就是说,更喜欢fileinput.inputwith path.open() as f

                【讨论】:

                  【解决方案23】:

                  如果文档中也有空行我喜欢在内容中读取并通过filter 传递以防止出现空字符串元素

                  with open(myFile, "r") as f:
                      excludeFileContent = list(filter(None, f.read().splitlines()))
                  

                  【讨论】:

                  • 这是非pythonic,小心。
                  【解决方案24】:

                  我喜欢使用以下内容。立即阅读这些行。

                  contents = []
                  for line in open(filepath, 'r').readlines():
                      contents.append(line.strip())
                  

                  或者使用列表推导:

                  contents = [line.strip() for line in open(filepath, 'r').readlines()]
                  

                  【讨论】:

                  • 不需要readlines(),它甚至会导致内存损失。您可以简单地删除它,因为迭代(文本)文件会依次给出每一行。
                  • 您应该使用with 语句打开(并隐式关闭)文件。
                  【解决方案25】:

                  您也可以在 NumPy 中使用 loadtxt 命令。这检查的条件比 genfromtxt 少,因此可能更快。

                  import numpy
                  data = numpy.loadtxt(filename, delimiter="\n")
                  

                  【讨论】:

                    【解决方案26】:

                    我会尝试以下提到的方法之一。我使用的示例文件名为dummy.txt。您可以找到文件here。我认为该文件与代码位于同一目录中(您可以更改 fpath 以包含正确的文件名和文件夹路径。)

                    在下面提到的两个示例中,您想要的列表都由lst 给出。

                    1.>第一种方法

                    fpath = 'dummy.txt'
                    with open(fpath, "r") as f: lst = [line.rstrip('\n \t') for line in f]
                    
                    print lst
                    >>>['THIS IS LINE1.', 'THIS IS LINE2.', 'THIS IS LINE3.', 'THIS IS LINE4.']
                    

                    2.>第二种方法中,可以使用Python标准库中的csv.reader模块

                    import csv
                    fpath = 'dummy.txt'
                    with open(fpath) as csv_file:
                        csv_reader = csv.reader(csv_file, delimiter='   ')
                        lst = [row[0] for row in csv_reader] 
                    
                    print lst
                    >>>['THIS IS LINE1.', 'THIS IS LINE2.', 'THIS IS LINE3.', 'THIS IS LINE4.']
                    

                    您可以使用这两种方法中的任何一种。两种方法创建lst 所用的时间几乎相等。

                    【讨论】:

                    • 第二种方法的优势是什么?为什么要调用一个额外的库,它会添加边缘情况(分隔符和引号)?
                    • delimiter=' ' 参数的用途是什么?
                    【解决方案27】:

                    这是我用来简化文件 I/O 的 Python(3) 助手 library 类:

                    import os
                    
                    # handle files using a callback method, prevents repetition
                    def _FileIO__file_handler(file_path, mode, callback = lambda f: None):
                      f = open(file_path, mode)
                      try:
                        return callback(f)
                      except Exception as e:
                        raise IOError("Failed to %s file" % ["write to", "read from"][mode.lower() in "r rb r+".split(" ")])
                      finally:
                        f.close()
                    
                    
                    class FileIO:
                      # return the contents of a file
                      def read(file_path, mode = "r"):
                        return __file_handler(file_path, mode, lambda rf: rf.read())
                    
                      # get the lines of a file
                      def lines(file_path, mode = "r", filter_fn = lambda line: len(line) > 0):
                        return [line for line in FileIO.read(file_path, mode).strip().split("\n") if filter_fn(line)]
                    
                      # create or update a file (NOTE: can also be used to replace a file's original content)
                      def write(file_path, new_content, mode = "w"):
                        return __file_handler(file_path, mode, lambda wf: wf.write(new_content))
                    
                      # delete a file (if it exists)
                      def delete(file_path):
                        return os.remove() if os.path.isfile(file_path) else None
                    

                    然后您将使用FileIO.lines 函数,如下所示:

                    file_ext_lines = FileIO.lines("./path/to/file.ext"):
                    for i, line in enumerate(file_ext_lines):
                      print("Line {}: {}".format(i + 1, line))
                    

                    请记住,mode(默认为"r")和filter_fn(默认检查空行)参数是可选的。

                    您甚至可以删除readwritedelete 方法而只保留FileIO.lines,或者甚至将其变成一个名为read_lines 的单独方法。

                    【讨论】:

                    • lines = FileIO.lines(path) 真的比with open(path) as f: lines = f.readlines() 简单到足以证明这个助手的存在吗?每次通话可以节省 17 个字符。 (而且大多数时候,出于性能和内存的原因,你会想要直接循环一个文件对象,而不是把它的行读入一个列表,所以你甚至不想经常使用它!)我是通常是创建小型实用程序函数的粉丝,但在我看来,这只是不必要地创建一种新方法来编写已经很短且容易使用标准库提供的东西。
                    • 除了@MarkAmery 所说的,为什么要为此使用一个类?
                    【解决方案28】:

                    命令行版本

                    #!/bin/python3
                    import os
                    import sys
                    abspath = os.path.abspath(__file__)
                    dname = os.path.dirname(abspath)
                    filename = dname + sys.argv[1]
                    arr = open(filename).read().split("\n") 
                    print(arr)
                    

                    运行:

                    python3 somefile.py input_file_name.txt
                    

                    【讨论】:

                    • 你到底为什么要要求文本文件在你的 python 脚本所在的同一目录中?只需 open(sys.argv[1]) 即可,无论指定相对路径还是绝对路径,它都可以工作,而且它不会关心您的脚本所在的位置。
                    猜你喜欢
                    • 2012-11-05
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-05-21
                    • 1970-01-01
                    • 2019-03-26
                    相关资源
                    最近更新 更多