文件对象概述

文件对象是指对外提供面向文件 API 以使用下层资源的对象(带有 read() 或 write() 这样的方法),也被称作文件类对象

有三种类别的文件对象: 原始二进制文件, 缓冲二进制文件 以及 文本文件。三种类别下还有子类别,因创建方式的不同得到不同类别文件对象。它们的接口定义均在 io 模块中。创建文件对象的规范方式是使用 open() 函数

用户代码直接操作原始流的用法非常罕见。不过,可以通过在禁用缓冲的情况下以二进制模式打开文件来创建原始流:

f = open("test.txt","rb", buffering=0)
f
<_io.FileIO name='test.txt' mode='rb' closefd=True>

缓冲二进制流不执行编码、解码或换行转换。这种类型的流可以用于所有类型的非文本数据(例如图片,视频),并且还可以在需要手动控制文本数据的处理时使用。创建缓冲二进制流的最简单方法是使用 open(),并在模式中指定 ‘b’:

f = open("test.txt","rb")
f
<_io.BufferedReader name='test.txt'>

文本流生成 str 对象。这意味着,无论何时后台存储是由字节组成的,数据的编码和解码都是透明的,并且可以选择转换特定于平台的换行符。创建文本流的最简单方法是使用 open(),可以选择指定编码:

f = open("test.txt",encoding="utf-8")
f
<_io.TextIOWrapper name='test.txt' mode='r' encoding='utf-8'>

所有流对提供给它们的数据类型都很敏感。例如将 str 对象给二进制流的 write() 方法会引发 TypeError。

f = open("test.txt","ab")
f.write('写入内容')
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-19-a9efd264aca2> in <module>
      1 f = open("test.txt","ab")
----> 2 f.write('写入内容')


TypeError: a bytes-like object is required, not 'str'

内存中的流也可以作为文件对象使用:

import io
f = io.StringIO("some initial text data")
print(f)
f.read()
<_io.StringIO object at 0x000001BE348D2040>


'some initial text data'
f = io.BytesIO(b"some initial binary data: \x00\x01")
print(f)
f.read()
<_io.BytesIO object at 0x000001BE348D3310>


b'some initial binary data: \x00\x01'

open() 函数打开文件,创建流后,会使文件在一段不确定的时间内处于打开状态。这在简单脚本中不是问题,但对于较大的应用程序来说可能是个问题。此时用 close() 方法刷新并关闭流(或直接使用 with 语句打开)是明智的做法。

f = open("test.txt",encoding="utf-8")
print(f.read())
f.close()
为什么要掌握自学能力?
未来还很长。
jupyter附件

读取文件内容

打开方式不同,会创建不同类型的文件对象(流),不同类型的文件对象,可能有不同的属性或方法。

下列检查或读取内容的属性或方法,是多数文件对象通用的:

  • readable() 如果可以读取流,则返回 True 。否则为 False ,且 read() 将引发 OSError 错误。
f = open('test.txt')
f.readable()
True
  • read(size=-1) 从对象中读取 size 个字节并将其返回。作为一个便捷选项,如果 size 未指定或为 -1,则返回所有字节直到 EOF。流的位置与读取内容同步,不重设流的位置,内容只能被读取一次。

  • tell() 返回当前流的位置。

f = open('test.txt',encoding='utf-8')
f.read()
'为什么一定要掌握自学能力?\n未来的日子还很长,\n这世界进步得太快,\n没有自学能力,\n没有未来。'
f = open('test.txt',encoding='utf-8')
f.read(12)
'为什么一定要掌握自学能力'
f.tell()
36
f.read() # 再次读取,将读取剩下未读部分
'?\n未来的日子还很长,\n这世界进步得太快,\n没有自学能力,\n没有未来。'
f.read() # 已经没有内容
''
  • seek(offset, whence=0) 将流位置修改到给定的字节 offset。返回新的绝对位置。
f.seek(0, 0)
0
f.read() # 从新位置读取
'为什么一定要掌握自学能力?\n未来的日子还很长,\n这世界进步得太快,\n没有自学能力,\n没有未来。'
  • readline(size=-1) 从流中读取并返回一行。如果指定了 size,将至多读取 size 个字节。
f = open('test.txt',encoding='utf-8')
f.readline()
'为什么一定要掌握自学能力?\n'
f.readline(2) # 再次读取,将读取剩下未读部分
'未来'
  • readlines(hint=-1) 从流中读取并返回包含多行的列表。可以指定 hint 来控制要读取的行数。指定行数可以多于实际。
f = open('test.txt',encoding='utf-8')
f.readlines(1)
['为什么一定要掌握自学能力?\n']
f.readlines(10) # 再次读取,将读取剩下未读部分
['未来的日子还很长,\n', '这世界进步得太快,\n']
  • 使用 for line in file: ... 就足够对文件对象进行迭代了,可以不必调用 file.readlines()。
f = open('test.txt',encoding='utf-8')
for line in f:
    print(line)
为什么一定要掌握自学能力?

未来的日子还很长,

这世界进步得太快,

没有自学能力,

没有未来。
  • closed 如果流已关闭,则返回 True。
f.closed
False
  • close() 刷新并关闭此流。无论读写操作,最后都应该关闭流。如果文件已经关闭,则此方法无效。文件关闭后,对文件的任何操作(例如读取或写入)都会引发 ValueError 。为方便起见,允许多次调用此方法。但是,只有第一个调用才会生效。
f.close()
f.close()
f.closed
True

文件写入内容

打开方式不同,会创建不同类型的文件对象(流),不同类型的文件对象,可能有不同的属性或方法。

打开模式不同,写入内容的方式也会不同,详见 open() 打开文件

下列检查或写入内容的属性或方法,是多数文件对象通用的:

  • writable() 如果流支持写入则返回 True。如为 False,则 write() 将引发 OSError。
f = open('test.txt','a',encoding='utf-8')
f.writable()
True
f = open('test.txt')
f.writable()
f.write('这世界进步得太快,')
---------------------------------------------------------------------------

UnsupportedOperation                      Traceback (most recent call last)

<ipython-input-1-7bf449cf8958> in <module>
      1 f = open('test.txt')
      2 f.writable()
----> 3 f.write('这世界进步得太快,')


UnsupportedOperation: not writable
  • write() 将字符串或字节串写入到流并返回写入的字符或字节数。对于阻塞流(需要刷新才能将内容写入文件),写入内容在缓冲区(打开文件看不到写入的内容)。
f = open('test.txt','a+',encoding='utf-8')
f.write('\n这世界进步得太快,')
10
  • flush() 刷新流的写入缓冲区(打开文件将看到写入的内容)。这对只读和非阻塞流不起作用。
f.flush()
  • writelines(lines) 将行列表写入到流。不会添加行分隔符,因此通常所提供的每一行都带有末尾行分隔符。对于阻塞流,写入内容在缓冲区。
f = open('test.txt','a+',encoding='utf-8')
f.writelines(['\n没有自学能力,\n', '没有未来。'])
f.tell() # 流的位置在末尾
137
f.read() # 从末尾读取内容为空
''
f.seek(0, 0) # 重设流的位置为开头
0
f.read()
'为什么一定要掌握自学能力?\n未来的日子还很长,\n这世界进步得太快,\n没有自学能力,\n没有未来。'
  • closed 如果流已关闭,则返回 True。
f.closed
False
  • close() 刷新并关闭此流。无论读写操作,最后都应该关闭流。如果文件已经关闭,则此方法无效。文件关闭后,对文件的任何操作(例如读取或写入)都会引发 ValueError 。为方便起见,允许多次调用此方法。但是,只有第一个调用才会生效。
f.close()
f.close()
f.closed
True