IO编程

f = open('/Users/fish/Desktop/readme.txt', 'r')
content=f.read() 
print(content)
f.close()

文件使用完必须关闭,文件对象会占用系统资源,操作系统同时能打开文件数量也是有限的
为了保证每次不论是否文件读碟出现IOError出错 都能正确关闭文件,通常这么写:

try:
    f = open('/path/to/file', 'r')
    print(f.read())
finally:
    if f:
        f.close()

# 使用 python的with语句来自动帮我们调用close()方法
#与try...finall..效果相同代码更简洁

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

read()方法会一次性读取全部内容,如果文件过大会挑战内存
read(size)每次最多读取size字节的内容
readline()每次读取一行内容
readlines()一次性读取所有行,返回一个list

类似文件这种 open()函数返回可以read()的对象,均称为 file-like Object,除此之外还有内存的字节流、网络流、自定义流

二进制文件

默认读取的为UTF-8编码的文本文件,如果为二进制文件,需要用rb模式打开

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

其它编码格式

对于非UTF-8编码的文本文件,需要open()函数需要传入encoding参数

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')

当编码不规范,文本中夹杂着非法编码字符时,会发生转码错误(UnicodeDecodeError),此时可以通过加入参数errors来指定处理方式,常用的为直接忽略

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

写文件

写文件也是调用open()函数 只是传入的标识符为w或者wb表示写文本文件或写二进制文件

f3 = open('/Users/fish/Desktop/readme.txt', 'wb')
f3.write(b'\xe4\xb8\xad\xe6\x96\x87')
f3.close()

与读文件相同要记得调用close()方法,否则可能有部分未写入

与读文件相同,可以通过with语句 确保自动调用close()方法

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

通过encoding参数将字符转为指定编码
w默认为覆盖模式 a是append模式

StringIO 和 BytesIO

内存中进行读写

from io import StringIO

f4=StringIO("初始\n 字符串")
f4.write("hello,")
f4.write(" ")
f4.write("world!")

print(f4.getvalue())  # getvalue()方法用于获得写入后的内容
#hello, world!

from io import BytesIO
f5=BytesIO()
f5.write("中文".encode("utf-8"))
print(f5.getvalue())
# b'\xe4\xb8\xad\xe6\x96\x87'

要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:
和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:

from io import StringIO
f = StringIO('Hello!\nHi!\nGoodbye!')
while True:
     s = f.readline()
     if s == '':
         break
     print(s.strip())

# Hello!
# Hi!
# Goodbye!

from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
f.read()
# b'\xe4\xb8\xad\xe6\x96\x87'

操作文件和目录

操作文件和目录
通过os模块提供的功能

import os
os.name # posix 操作系统类型(posix表示是Linux、Unix、Mac OS,nt表示是Windows)

os.uname() #查看详细的系统信息
#posix.uname_result(sysname='Darwin', nodename='fishdeMacBook-Pro.local', release='17.5.0', version='Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/RELEASE_X86_64', machine='x86_64')

环境变量

os.environ #操作系统定义的全部环境变量
os.environ.get("PATH") # 获取某个环境变量值
os.environ.get('x', 'default') # 

操作文件和目录

操作文件和目录的函数 在osos.path

import os

currentPath=os.path.abspath(".")  # .表示当前路径
print(currentPath) # /Users/fish/Desktop/LYY/Python

joinDir=os.path.join("/Users/fish/Desktop", "testDir") #在目录下新建目录 获取新目录路径
print(joinDir) # /Users/fish/Desktop/testDir

splitDir=os.path.split("/Users/fish/Desktop/testDir")
print(splitDir) #('/Users/fish/Desktop', 'testDir')  获取最后一部分文件或目录
splitext=os.path.splitext("/Users/fish/Desktop/testDir") #获取扩展名 如果最后一部分为目录 则为空
print(splitext) # ('/Users/fish/Desktop/testDir/readme', '.txt')

os.mkdir("/Users/fish/Desktop/testDir2") #新建目录
os.rmdir("/Users/fish/Desktop/testDir2") #删除目录

os.path.join("/Users/fish/Desktop", "readme.txt")
os.rename('/Users/fish/Desktop/readme.txt', '/Users/fish/Desktop/readme.py')  # 重命名文件
os.remove('/Users/fish/Desktop/readme.py') # 删除文件

dirlist=os.listdir(".") #获取当前目录下的所有文件夹列表
os.path.isdir(".") # 判断是否为文件夹目录

当合并路径时,不要直接拼接字符串,通过os.path.join()函数可以正确处理不用操作系统的路径分隔符.
同理,拆分字符串时通过os.path.split()函数,可以把路径拆分为两部分,后一部分总是最后级别的目录或文件名
os.path.splitext()可以直接让你得到文件扩展名

os模块中并没有复制文件函数,可以再shutil模块中提供了copyfile()函数等使用的文件操作函数

序列化

Python通过pickle模块实现序列化

import pickle
#序列化
dict1=dict(name="Bob", age=24, score=88)
data=pickle.dumps(dict1)
print(data) #b'\x80\x03}q\...\x04KXu.'

#直接将序列化的内容写入文件
file1=open("/Users/fish/Desktop/readme.txt", "wb")
pickle.dump(dict1, file1)
file1.close()

#  将文件从磁盘读到内存后使用pickle.loads()方法反序列化出对象, 
#  也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象
file2=open("/Users/fish/Desktop/readme.txt", "rb")
dict2=pickle.load(file2)
file2.close()
print(dict2) #{'name': 'Bob', 'age': 24, 'score': 88}


JSON

dict可以转为json序列化

import json
print(json.dumps(dict1)) # {"name": "Bob", "age": 24, "score": 88}

file1=open("/Users/fish/Desktop/readme.txt", "w")
json.dump(dict1, file1)
file1.close()  # 文件内容为 {"name": "Bob", "age": 24, "score": 88}

将class 序列化为 json

import json

#序列化  原理是先将class转为dict 然后将dict序列化json

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

s = Student('Bob', 20, 88)

#专门写一个转换函数 将 class 转为json
def student2dict(std):
    return {
        'name': std.name,
        'age': std.age,
        'score': std.score
    }
# 传入更多参数来 指定序列化规则
print(json.dumps(s, default=student2dict))  #{"age": 20, "name": "Bob", "score": 88}

# 可以这么写 对大多数class都有__dict__属性来存储实例变量(__slots__除外)
print(json.dumps(s, default=lambda obj: obj.__dict__))

# 反序列化  原理为将json反序列化为dict 然后转为 class实例

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))