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

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


当前回答

如果文档中也有空行,我希望读取内容并将其通过过滤器以防止空字符串元素

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

其他回答

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

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(默认为检查空行)参数是可选的。

您甚至可以删除read、write和delete方法,只保留FileIO.line,甚至将其转换为一个单独的方法read_lines。

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

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

open返回一个可以迭代的文件。当您遍历一个文件时,您会从该文件中获取行。tuple可以使用迭代器,并从您给它的迭代器中为您实例化一个tuple实例。

最简单的方法

一个简单的方法是:

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

在一行中,这将给出:

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

然而,这是一种非常低效的方式,因为这将在内存中存储两个版本的内容(对于小文件来说可能不是大问题,但仍然如此)。[谢谢Mark Amery]。

有两种更简单的方法:

将文件用作迭代器

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')]

如果您使用的是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()]

要将文件读取到列表中,需要执行以下三项操作:

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

幸运的是,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,表示“只读”。这正是你需要的。

但如果你真的想要创建一个文件和/或写入一个文件,你需要一个不同的参数。如果你想要一个概览,有一个很好的答案。

对于读取文件,可以省略模式或显式传入:

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

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

open(filename, 'rb')

在其他平台上,“b”(二进制模式)被简单地忽略。


既然我已经演示了如何打开该文件,那么让我们来谈谈您总是需要再次关闭它的事实。否则,它将保持文件的打开文件句柄,直到进程退出(或Python破坏文件句柄)。

虽然您可以使用:

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

当打开和关闭之间发生异常时,将无法关闭文件。您可以通过尝试并最终:

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

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

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

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

正在读取文件

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

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

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

这将打印文件的每一行。但是,请注意,每一行结尾都将包含一个换行符(您可能需要检查Python是否具有通用换行符支持,否则您也可以在Windows或Mac上使用换行符)。如果您不想这样做,可以简单地删除最后一个字符(或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)

但是您可以简单地删除字符串末尾的所有空格(包括字符),这也会删除所有其他尾随空格,因此如果这些空格很重要,您必须小心:

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

但是,如果行以\r\n(Windows“newlines”)结尾,.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()方法返回一个行列表:

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

这还将包括后面的换行符,如果你不想要它们,我建议使用[line.rstrip()for line-in-f]方法,因为它避免了在内存中保留包含所有行的两个列表。

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

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

or:

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

因为不包含拆分字符,所以它们会自动处理尾随换行符。然而,它们并不理想,因为您将文件保存为字符串和内存中的行列表!

总结

在打开文件时使用with open(…)作为f,因为您不需要自己关闭文件,即使发生异常,它也会关闭文件。文件对象支持迭代协议,因此逐行读取文件与file_object:中的行一样简单。始终浏览文档以查找可用的函数/类。大多数时候,这项任务有一个完美的匹配,或者至少有一两个好的匹配。在这种情况下,明显的选择是readlines(),但如果您想在将行存储在列表中之前处理它们,我建议您进行简单的列表理解。

如果你面对一个非常大/巨大的文件,并且想读得更快(假设你在TopCoder或HackerBank编码竞赛中),你可以一次将相当大的行块读入内存缓冲区,而不只是在文件级别逐行迭代。

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)