geekdoc-python-zh/docs/pythonland/42.md

17 KiB
Raw Permalink Blame History

Python 读写文件:示例

原文:https://python.land/operating-system/python-files

文件是使用计算机的重要组成部分,因此使用 Python 读写文件是您需要掌握的基本技能。在本文中,我将向您展示如何完成您的目标,例如:

  • 如何在 Python 中打开文件
  • 用 Python 读取文件(一次或逐行)
  • 用 Python 写文件
  • 复制、移动、重命名和删除文件
  • 检查文件或目录是否存在

当处理文件时,你需要了解文件模式和权限。如果你需要的话,我也包括了对这个主题的解释。

目录

用 Python 打开一个文件

在 Python 中,我们用open() 函数打开一个文件。这是 Python 内置函数的一部分,你不需要导入任何东西来使用open()。open()函数至少需要一个参数:文件名。如果文件成功打开,它将返回一个 file 对象,您可以使用该对象读取和写入该文件。

当你用 Python 打开一个文件时,你正在使用系统资源,一旦你完成了,你需要释放这些资源。如果不这样做,就会造成所谓的资源泄漏。如果您经常这样做,您可能会遇到问题,因为普通操作系统用户可以打开的文件数量是有限的。

不过这不一定是个问题。当您的程序退出时所有资源都会自动释放。Python 开发者的想法很好,也很体贴,但是很多软件都是无限期运行的。有了这样的软件,你需要更加小心,关闭你不再需要的资源。这样,您可以确保其他软件可以安全地访问该文件。此外,当您打开许多文件时,每个打开的文件都会占用内存和其他资源。由于这些原因,当你完成一个文件时,关闭它是一个好习惯。

关闭文件曾经是一项手动任务很容易被忘记。幸运的是Python 有with语句来帮助我们。我们将很快讨论with声明。我首先要向你展示“老式的做事方法”。

打开文件的老式方法

为了说明 with 语句如此有用的原因,让我们首先以传统的手动方式打开和关闭一个文件:

https://crumb . sh/embed/aetlu 9 ifs

打开文件的老式方法。您应该更喜欢使用 with 语句。

如果你想冒险,试着去掉f.close()。它应该是一样的Python 不会抱怨,会在退出时关闭文件资源。

如果上面的交互式示例由于某种原因无法运行,下面是相同代码的文本版本:

f = open('text.txt')
print(f.read())
f.close()

Python 一次读取文件内容

在上面的例子中,您可以看到我们如何从文件中读取所有内容,以便打印它。如果您想一次将所有文件内容读入一个字符串,请对 file 对象使用read()方法,不带参数。这对于小文件来说没有问题,但是要意识到你是一次将所有的内容加载到内存中。这可能是大文件的一个问题,但是我们很快就会解决这个问题。

在 Python 中使用 with open()

在前面的例子中有一个潜在的问题。如果在 Python 读取文件时发生了异常,那么f.close()调用将永远不会到达。这是一个微不足道的例子,但是你可以想象,对于更复杂的软件,其中的异常可能会被捕获,以便软件可以继续运行,它可能会很快出错。

另一个可能出现的问题是,您只是忘记编写 close()调用。它发生了,我们都是人类。因此,对于现代 Python建议尽可能使用 with 语句。通过使用 Python 的with open(),打开的文件资源将只在缩进的代码块中可用:

https://crumb.sh/embed/39hFGitfZhd

如果上面的交互式示例由于某种原因无法运行,下面是相同代码的文本版本:

with open('text.txt') as f:
    text = f.read()

print(text)

在本例中,with 语句确保文件关闭,即使发生异常。这是因为一旦我们跳出这个 with 语句的范围Python 就会自动关闭资源。由于这种自动关闭,您不能在 with 语句之外使用文件(在我们的例子中称为f)。如果你想再次使用它,你必须再次打开它。

文件模式

到目前为止,我们使用的open()函数只有一个参数:文件名。这是一个强制参数,但是 open()也有一些可选的额外参数,比如文件 模式 。该模式默认为“rt”代表' r ead t ext '。你打开文件是为了读,这意味着你不能写,你希望它是一个文本文件。

下表列出了您可以通过的其他模式:

| 性格;角色;字母 | 意义 | | r | 打开文件进行读取(默认) | | w | 打开文件进行写入,首先截断文件 | | x | 创建一个新文件并打开它进行写入 | | | 打开以供写入,如果文件已经存在,则追加到文件末尾 | | t | 文本模式(默认),可与 rwxa 结合使用 | | b | 二进制模式(与文本模式相反),可以与 rwxa 结合使用 | | + | 打开磁盘文件进行更新(读写) |

可用于 open()的模式参数的文件模式

我不会在这里详细介绍所有的模式,而是在下面的适当部分解释和演示其中的大部分。

Python 写文件

既然您已经了解了文件模式和如何打开文件,我们也可以使用 Python 来写入文件。我们可以分三步走:

  1. 首先,我们需要确定文件模式。如果你看上面的表格,我们需要用 w 和 t。因为“t”是默认值所以我们可以忽略它。
  2. 接下来,我们需要打开文件进行写入
  3. 最后,我们在文件对象上调用 write()方法。

在这种情况下Write 需要一个参数:一个 Python 字符串。如果您有另一种类型的数据,如数字,您需要手动将其转换为字符串。毕竟,文本文件没有数据类型的概念:它们只包含文本。

在下面的例子中,我们使用 str()函数将整数转换为字符串,并将它们写入文件:

https://crumb . sh/embed/3 nwtvkb 2 r xk

用 Python 写一个文件,使用写模式

如果上面的交互示例不起作用,下面是相同的代码:

with open('test.txt', 'w') as f:
    for i in range(1, 5):
        f.write(str(i))

with open('test.txt', 'r') as f:
    print(f.read())

现在,您的文件系统中有一个文件(与您的脚本在同一个目录中),其内容如下:

1234

换行符

你期望每个数字都在一个新的行上吗?

Thank you for reading my tutorials. I write these in my free time, and it requires a lot of time and effort. I use ads to keep writing these free articles, I hope you understand! Support me by disabling your adblocker on my website or, alternatively, buy me some coffee. It's much appreciated and allows me to keep working on this site!

写文件时,需要显式指定换行符。你可以在上面的交互例子中尝试一下。修改代码,使其看起来像这样:

with open('test.txt', 'w') as f:
    for i in range(1, 5):
        f.write(f'Number {i}\n')

with open('test.txt', 'r') as f:
    print(f.read())

请注意,我在这里使用了 f 弦。我个人很喜欢它们,但是你也可以用类似str(i) + '\n'的东西。

Python 追加到文件

现在我们有了一个测试文件我们还可以添加一些额外的数据。默认情况下当我们打开一个文件进行写入时我们会覆盖任何已经存在的内容。因此我们再次首先查看上面的文件模式表我们可以使用哪种模式将数据追加到文件中。我们需要模式“a ”,用于追加。

在下面的例子中,我们:

  1. 使用 Python 的with open()写入一个文件,就像前面的例子一样。
  2. 之后,我们再次打开文件,这次使用 append 标志,并添加一些额外的行。
  3. 回读文件内容并打印到屏幕上,以便我们可以检查结果

给你:

https://crumb . sh/embed/4xb 5 eteh 6 FP

用 Python 向文件追加文本

如果上面的交互示例不起作用,下面是相同的代码:

# First create a file, with a couple of lines
with open('test.txt', 'w') as f:
    for i in range(1, 5):
        f.write(f'Number {i}\n')

# Now add some extra lines using append mode
with open('test.txt', 'a') as f:
    for i in range(5, 8):
        f.write(f'Append number {i}\n')

with open('test.txt') as f:
    print(f.read())

Python 读取文件到列表

对于小文件,将所有行一次读入一个列表会很方便。有两种方法可以做到这一点:

with open('test.txt') as f:
    lines = list(f)

# lines = ['1\n', '2\n', '3\n', '4\n', '5\n', '6\n', '7\n']

相当于:

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

# lines = ['1\n', '2\n', '3\n', '4\n', '5\n', '6\n', '7\n']

逐行读取文件

你并不总是有一次阅读文件的奢侈。例如,当您需要处理 140 GB 大小的日志文件时,您不能将其全部读入内存并侥幸逃脱。你的程序可能会崩溃,或者至少变得非常慢。

在这种情况下,逐行解析文件要高效得多。为了逐行读取文件,我们可以将打开的文件视为一个迭代器。打开文件后,我们可以使用一个 Python for-loop 来遍历这些行:

with open('myfile.txt', 'r') as f:
    for line in f:
        print(line)

常见的 Python 文件操作

Python 有内置模块来执行常见的文件操作,比如删除文件、创建目录、移动文件等等。这些函数中的大部分都可以在os模块中获得,所以你需要先导入它。在这一节中,我们将介绍一些您可能需要执行的操作。

使用 Python 检查文件是否存在

要检查文件是否存在,我们可以使用isfile函数:

import os

if os.path.isfile('myfile.txt'):
    print("It's a file")

如果文件存在,这将返回True,如果不存在,则返回False

使用 Python 检查目录是否存在

类似地,要检查目录是否存在,我们可以使用isdir函数:

import os

if os.path.isdir('mydir'):
    print("It's a directory")

如果目录存在,这将返回True。否则将返回False

创建目录

要创建目录,使用os模块中的mkdir函数:

import os

os.mkdir('mydir')

删除文件

要删除一个文件,我们可以使用下面的命令:

import os

os.remove('myfile.txt')

这将删除文件。如果文件不存在,它将引发一个异常

重命名(或移动)文件

要重命名或移动文件,我们可以使用以下命令:

import os
os.rename('myfile.txt', 'myfile_renamed.txt')

只要文件在同一个文件系统中,重命名操作就会起作用。如果您想将一个文件从一个文件系统移动到另一个文件系统,您需要来自shutil的更高级的move函数,如下所述。

用 shutil 移动文件

为了以类似终端外壳上的mv命令的方式移动文件,我们可以使用shutil模块。与os.rename的一个重要区别是,这个函数也可以在文件系统之间移动文件。重命名只能重命名/移动同一文件系统中的文件:

import shutil

shutil.move('/mnt/filesystem1/myfile.txt', '/mnt/filesystem2/mydir')

# Move to a directory, keeping the name intact
shutil.move('/home/erik/myfile.txt', '/home/erik/backups/')

用 Python 复制文件

shutil模块是一个更高级的模块,它提供了许多可用于复制单个文件或复制和删除整个文件树的功能:

import shutil

# Copy a single file
shutil.copy('/home/erik/myfile.txt', '/home/erik/myfile_copy.txt')

# Copy entire tree of files
shutil.copytree('mydir', 'mydir_copy')

# Remove a tree of files
shutil.rmtree('mydir')

处理 Python 文件异常

如果出现错误,shutilos模块将引发异常。您可以使用tryexcept模块来处理异常。您需要处理的异常几乎总是属于OSError类型。然而,有时您可能还需要处理其他异常,比如SameFileError

我写了一个详细的教程,关于如何处理异常和 try-catch 块,你可能想读一下。

关于 Unix 文件权限

在处理文件时,您不可避免地会遇到文件权限问题。这是关于 Unix 文件权限的简短入门。你迟早会遇到它们,尤其是在云中工作时,因为大多数云服务器都运行 Linux。

文件权限

权限是按文件指定的。当您列出目录时,您将能够看到其权限。例如,在 Linux 下,我们可以用 ls -l 命令这样做:

$ ls -l
total 0
-rwxr-xr-x 1 erik erik 0 Jun 25 10:33 build_script.sh
-rw-r--r-- 1 erik erik 0 Jun 25 10:33 myapp.py

在输出中,您可以看到我出于演示目的创建的两个虚拟文件。第一个是脚本文件,第二个是名为 myapp.py 的 Python 文件。在这一行的开头,您会看到像 r、w 和 x 这样的神秘字母,它们定义了文件权限。文件可以具有以下权限:

| 信 | 许可 | | r | 该文件可以被读取 | | w | 文件是可写的 | | x | 该文件是可执行的 | | | 未设置,未授予权限 |

可能的文件权限

用户和组

然而,仅仅知道权限是不够的。正如您在上面的示例清单中看到的,对于每个文件, r 重复了三次。如果你想知道为什么:计算机系统通常有多个用户和组。

每个文件都有三种访问类型的权限:

  • 用户:文件的所有者。创建文件的人自动成为所有者
  • 组:由 0 个或更多用户组成的组
  • 其他所有人;也称为“世界”

权限也按此顺序列出。因此,对于每种访问类型,我们有三个权限字段,结果是一个九个字符长的字符串。下面的 ASCII 艺术应该可以澄清一些事情:

    User   Group   World
0   123    456     789
-   rwx    r-x     r-x

Positions 1, 2, 3 define permissions for the user
Positions 4, 5, 6 define permissions for the group that the user is in
Positions 7, 8, 9 define permissions for world
Position 0 is the file type (see below)

文件类型

最后,有几种文件类型。最广为人知的是常规文件和目录,但还有更多类型。这是完整的列表:

  • :常规文件
  • d :目录
  • c :字符设备文件
  • b :块设备文件
  • s :本地套接字文件
  • p :命名管道
  • l :符号链接

为了演示,您可以检查文件/dev/random:

ls -l /dev/random
crw-rw-rw- 1 root root 1, 8 jun 22 08:44 /dev/random

这是一个字符设备,当读取时提供一个随机数据流。如您所见,它也是可写的。在这种情况下,写入/dev/random将更新熵池。

还有更多的东西需要学习,您可能也想深入了解我们关于使用 Unix shell 的章节。所以,如果你想或需要,就去探索吧,但是这里的快速介绍应该可以让你开始。

继续学习

使用这些资源扩展您的知识和理解:

  • 如何在 Python 中加载、读取和写入 YAML
  • 在 Python 中使用JSON
  • 关于使用文件的官方 Python 文档
  • 官方 shutil 文档
  • 维基百科关于文件权限的页面
  • 我们关于使用 unix shell 的章节