Python学习笔记(IO编程)
1、文件读写
读文件
使用内置open(name[, mode[, buffering]])函数,name是 包含了文件名的路径字符串,mode是打开方式。
例子,以只读方式打开文件:
最后需要调用close()方法关闭文件,否则会占用系统的资源。
不必写close()方法,能自动关闭文件。
调用read()会一次性读取文件的全部内容,如果文件太大,内存就爆了,所以,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。
二进制文件
要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可:
字符编码
要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件
open()函数还接收一个errors参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略:
写文件
调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件:
如果要写入特定编码的文本,也需要和open()一样,传入encoding参数。
2、StringIO和BytesIO
StringIO
在内存中读写str,需要先创建一个StringIO,然后,像文件一样写入,getvalue()方法用于获得写入后的str。
要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:
文件指针
当使用StringIO()去初始化的时候,其指针是指向0的位置;而如果是用write的方法的时候,其指针则是会移动到后面的,使用readline指针会移到第一行的后面。
文件指针涉及两个方法:
tell()方法返回当前指针位置。
seek()用于移动文件读写指针到指定位置,有两个参数,第一个offset: 偏移量,需要向前或向后的字节数,正为向后,负为向前;第二个whence: 可选值,默认为0,表示文件开头,1表示相对于当前的位置,2表示文件末尾。
BytesIO
如果要操作二进制数据,就需要使用BytesIO。
写入的是经过UTF-8编码的bytes。
3、操作文件和目录
Python内置的os模块可以直接调用操作系统提供的接口函数。
如果是posix,说明系统是Linux、Unix或Mac OS X,如果是nt,就是Windows系统。
环境变量
在操作系统中定义的环境变量,全部保存在os.environ这个变量中,可以直接查看。要获取某个环境变量的值,可以调用os.environ.get('key')。
操作文件和目录
操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中。
os.path 模块主要用于获取文件的属性。常用的方法如下:
例子:
拆分路径,获得最后级别的目录或文件名
得到文件扩展名
列出当前目录下的所有目录
列出所有的.py文件
OS模块没有复制文件的函数,shutil模块提供了copyfile()的函数。
4、序列化
把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
Python提供了pickle模块来实现序列化。
pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object:
当我们要把对象从磁盘读到内存时,可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象,也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。
JSON
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:
使用Python内置的json模块可以完成Python对象到JSON格式的转换。
dumps()方法返回一个str,内容就是标准的JSON。类似的,dump()方法可以直接把JSON写入一个file-like Object。
要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化。
JSON进阶
将类的实例序列化为JSON时,dumps()方法默认不支持,需要增加default可选参数,我们可以自己为类专门写一个转换函数,再把函数传给default参数,就能实现类到JSON的转换。
Student实例首先被student2dict()函数转换成dict,然后再被顺利序列化为JSON。
如果要把任意class的实例变为dict:
如果我们要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例。
json.dumps()提供了一个ensure_ascii参数,如果ensure_ascii为True(默认值),则输出保证将所有输入的非ASCII字符转义。如果确保ensure_ascii为False,这些字符将原样输出。
读文件
使用内置open(name[, mode[, buffering]])函数,name是 包含了文件名的路径字符串,mode是打开方式。
|
---|
>>> f = open('/Users/michael/test.txt', 'r')
调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示:
>>> f.read()
'Hello, world!'
>>> f.close()
Python引入了with语句来自动帮我们调用close()方法,
with open('/path/to/file', 'r') as f:
print(f.read())
调用read()会一次性读取文件的全部内容,如果文件太大,内存就爆了,所以,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。
二进制文件
要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可:
>>> f = open('/Users/michael/test.jpg', 'rb')
>>> f.read()
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节
字符编码
要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
>>> f.read()
'测试'
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
写文件
调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件:
with open('/Users/michael/test.txt', 'w') as f:
f.write('Hello, world!')
2、StringIO和BytesIO
StringIO
在内存中读写str,需要先创建一个StringIO,然后,像文件一样写入,getvalue()方法用于获得写入后的str。
>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5
>>> f.write(' ')
1
>>> f.write('world!')
6
>>> print(f.getvalue())
hello world!
>>> from io import StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
... s = f.readline()
... if s == '':
... break
... print(s.strip())
...
Hello!
Hi!
Goodbye!
当使用StringIO()去初始化的时候,其指针是指向0的位置;而如果是用write的方法的时候,其指针则是会移动到后面的,使用readline指针会移到第一行的后面。
文件指针涉及两个方法:
tell()方法返回当前指针位置。
seek()用于移动文件读写指针到指定位置,有两个参数,第一个offset: 偏移量,需要向前或向后的字节数,正为向后,负为向前;第二个whence: 可选值,默认为0,表示文件开头,1表示相对于当前的位置,2表示文件末尾。
BytesIO
如果要操作二进制数据,就需要使用BytesIO。
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'
3、操作文件和目录
Python内置的os模块可以直接调用操作系统提供的接口函数。
>>> import os
>>> os.name # 操作系统类型
'posix'
环境变量
在操作系统中定义的环境变量,全部保存在os.environ这个变量中,可以直接查看。要获取某个环境变量的值,可以调用os.environ.get('key')。
>>> os.environ.get('PATH')
'/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin'
>>> os.environ.get('x', 'default')
'default'
操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中。
# 查看目录的绝对路径:
>>> os.path.abspath('.')
'/Users/michael'
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 然后创建一个目录:
>>> os.mkdir('/Users/michael/testdir')
# 删掉一个目录:
>>> os.rmdir('/Users/michael/testdir')
# 对文件重命名:
>>> os.rename('test.txt', 'test.py')
# 删掉文件:
>>> os.remove('test.py')
方法 | 说明 |
---|---|
os.path.abspath(path) | 返回绝对路径 |
os.path.basename(path) | 返回文件名 |
os.path.commonprefix(list) | 返回list(多个路径)中,所有path共有的最长的路径 |
os.path.dirname(path) | 返回文件路径 |
os.path.exists(path) | 路径存在则返回True,路径损坏返回False |
os.path.lexists | 路径存在则返回True,路径损坏也返回True |
os.path.expanduser(path) | 把path中包含的"~"和"~user"转换成用户目录 |
os.path.expandvars(path) | 根据环境变量的值替换path中包含的"$name"和"${name}" |
os.path.getatime(path) | 返回最近访问时间(浮点型秒数) |
os.path.getmtime(path) | 返回最近文件修改时间 |
os.path.getctime(path) | 返回文件 path 创建时间 |
os.path.getsize(path) | 返回文件大小,如果文件不存在就返回错误 |
os.path.isabs(path) | 判断是否为绝对路径 |
os.path.isfile(path) | 判断路径是否为文件 |
os.path.isdir(path) | 判断路径是否为目录 |
os.path.islink(path) | 判断路径是否为链接 |
os.path.ismount(path) | 判断路径是否为挂载点 |
os.path.join(path1[, path2[, ...]]) | 把目录和文件名合成一个路径 |
os.path.normcase(path) | 转换path的大小写和斜杠 |
os.path.normpath(path) | 规范path字符串形式 |
os.path.realpath(path) | 返回path的真实路径 |
os.path.relpath(path[, start]) | 从start开始计算相对路径 |
os.path.samefile(path1, path2) | 判断目录或文件是否相同 |
os.path.sameopenfile(fp1, fp2) | 判断fp1和fp2是否指向同一文件 |
os.path.samestat(stat1, stat2) | 判断stat tuple stat1和stat2是否指向同一个文件 |
os.path.split(path) | 把路径分割成 dirname 和 basename,返回一个元组 |
os.path.splitdrive(path) | 一般用在 windows 下,返回驱动器名和路径组成的元组 |
os.path.splitext(path) | 分割路径,返回路径名和文件扩展名的元组 |
os.path.splitunc(path) | 把路径分割为加载点与文件 |
os.path.walk(path, visit, arg) | 遍历path,进入每个目录都调用visit函数,visit函数必须有3个参数(arg, dirname, names),dirname表示当前目录的目录名,names代表当前目录下的所有文件名,args则为walk的第三个参数 |
os.path.supports_unicode_filenames | 设置是否支持unicode路径名 |
拆分路径,获得最后级别的目录或文件名
>>> os.path.split('/Users/michael/testdir/file.txt')
('/Users/michael/testdir', 'file.txt')
>>> os.path.splitext('/path/to/file.txt')
('/path/to/file', '.txt')
>>> [x for x in os.listdir('.') if os.path.isdir(x)]
['.lein', '.local', '.m2', ...]
>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']
4、序列化
把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
Python提供了pickle模块来实现序列化。
>>> import pickle
>>> d = dict(name='Bob', age=20, score=88)
>>> pickle.dumps(d)
b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x14X\x05\.'
>>> f = open('dump.txt', 'wb')
>>> pickle.dump(d, f)
>>> f.close()
>>> f = open('dump.txt', 'rb')
>>> d = pickle.load(f)
>>> f.close()
>>> d
{'age': 20, 'score': 88, 'name': 'Bob'}
JSON
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:
JSON类型 | Python类型 |
---|---|
{} | dict |
[] | list |
"string" | str |
1234.56 | int或float |
true/false | True/False |
null | None |
>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)
'{"age": 20, "score": 88, "name": "Bob"}'
要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化。
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> json.loads(json_str)
{'age': 20, 'score': 88, 'name': 'Bob'}
JSON进阶
将类的实例序列化为JSON时,dumps()方法默认不支持,需要增加default可选参数,我们可以自己为类专门写一个转换函数,再把函数传给default参数,就能实现类到JSON的转换。
import json
class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
>>>s = Student('Bob', 20, 88)
>>> print(json.dumps(s, default=student2dict))
{"age": 20, "name": "Bob", "score": 88}
如果要把任意class的实例变为dict:
print(json.dumps(s, default=lambda obj: obj.__dict__))
有的python对象存在__dict__属性,主要是自定义的class和对应生成的object,用__dict__记录了的属性字典。
>>> class testdict():
... cls = 0
... def __init__(self, value):
... self.value = value
...
>>> testdict.__dict__
mappingproxy({'__module__': '__main__', 'cls': 0, '__init__': , '__dict__': ,
'__weakref__': , '__doc__': None})
>>> t = testdict(123)
>>> t.__dict__
{'value': 123}
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> print(json.loads(json_str, object_hook=dict2student))
<__main__.Student object at 0x10cd3c190>
>>> import json
>>> obj = dict(name='小明', age=20)
>>> s = json.dumps(obj, ensure_ascii=True)
>>> print(s)
{"name": "\u5c0f\u660e", "age": 20}
>>> s = json.dumps(obj, ensure_ascii=False)
>>> print(s)
{"name": "小明", "age": 20}
>>>
评论
发表评论