一、文件读写

1.1 读文件

(1)打开文件

使用Python内置的open()函数,传入文件名和标示符,打开一个文件对象:

1
2
>>> import os
>>> f = open('/Users/michael/test.txt', 'r')

标示符'r'表示读,这样,我们就成功地打开了一个文件。

Python引入了with语句来避免程序出错:

1
2
with open('/path/to/file', 'r') as f:
print(f.read())

上面的代码相当于:

1
2
3
4
5
6
try:
f = open('/path/to/file', 'r')
print(f.read())
finally:
if f:
f.close()

(2)读文件内容

方法 作用
read() 一次读取文件的全部内容
read(size) 每次最多读取size个字节的内容
readline() 每次读取一行内容
readlines() 一次读取所有内容并按行返回

(3)关闭文件

调用close()方法关闭文件。文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源。

1
>>> f.close()

(4)读取其它编码格式文件

要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可:

1
2
3
>>> f = open('/Users/michael/test.jpg', 'rb')
>>> f.read()
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节

要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件:

1
2
3
>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
>>> f.read()
'测试'

1.2 写文件

调用open(),传入标识符'w'或者'wb'表示写文本文件或写二进制文件:

1
2
3
>>> f = open('/Users/michael/test.txt', 'w')
>>> f.write('Hello, world!')
>>> f.close()

可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件。当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。

所以通常,还是使用with语句写文件:

1
2
with open('/Users/michael/test.txt', 'w') as f:
f.write('Hello, world!')

二、文件和目录操作

Python内置的os模块可以直接调用操作系统提供的接口函数。

2.1 目录操作

(1)查看目录

1
2
3
# 查看当前目录的绝对路径:
>>> os.path.abspath('.')
'/Users/michael'

(2)创建目录

1
2
3
4
5
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 然后创建一个目录:
>>> os.mkdir('/Users/michael/testdir')

(3)删除目录

1
2
# 删掉一个目录:
>>> os.rmdir('/Users/michael/testdir')

(4)合并与拆分路径

把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数。

1
2
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'

要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数。

1
2
>>> os.path.split('/Users/michael/testdir/file.txt')
('/Users/michael/testdir', 'file.txt')

(5)获取扩展名

os.path.splitext()可以直接让你得到文件扩展名:

1
2
>>> os.path.splitext('/path/to/file.txt')
('/path/to/file', '.txt')

2.2 文件操作

(1)文件重命名

1
2
# 对文件重命名:
>>> os.rename('test.txt', 'test.py')

(2)文件删除

1
2
# 删掉文件:
>>> os.remove('test.py')

(3)复制与移动文件

os模块中并未提供复制与移动文件的函数,但shutil模块提供了copyfile()的函数,可以看作是os模块的补充。

shutil.copy(src_file, target_path)
shutil.move(src_file, target_path)

1
2
3
import shutil
shutil.copy('/Users/michael/testdir1/file.txt', '/Users/michael/testdir2')
shutil.move('/Users/michael/testdir1/file.txt', '/Users/michael/testdir2')

三、JSON

要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,最常用的就是序列化为JSON。

因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

3.1 Python dict -> JSON

Python内置的json模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON:

1
2
3
4
>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)
'{"age": 20, "score": 88, "name": "Bob"}'

dumps()方法返回一个str,内容就是标准的JSON。
dump()方法可以直接把JSON写入一个file-like Object

3.2 JSON -> Python dict

要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化:

1
2
3
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> json.loads(json_str)
{'age': 20, 'score': 88, 'name': 'Bob'}

3.3 Python Class -> JSON

由于通常情况下,我们会用class表示对象,如果直接将对象序列化肯定会报错,原因是Student对象不是一个可序列化为JSON的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import json

class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score

s = Student('Bob', 20, 88)
print(json.dumps(s))

# 输出
Traceback (most recent call last):
...
TypeError: <__main__.Student object at 0x10603cc50> is not JSON serializable

但,dumps()方法还提供了一大堆的可选参数,其中可选参数default就支持通过提供转换函数,为dumps()传入对象实例以及转换函数,就可以实现序列化。

精简后的写法如下:

1
print(json.dumps(s, default=lambda obj: obj.__dict__))

因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。

3.4 JSON -> Python Class

如果我们要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例:

1
2
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
1
2
3
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> print(json.loads(json_str, object_hook=dict2student))
<__main__.Student object at 0x10cd3c190>