Python之IO编程——⽂件读写、StringIOBytesIO、操作⽂件
和⽬录、序列化
IO编程
IO在计算机中指Input/Output,也就是输⼊和输出。由于程序和运⾏时数据是在内存中驻留,由CPU这个超快的计算核⼼来执⾏,涉及到数据交换的地⽅,通常是磁盘、⽹络等,就需要IO接⼝。从磁盘读取⽂件到内存,就只有Input操作,反过来,把数据写到磁盘⽂件⾥,就只是⼀个Output操作。
由于CPU和内存的速度远远⾼于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。举个例⼦来说,⽐如要把100M的数据写⼊磁盘,CPU输出100M的数据只需要0.01秒,可是磁盘要接收这100M数据可能需要10秒,怎么办呢?有两种办法:
第⼀种是CPU等着,也就是程序暂停执⾏后续代码,等100M的数据在10秒后写⼊磁盘,再接着往下执⾏,这种模式称为同步IO;
另⼀种⽅法是CPU不等待,只是告诉磁盘,“您⽼慢慢写,不着急,我接着⼲别的事去了”,于是,后续代码可以⽴刻接着执⾏,这种模式称为异步IO。
同步和异步的区别就在于是否等待IO执⾏的结果。异步IO来编写程序性能会远远⾼于同步IO,但是异步IO的缺点是编程模型复杂
⼀、⽂件读写
读写⽂件是最常见的IO操作。Python内置了读写⽂件的函数,⽤法和C是兼容的。读写⽂件就是请求操作系统打开⼀个⽂件对象(通常称为⽂件描述符),然后,通过操作系统提供的接⼝从这个⽂件对象中读取数据(读⽂件),或者把数据写⼊这个⽂件对象(写⽂件)。
1.从⽂件中读取数据
1.1读取整个⽂件
要读取⽂件,需要⼀个包含⼏⾏⽂本的⽂件。下⾯⾸先来创建⼀个⽂件,它包含精确到⼩数点后30位的圆周率值,且在⼩数点后每10位处都换⾏:
#
3.1415926535
8979323846
2643383279
with open('') as file_object:
contents = ad()
print(contents)
函数open() 接受⼀个参数:要打开的⽂件的名称。Python在当前执⾏的⽂件所在的⽬录中查指定的⽂件,函数open() 返回⼀个表⽰⽂件的对象。在这⾥,open('') 返回⼀个表⽰⽂件 的对象;Python将这个对象存储在我们将在后⾯使⽤的变量中。
关键字with 在不再需要访问⽂件后将其关闭。
PS:在这个程序中,注意到我们调⽤了open() ,但没有调⽤close() ;调⽤open() 和close() 来打开和关闭⽂件,如果程序存在bug,导致close() 语句未执⾏,⽂件将不会关闭。未妥善地关闭⽂件可能会导致数据丢失或受损。如果在程序中过早地调⽤close() ,需要使⽤⽂件时它已关闭(⽆法访问),会导致更多的错误。通过使⽤前⾯所⽰的结构,可让Python去确定:你只管打开⽂件,并在需要时使⽤它,Python⾃会在合适的时候⾃动将其关闭。
函数read() 读取这个⽂件的全部内容,并将其作为⼀个长长的字符串存储在变量contents中。这样,通过打印contents 的值,就可将这个⽂本⽂件的全部内容显⽰出来。相⽐于原始⽂件,该输出不同的地⽅是末尾多了⼀个空⾏。read() 到达⽂件末尾时返回⼀个空字符串,⽽将这个空字符串显⽰出来时就是⼀个空⾏。要删除多出来的空⾏,可在print 语句中使⽤rstrip() :
with open('') as file_object:
python怎么读文件夹下的文件夹
contents = ad()
print(contents.rstrip())
调⽤read()会⼀次性读取⽂件的全部内容,如果⽂件有10G,内存就爆了,所以,要保险起见,可以反复调⽤read(size)⽅法,每次最多读取size个字节的内容。另外,调⽤readline()可以每次读取⼀⾏内容,调⽤readlines()⼀次读取所有内容并按⾏返回list。因此,要根据需要决定怎么调⽤。
如果⽂件很⼩,read()⼀次性读取最⽅便;如果不能确定⽂件⼤⼩,反复调⽤read(size)⽐较保险;如果是配置⽂件,调⽤readlines()最⽅便:
for line adlines():
print(line.strip()) # 把末尾的'\n'删掉
file-like Object:像open()函数返回的这种有个read()⽅法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,⽹络流,⾃定义流等等。file-like Object不要求从特定类继承,只要写个read()⽅法就⾏。StringIO就是在内存中创建的file-like Object,常⽤作临时缓冲。
⼆进制⽂件:前⾯讲的默认都是读取⽂本⽂件,并且是UTF-8编码的⽂本⽂件。要读取⼆进制⽂件,⽐如图⽚、视频等等,⽤'rb'模式打开⽂件即可:
>>> f = open('/Users/michael/test.jpg', 'rb')
>>> f.read()
b'\xff\xd8\xff\xe1\x00\x18Exif\' # ⼗六进制表⽰的字节
字符编码:要读取⾮UTF-8编码的⽂本⽂件,需要给open()函数传⼊encoding参数,例如,读取GBK编码的⽂件:
>>> f = open('/Users/', 'r', encoding='gbk')
>>> f.read()
'测试'
遇到有些编码不规范的⽂件,你可能会遇到UnicodeDecodeError,因为在⽂本⽂件中可能夹杂了⼀些⾮法编码的字符。遇到这种情况,open()函数还接收⼀个errors参数,表⽰如果遇到编码错误后如何处理。最简单的⽅式是直接忽略:
>>> f = open('/Users/', 'r', encoding='gbk', errors='ignore')
1.2⽂件路径
程序⽂件存储在⽂件夹python_work中,⽽在⽂件夹python_work中,有⼀个名为text_files的⽂件夹,⽤于存储程序⽂件操作的⽂本⽂件。使⽤相对⽂件路径来打开该⽂件夹中的⽂件。相对⽂件路径让Python到指定的位置去查,⽽该位置是相对于当前运⾏的程序所在⽬录的。在Linux和OS X中,你可以这样编写代码:
with open('text_') as file_object:
在Windows系统中,在⽂件路径中使⽤反斜杠(\ )⽽不是斜杠(/ ):
with open('text_') as file_object:
在相对⽂件路径⾏不通时,可使⽤绝对⽂件路径,绝对路径通常⽐相对路径更长,因此将其存储在⼀个变量中,再将该变量传递给open() 会有所帮助。在Linux和OS X中,绝对路径类似于下⾯这样:
file_path = '/home/ehmatthes/other_files/text_'
with open(file_path) as file_object:
在Windows系统中,它们类似于下⾯这样:
file_path = 'C:\Users\ehmatthes\other_files\text_'
with open(file_path) as file_object:
通过使⽤绝对路径,可读取系统任何地⽅的⽂件。就⽬前⽽⾔,最简单的做法是,要么将数据⽂件存储在程序⽂件所在的⽬录,要么将其存储在程序⽂件所在⽬录下的⼀个⽂件夹(如text_files)中。
1.3逐⾏读取
读取⽂件时,常常需要检查其中的每⼀⾏:你可能要在⽂件中查特定的信息,或者要以某种⽅式修改⽂件中的⽂本。
例如,你可能要遍历⼀个包含天⽓数据的⽂件,并使⽤天⽓描述中包含字样sunny的⾏。在新闻报道中,你可能会查包含标签<headline> 的⾏,并按特定的格式设置它。要以每次⼀⾏的⽅式检查⽂件,可对⽂件对象使⽤for 循环:
❶ filename = ''
❷ with open(filename) as file_object:
❸    for line in file_object:
print(line)
在这个⽂件中,每⾏的末尾都有⼀个看不见的换⾏符,⽽print 语句也会加上⼀个换⾏符,因此每⾏末尾都有两个换⾏符:⼀个来⾃⽂件,另⼀个来⾃
print 语句。
3.1415926535
8979323846
2643383279
要消除这些多余的空⽩⾏,可在print 语句中使⽤rstrip() :
filename = ''
with open(filename) as file_object:
for line in file_object:
print(line.rstrip())
1.4创建⼀个包含⽂件各⾏内容的列表
使⽤关键字with 时,open() 返回的⽂件对象只在with 代码块内可⽤。如果要在with 代码块外访问⽂件的内容,可在with 代码块内将⽂件的各⾏存储在⼀个列表中,并在with 代码块外使⽤该列表:你可以⽴即处理⽂件的各个部分,也可推迟到程序后⾯再处理。
filename = ''
with open(filename) as file_object:
lines = adlines()
for line in lines:
print(line.rstrip())
1.5使⽤⽂件内容
将⽂件读取到内存中后,就可以以任何⽅式使⽤这些数据了。下⾯以简单的⽅式使⽤圆周率的值。⾸先,我们将创建⼀个字符串,它包含⽂件中存储的所有数字,且没有任何空格:
filename = ''
with open(filename) as file_object:
lines = adlines()
pi_string = ''
for line in lines:
pi_string += line.strip()  #变量pi_string存储的字符串中,包含原来位于每⾏左边的空格,为删除这些空格,可使⽤strip()
print(pi_string)
print(len(pi_string))
注意
 读取⽂本⽂件时,Python将其中的所有⽂本都解读为字符串。如果你读取的是数字,并要将其作为数值使⽤,就必须使⽤函数int() 将其转换为整数,或使⽤函数float() 将其转换为浮点数。
1.6包含⼀百万位的⼤型⽂件
对于你可处理的数据量,Python没有任何限制;只要系统的内存⾜够多,你想处理多少数据都可以。包含精确到⼩数点后1 000 000位,打印前52位,判
断是否包含你的⽣⽇。
filename = 'pi_'
with open(filename) as file_object:
lines = adlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string[:52] + "...")
print(len(pi_string))
birthday = input("Enter your birthday, in the form mmddyy: ")
if birthday in pi_string:
print("Your birthday appears in the first million digits of pi!")
else:
print("Your birthday does not appear in the first million digits of pi.")
2.写⼊⽂件
保存数据的最简单的⽅式之⼀是将其写⼊到⽂件中
2.1写⼊空⽂件
要将⽂本写⼊⽂件,你在调⽤open() 时需要提供另⼀个实参,告诉Python你要写⼊打开的⽂件。传⼊标识符'w'或者'wb'表⽰写⽂本⽂件或写⼆进制⽂件:
filename = ''
with open(filename, 'w') as file_object:
file_object.write("I love programming.\n")
file_object.write("I love creating new games.")#像显⽰到终端的输出⼀样,还可以使⽤空格、制表符和空⾏来设置这些输出的格式。
第⼀个实参也是要打开的⽂件的名称;第⼆个实参('w' )告诉Python,我们要以写⼊模式 打开这个⽂件。打开⽂件时,可指定读取模式 ('r' )、写⼊模式 ('w' )、附加模式 ('a' )或让你能够读取和写⼊⽂件的模式('r+' )。如果省略了模式实参,Python将以默认的只读模式打开⽂件。
如果要写⼊的⽂件不存在,函数open() 将⾃动创建它。然⽽,以写⼊('w' )模式打开⽂件时,如果指定的⽂件已经存在,Python将在返回⽂件对象前清空该⽂件。
注意:  Python只能将字符串写⼊⽂本⽂件。要将数值数据存储到⽂本⽂件中,必须先使⽤函数str() 将其转换为字符串格式
2.2附加到⽂件
如果你要给⽂件添加内容,⽽不是覆盖原有的内容,可以附加模式 打开⽂件。你以附加模式打开⽂件时,Python不会在返回⽂件对象前清空⽂件,⽽你写⼊到⽂件的⾏都将添加到⽂件末尾。如果指定的⽂件不存在,Python将为你创建⼀个空⽂件。
filename = ''
with open(filename, 'a') as file_object:
file_object.write("I also love finding meaning in large datasets.\n")
file_object.write("I love creating apps that can run in a browser.\n")
⼆、StringIO和BytesIO
StringIO
很多时候,数据读写不⼀定是⽂件,也可以在内存中读写。StringIO顾名思义就是在内存中读写str。要把str写⼊StringIO,我们需要先创建⼀个StringIO,然后,像⽂件⼀样写⼊即可:
>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5
>>> f.write(' ')
1
>>> f.write('world!')
6
>>> value())
hello world!
getvalue()⽅法⽤于获得写⼊后的str。
要读取StringIO,可以⽤⼀个str初始化StringIO,然后,像读⽂件⼀样读取:
>>> from io import StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
...    s = f.readline()
...    if s == '':
...        break
...    print(s.strip())
...
Hello!
Hi!
Goodbye!
BytesIO
StringIO操作的只能是str,如果要操作⼆进制数据,就需要使⽤BytesIO。BytesIO实现了在内存中读写bytes,我们创建⼀个BytesIO,然后写⼊⼀些bytes: 写⼊的不是str,⽽是经过UTF-8编码的bytes。
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中⽂'.encode('utf-8'))
6
>>> value())
b'\xe4\xb8\xad\xe6\x96\x87'
和StringIO类似,可以⽤⼀个bytes初始化BytesIO,然后,像读⽂件⼀样读取:
>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
⼩结:StringIO和BytesIO是在内存中操作str和bytes的⽅法,使得和读写⽂件具有⼀致的接⼝。
三、操作⽂件和⽬录
操作⽂件和⽬录的函数⼀部分放在os模块中,⼀部分放在os.path模块中,这⼀点要注意⼀下。查看、创建和删除⽬录可以这么调⽤:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。