1 文件操作
无论在那种语言中都会对文件进行操作处理, 而文件相关的处理无非就是打开文件, 读取或者写入内容, 最后再是关闭文件. ython 中文件常用的 IO 操作有以下几个:
Function | Operation |
open | 打开 |
read | 读取 |
write | 写入 |
close | 关闭 |
readline | 行读取 |
readlines | 多行读取 |
seek | 文件指针操作 |
tell | 指针位置 |
2 打开操作
文件的打开操作是对文件进行操作的第一步, Python 中提供 open 函数, open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None),open 函数是打开一个文件, 返回以文件对象 (l 流对象) 和文件描述符. 打开文件失败, 则返回异常.
2.1 open 函数基本使用
创建一个文件 test, 然后打开它, 用完关闭.
- f = open("test") # file 对象
- # Windows <_io.TextIOWrapper name='test' mode='r' encoding='cp936'>
- # Linux <_io.TextIOWrapper name='test' mode='r' encoding='UTF-8'>
- print(f.read()) # 读取文件
- f.close() # 关闭文件
- View Code
文件操作找那个, 最常用的操作就是读和写. 文件访问的模式有两种: 文本模式和二进制模式. 不同模式下, 操作函数不尽相同, 表现的结果也不一样.
2.2 open 函数的参数
2.2.1 file
open 函数中的 file 文件是指定要打开或者要创建的文件名, 如果不指定路径, 默认是当前路径.
2.2.3 mode 模式
open 函数中提供 mode 参数, 可以控制是以什么方式打开文件的, 不同的模式适用不同场景下对文件的操作. 以下是打开文件的模式以及其对应的作用:
Description | Meaning |
r | 缺省的,表示只读打开 |
w | 只写打开 |
x | 创建并写入一个新文件 |
a | 写入打开,如果文件存在,则追加 |
b | 二进制模式 |
t | 缺省的,文本模式 |
+ | 读写打开一个文件。给原来只读、只写方式打开提供缺失的读或者写能力 |
在 2.1 的例子中, 打开 test 文件时没有指定 mode 参数, 那么就是默认以文本打开模式并且是以只读模式打开 test 文件.
r 模式
open 默认是只读模式 r 打开已经存在的文件, 如果文件不存在, 抛出 FileNotFoundErro 异常. 只读打开文件, 如果使用 write 方法, 会抛出异常.
w 模式
如果 mode 后是 w 描述符, 表示只写方式打开文件, 如果读取则抛出异常. 如果文件不存在, 则直接创建文件, 如果文件存在, 则清空文件内容.
x 模式
x 模式下如果文件不存在, 创建文件, 并以只写方式打开文件; 文件存在时, 抛出 FileExistsError 异常.
a 模式
a 模式下, 文件存在, 只写模式打开, 追加内容; 文件不存在, 则创建后, 只写模式打开文件, 追加内容.
文本模式 t
字符流, 将文件的字节按照某种字符编码理解, 按照字符操作. open 的默认 mode 是 rt.
二进制模式 b
字节流, 将文本按照字节理解, 与字符编码无关. 二进制模式操作是, 字节操作使用 bytes 类型.
+ 模式
为 r,w,a,x 提供确实的读写功能. 但是, 获取文件对象依旧按照 r,w,a,x.+ 不能单独使用, 可以认为它是为前面的模式字符做增强功能的.
2.2.4 buffering: 缓冲区
Python 在处理文件时, 是在内存中对文件进行处理. 当给文件中写入内容是, 不是立即将内容写入磁盘中, 而是先写入内存中, 存入缓冲区中待缓冲区满了或者在关闭文件之前, 将内存中的内容写入磁盘中.
缓冲区是一个内存空间, 一般来说是一个 FIFO 队列, 到缓冲区满了或者达到阈值时数据才会 flush 到磁盘. flush 函数是将缓冲区数据写入磁盘, close()关闭前会调用 flush 函数. io.DEFAULT_BUFFER_SIZE 缺省缓冲区大小, 单位是字节, 默认是 4096 或者 8192.
open 函数中的 buffering 参数, 用 - 1 表示使用缺省大小的 buffer. 如果是二进制模式, 使用 io.DEFAULT_BUFFER_SIZE 值; 如果是文本模式, 如果是是终端设备, 是行缓方式, 如果不是则使用二进制模式的策略.
0 只在二进制模式使用, 表示关 buffer
1 只在文本模式使用, 表示使用行缓冲. 意思就是见到换行符就 flush
大于 1 用于指定 buffer 的大小
1, 二进制下的例子
- import io
- f = open('test4', 'w+b')
- print(io.DEFAULT_BUFFER_SIZE)
- f.write('baidu.com'.encode())
- # cat test4
- f.seek(0)
- # cat test4
- f.write('www.baidu.com'.encode())
- f.flush()
- f.close()
- f = open('test4', 'w+b', 4)
- f.write(b'dab')
- # cat test4
- f.write(b'ric')
- # cat test4
- f.close
- View Code
2, 文本模式下
- # buffering=1, 使用行缓冲
- f = open('test4', 'w+', 1)
- f.write('dab') # cat test4
- f.write('dabric'*4) # cat test4
- f.write('\n') # cat test4
- f.write('Hello\nPython') # cat test4
- f.close
- # buffering>1, 使用指定大小的缓冲区
- f = open('test4', 'w+', 15)
- f.write('dab') # cat test4
- f.write('ric') # cat test4
- f.write('Hello\n') # cat test4
- f.write('\nPython') # cat test4
- f.write('a' * (io.DEFAULT_BUFFER_SIZE - 20)) # 设置为大于 1 没什么用
- f.write('\nwww.baidu.com/python')
- f.close
- View Code
buffering=0, 这时一种特殊的二进制模式, 不需要内存的 buffer, 可以看做是一个 FIFO 的文件.
- f = open('test4', 'wb+', 0)
- f.write(b'd') # cat test4
- f.write(b'a') # cat test4
- f.write(b'b') # cat test4
- f.write(b'dabric'*4) # cat test4
- f.write(b'\n') # cat test4
- f.write(b'Hello\nPython') # cat test4
- f.close
- View Code
buffering 为不同值下多代表的含义总结如下表:
buffering | Introduction |
buffering=-1 | t 和 b 都是 io.DEFAULT_BUFFER_SIZE |
buffering=0 | b 关闭缓冲区 t 不支持 |
buffering=1 | b 就 1 个字节 t 行缓冲,遇到换行读才 flush |
buffering>1 | b 模式表示行缓冲大小。缓冲区的值可以超过 io.DEFAULT_BUFFER_SIZE, 直到设定的值超出后才把缓冲区 flush t 模式,是 io.DEFAULT_BUFFER_SIZE,flush 完后把当前字符串也写入磁盘 |
似乎看起来很玛法, 一般来说, 只需记得以下几点:
文本模式, 一般都使用默认缓冲区大小
二进制模式, 是一个个字节的操作, 可以指定 buffer 的大小
一般来说, 默认缓冲区大小是个比较好的选择, 除非明确知道, 否则不调整它
一般编程中, 明确知道需要写磁盘了, 都会手动调用一次 flush, 而不是等到自定 flush 或者 close 的时候
2.2.5 encoding: 编码, 仅文本模式使用
文件在磁盘中的存储是以字节形式存储的, 如果要讲文件显示在屏幕上的话, 就要对其进行解码, 反过来写入时就要对其进行编码. Python 中的 open 函数会在读取文件时做必要的解码, 以文本模式写入文件时还会做必要的编码, 所以在对文件调用读取或者是写入操作都是字符串对象.
encoding 参数指定编码的格式, None 标识使用缺省编码, 依赖操作系统. Windows 下缺省 GBK,Linux 下缺省 UTF-8. 在对文件的读取和写入操作时要保证编码格式的一致, 如果使用默认的编码格式的话, 在不同的操作系统中可能会产生乱码的现象, 如下:
- >>> open('cafe.txt', 'w', encoding='utf_8').write('café')
- 4
- >>> open('cafe.txt').read()
- 'café'
- View Code
写入时文件指定 UTF-8 编码, 但是读取文件时没有那么做. 有可能在对文件进行读取时是在 Windows 环境下, 那么 Windows 环境下使用的默认编码集为 GBK, 于是就会产生乱码现在. 解决办法是在读取操作之前, 打开文件制定编码格式为 UTF-8 即可.
2.2.6 其他参数
errors
errors 参数标识什么样的编码错误将被捕获. 一般情况下, None 和 strict 表示有编码错误将抛出 ValueError 异常; ingore 标识忽略编码错误.
newline
newline 参数表示在文本模式中的换行的转换. 可以为 None,''空串,"\r","\n","\r\n".
读时, None 表示 "\r","\n","\r\n" 都被转换为'\n';''表示不会自动转换通用换行符; 其它合法字符表示换行符就是制定字符, 就会按照制定字符分行.
写时, None 表示'\n'都会被替换为系统缺省分隔符 os,linesep;'\n'或''表示'\n'不替换; 其它合法字符表示'\n'会被替换为指定的字符.
- f = open('o:/test', 'w')
- f.write('python\rwww.python.org\nwww.baidu.com\r\npython3')
- f.close()
- newlines = [None, '','\n','\r\n']
- for nl in newlines:
- f = open('o:/test', 'r+', newline=nl) # q 缺省替换所有换行符
- print(f.readlines())
- f.close
- View Code
- closefd
关闭文件描述符, True 表示关闭它. False 会在文件关闭后保持这个描述符. fileobj.fileno()查看.
3 读取操作
3.1 read 函数
read 函数读取文件时, 将整个文件中的内容读取到内存中, 对于小文件的读取可以使用 read, 其不适用大文件的读取. read 函数中的 size 参数表示读取的多少个字符或字节; 负数或 None 表述读取到 EOF.
- f = open('o:/test4', 'r+', 0)
- f.write("dabric")
- f.write('\n')
- f.write('你好')
- f.seek(0)
- f.read(7)
- f.close
- # 二进制
- f = open('test4', 'rb+')
- f.read(7)
- f.read(1)
- f.close()
- View Code
3.2 行读取
readline 函数表示一行行读取文件内容. size 设置一个能读取行内几个字符或字节.
readlines 函数表述读取所有行的列表. 指定 hint 则返回指定的行数.
- # 按行迭代
- f = open('test') # 返回可迭代对象
- for line in f:
- print(line)
- f.close()
- View Code
4 写入操作
写入操作在前面的代码中多多少少都使用过, 下面具体看下写入操作的函数.
write(s), 函数把字符串 s 写入到文件中并返回字符的个数;
writelines(lines), 将字符串列表写入文件.
- f = open('test', 'w+')
- lines = ['abc', '123\n', 'dabric'] # 提供换行符
- f.writelines(lines)
- f.seek(0)
- print(f.read())
- f.close()
- View Code
5 文件指针
文件是通过文件指针来记录文件当前指向的字节位置, 我们可以通过控制文件指针, 来指向指定的字节位置. 在模式为 r 的情况下, 文件指针指向起始 0 位置, 表示文件开头; 在模式为 a 的情况下, 文件指针指向 EOF, 表示文件末尾, 所以 a 模式被称为追加模式. Python 中提供 tell 函数来显示文件指针当前的位置.
5.1 文件指针操作
Python 提供 seek(offset[, whence])函数来系统文件指针位置. 其中 offset 表示变异多少字节, whence 表示从哪里开始.
在文本模式下, whence 的取值:
whence 0 缺省值, 表示从文件头开始, offset 只能为正整数
whence 1 表示从当前位置, offset 只能接受 0
whence 2 表示从 EOF 开始, offset 只能接受 0
- # 文本模式
- f = open('test4', 'r+')
- f.tell() # 起始
- f.read()
- f.tell() # EOF
- f.seek(0) # 起始
- f.read()
- f.seek(2, 0)
- f.read()
- f.seek(2, 0)
- f.seek(2, 1) # offset 必须为 0
- f.seek(2, 2) # offset 必须为 0
- f.close()
- View Code
文本模式支持从开头向后偏移的方式. whence 为 1 表示从当前位置开始偏移, 但是只支持偏移 0, 相当于原地不动, 所以没有什么用; whence 为 2 表示从 EOF 开始, 只支持偏移 0, 相当于移动文件指针到 EOF.seek 函数时按照字节偏移的.
在二进制模式下, whence 的取值:
whence 0 缺省值, 表示从文件头开始, offset 只能为正整数
whence 1 表示从当前位置, offset 可正可负
whence 2 表示从 EOF 开始, offset 可正可负
- # 二进制模式
- f = open('test4', 'rb+')
- f.tell() # 起始
- f.read()
- f.tell() # EOF
- f.write(b'abc')
- f.seek(0) # 起始
- f.seek(2, 1) # 从当前指针开始, 向后偏移 2 个字节
- f.read()
- f.seek(-2, 1) # 从当前指针开始, 向前偏移 2 个字节
- f.seek(2, 2) # 从 EOF 开始, 向后便宜 2 个字节
- f.seek(0)
- f.seek(-2, 2) # 从 EOF 开始, 向前偏移 2 个字节
- f.read()
- f.seek(-20, 2) # OSError
- f.close()
- View Code
二进制模式下支持任意起点的偏移, 从头, 从尾, 从中间位置开始的偏移. 向后 seek 可以超界, 但是向前 seek 的时候, 不能超界, 否则抛出异常.
6 上下文管理
在每次打开使用文件结束后, 都要使用 close 函数关闭文件对象, 有时候在编程时难免会忘记使用 close 函数对打开的文件关闭, 这样会导致该文件在其他地方不能使用的可能. Python 提供一种上下文管理机制, 使用它后在文件使用完后会自动关闭文件对象.
使用 with...as 关键字, 在 with 语句执行完的时候, 会自动关闭文件对象. 注意, 上下文管理的语句块并不会开启新的作用域.
- with open('test') as f:
- f.write("abc") # 文件只读, 写入失败
- # 测试 f 是否关闭
- f.close # f 的作用域
- View Code
另一种写法;
- f1 = open('test')
- with f1:
- f1.write('abc') # 文件只读, 写入失败
- # 测试 f 是否关闭
- f1.close # f1 的作用域
- View Code
对于类似于文件对象的 IO 对象, 一般来说都性需要在不使用的时候关闭, 注销, 以释放资源. IO 被打开的时候, 会获得一个文件描述符. 计算资源是有限的, 所以操作系统都会做限制. 就是为了保护计算机的资源不要被完全耗尽, 计算资源是共享的, 不是独占的. 一般情况下, 除非特别明确的直到资源情况, 否则不要提高资源的限制值来解决问题.
来源: https://www.cnblogs.com/dabric/p/11746651.html