# Python 文件 I/O

> 原文： [https://www.programiz.com/python-programming/file-operation](https://www.programiz.com/python-programming/file-operation)

#### 在本教程中，您将学习 Python 文件操作。 更具体地说，打开文件，读取文件，写入文件，关闭文件以及您应该注意的各种文件方法。

## 文件

文件被命名为磁盘上用于存储相关信息的位置。 它们用于将数据永久存储在非易失性存储器（例如硬盘）中。

由于随机存取存储器（RAM）是易失性的（当计算机关闭时会丢失其数据），因此我们通过永久存储文件来使用文件以备将来使用。

当我们要读取或写入文件时，我们需要先打开它。 完成后，需要关闭它，以便释放与文件绑定的资源。

因此，在 Python 中，文件操作按以下顺序进行：

1.  打开文件
2.  读取或写入（执行操作）
3.  关闭文件

* * *

## 用 Python 打开文件

Python 具有内置的`open()`函数来打开文件。 此函数返回文件对象，也称为句柄，因为它用于相应地读取或修改文件。

```py
>>> f = open("test.txt")    # open file in current directory
>>> f = open("C:/Python38/README.txt")  # specifying full path
```

我们可以在打开文件时指定模式。 在模式下，我们指定是要读取`r`，写入`w`还是将`a`附加到文件中。 我们还可以指定是否要以文本模式或二进制模式打开文件。

默认为在文本模式下阅读。 在这种模式下，当从文件中读取时，我们会得到字符串。

另一方面，二进制模式返回字节，这是处理非文本文件（例如图像或可执行文件）时要使用的模式。

| 模式 | 描述 |
| --- | --- |
| `r` | 打开文件进行读取。 （默认） |
| `w` | 打开一个文件进行写入。 如果不存在则创建一个新文件，或者如果存在则将其截断。 |
| `x` | 打开文件以进行独占创建。 如果文件已经存在，则操作失败。 |
| `a` | 打开文件以在文件末尾追加而不截断。 如果不存在，则创建一个新文件。 |
| `t` | 以文本模式打开。 （默认） |
| `b` | 以二进制模式打开。 |
| `+` | 打开文件进行更新（读取和写入） |

```py
f = open("test.txt")      # equivalent to 'r' or 'rt'
f = open("test.txt",'w')  # write in text mode
f = open("img.bmp",'r+b') # read and write in binary mode
```

与其他语言不同，字符`a`直到使用`ASCII`（或其他等效编码）编码后才隐含数字 97。

此外，默认编码取决于平台。 在 Windows 中，它是`cp1252`，在 Linux 中是`utf-8`。

因此，我们也不能依赖默认编码，否则我们的代码在不同平台上的行为会有所不同。

因此，在以文本模式处理文件时，强烈建议指定编码类型。

```py
f = open("test.txt", mode='r', encoding='utf-8')
```

* * *

## 在 Python 中关闭文件

完成对文件的操作后，我们需要正确关闭文件。

关闭文件将释放与该文件绑定的资源。 这是使用 Python 中可用的`close()`方法完成的。

Python 有一个垃圾收集器来清理未引用的对象，但是我们不能依靠它来关闭文件。

```py
f = open("test.txt", encoding = 'utf-8')
# perform file operations
f.close()
```

这种方法并不完全安全。 如果对文件执行某些操作时发生异常，则代码将退出而不关闭文件。

一种更安全的方法是使用 [try ... finally](/python-programming/exception-handling) 块。

```py
try:
   f = open("test.txt", encoding = 'utf-8')
   # perform file operations
finally:
   f.close()
```

这样，即使出现引发导致程序流停止的异常，我们也可以保证文件已正确关闭。

关闭文件的最佳方法是使用`with`语句。 这样可以确保退出`with`语句内的块时关闭文件。

我们不需要显式调用`close()`方法。 它是在内部完成的。

```py
with open("test.txt", encoding = 'utf-8') as f:
   # perform file operations
```

* * *

## 用 Python 写入文件

为了使用 Python 写入文件，我们需要以写入`w`，附加`a`或互斥创建`x`模式打开它。

我们需要特别注意`w`模式，因为如果它已经存在，它将覆盖到文件中。 因此，所有先前的数据都将被擦除。

写入字符串或字节序列（对于二进制文件）是使用`write()`方法完成的。 此方法返回写入文件的字符数。

```py
with open("test.txt",'w',encoding = 'utf-8') as f:
   f.write("my first file\n")
   f.write("This file\n\n")
   f.write("contains three lines\n")
```

如果该程序不存在，它将在当前目录中创建一个名为`test.txt`的新文件。 如果确实存在，则将其覆盖。

我们必须自己包括换行符，以区分不同的行。

* * *

## 用 Python 读取文件

要使用 Python 读取文件，我们必须以读取`r`模式打开文件。

有多种方法可用于此目的。 我们可以使用`read(size)`方法读取`size`数的数据。 如果未指定`size`参数，它将读取并返回文件末尾。

我们可以通过以下方式读取在上一节中编写的`text.txt`文件：

```py
>>> f = open("test.txt",'r',encoding = 'utf-8')
>>> f.read(4)    # read the first 4 data
'This'

>>> f.read(4)    # read the next 4 data
' is '

>>> f.read()     # read in the rest till end of file
'my first file\nThis file\ncontains three lines\n'

>>> f.read()  # further reading returns empty sting
''
```

我们可以看到`read()`方法返回一个换行符`'\n'`。 到达文件末尾后，我们将得到一个空字符串，供进一步阅读。

我们可以使用`seek()`方法更改当前文件的光标（位置）。 同样，`tell()`方法返回我们的当前位置（以字节数为单位）。

```py
>>> f.tell()    # get the current file position
56

>>> f.seek(0)   # bring file cursor to initial position
0

>>> print(f.read())  # read the entire file
This is my first file
This file
contains three lines
```

我们可以使用[循环](/python-programming/for-loop)逐行读取文件。 这既高效又快速。

```py
>>> for line in f:
...     print(line, end = '')
...
This is my first file
This file
contains three lines
```

在此程序中，文件本身的行包含换行符`\n`。 因此，我们在打印时使用`print()`函数的`end`参数来避免出现两个换行符。

另外，我们可以使用`readline()`方法读取文件的各个行。 此方法读取文件，直到换行符为止，包括换行符。

```py
>>> f.readline()
'This is my first file\n'

>>> f.readline()
'This file\n'

>>> f.readline()
'contains three lines\n'

>>> f.readline()
''
```

最后，`readlines()`方法返回整个文件剩余行的列表。 当到达文件末尾（EOF）时，所有这些读取方法都将返回空值。

```py
>>> f.readlines()
['This is my first file\n', 'This file\n', 'contains three lines\n']
```

* * *

## Python 文件方法

文件对象有多种可用方法。 其中一些已在以上示例中使用。

这是文本模式下方法的完整列表，并带有简要说明：

| 方法 | 描述 |
| --- | --- |
| `close()` | 关闭打开的文件。 如果文件已经关闭，则无效。 |
| `detach()` | 将底层二进制缓冲区与`TextIOBase`分离并返回。 |
| `fileno()` | 返回文件的整数（文件描述符）。 |
| `flush()` | 刷新文件流的写缓冲区。 |
| `isatty()` | 如果文件流是交互式的，则返回`True`。 |
| `read(n)` | 从文件中读取最多`n`个字符。 如果为负或`None`则读取到文件末尾。 |
| `readable()` | 如果可以读取文件流，则返回`True`。 |
| `readline(n=-1)` | 从文件读取并返回一行。 如果指定，则最多读入`n`个字节。 |
| `readlines(n=-1)` | 从文件读取并返回行列表。 如果指定，则最多读入`n`个字节/字符。 |
| `seek(offset,from=SEEK_SET)` | 参考`from`（开始，当前，结束），将文件位置更改为`offset`字节。 |
| `seekable()` | 如果文件流支持随机访问，则返回`True`。 |
| `tell()` | 返回当前文件位置。 |
| `truncate(size=None)` | 将文件流调整为`size`字节。 如果未指定`size`，则将其尺寸调整为当前位置。 |
| `writable()` | 如果可以写入文件流，则返回`True`。 |
| `write(s)` | 将字符串`s`写入文件，并返回写入的字符数。 |
| `writelines(lines)` | 将`lines`的列表写入文件。 |