35.md 8.3 KB
Newer Older
W
wizardforcel 已提交
1
# Python 文件 I/O
W
wizardforcel 已提交
2 3 4 5 6

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

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

W
wizardforcel 已提交
7
## 文件
W
wizardforcel 已提交
8 9 10 11 12 13 14 15 16

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

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

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

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

W
wizardforcel 已提交
17
1.  打开文件
W
wizardforcel 已提交
18
2.  读取或写入(执行操作)
W
wizardforcel 已提交
19
3.  关闭文件
W
wizardforcel 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

* * *

## 用 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`附加到文件中。 我们还可以指定是否要以文本模式或二进制模式打开文件。

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

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

| 模式 | 描述 |
W
wizardforcel 已提交
39
| --- | --- |
W
wizardforcel 已提交
40 41 42
| `r` | 打开文件进行读取。 (默认) |
| `w` | 打开一个文件进行写入。 如果不存在则创建一个新文件,或者如果存在则将其截断。 |
| `x` | 打开文件以进行独占创建。 如果文件已经存在,则操作失败。 |
W
wizardforcel 已提交
43
| `a` | 打开文件以在文件末尾附加而不截断。 如果不存在,则创建一个新文件。 |
W
wizardforcel 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| `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`模式打开文件。

W
wizardforcel 已提交
132
有多种方法可用于此目的。 我们可以使用`read(size)`方法读取`size`数的数据。 如果未指定`size`参数,它将读取并返回文件末尾。
W
wizardforcel 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178

我们可以通过以下方式读取在上一节中编写的`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
```

W
wizardforcel 已提交
179
在此程序中,文件本身的行包含换行符`\n`。 因此,我们在打印时使用`print()`函数的`end`参数来避免出现两个换行符。
W
wizardforcel 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

另外,我们可以使用`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 文件方法

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

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

W
wizardforcel 已提交
212 213
| 方法 | 描述 |
| --- | --- |
W
wizardforcel 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
| `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`的列表写入文件。 |