Python 6 - IO
第29节 IO- input和print
-
input() 和 raw_input(),
-
都可以读取控制台的输入,但是input和raw_input在处理数字时是有区别的。当输入为纯数字时
- input返回的是数值类型,如int,float
- raw_inpout返回的是字符串类型,string类型
-
内在联系
def input(prompt): return (eval(raw_input(prompt)))
-
-
print(value, …, sep=’ ‘, end=’\n’, file=sys.stdout, flush=False)
- 第一个是可变参数,可以是任意长度, 任意类型
- sep, 多个打印参量之间的间隔,默认为’’
- end,结束符号, 默认为’\n’
- 格式化输出,参见字符串部分
第30节 IO-文件读写
-
打开文件 open()
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
打开模式 执行操作 ‘r’ 以只读方式打开文件 (默认) ‘w’ 以写入的方式打开文件,会覆盖已存在的文件 ‘x’ 创建新文件,以写的方式打开。如果文件已经存在,使用此模式打开会发生异常 ‘a’ 以写入模式打开,如果文件存在,则在末尾追加写入 ‘b’ 以二进制模式打开文件 ‘t’ 以文本模式打开(默认) ’+’ open a disk file for updating (reading and writing)可读写模式 (可以添加到其它模式中) ‘U’ 通用换行符支持。universal newline mode (deprecated已经弃用) f = open('/Users/Zhen/Documents/hello.txt') f # <open file '/Users/Zhen/Documents/hello.txt', mode 'r' at 0x105e80390>
-
文件对象的方法
文件对象方法 执行操作 f.close() 关闭文件 f.read([size=-1]) 从文件读取size个字符(可选),当未给定size或给定负值的时候,读取剩余的所有字符,然后作为字符串返回 f.readline([size=-1]) 从文件中读取并返回一行(包括行结束符),如果有size定义则返回size个字符 f.write(str) 将字符串str写入文件 f.writeline(seq) 向文件希尔字符串序列seq,seq应该是一个返回字符串的可迭代对象 f.seek(offset, from) 在文件中移动文件指针(修改文件指针),从from(0代表文件起始位置,1代表当前位置,2代表文件末尾)偏移offset个字节 f.tell() 返回当前在文件中的位置 f.truncate([size=file.tell()]) 截取文件到size个字节,默认是截取到文件指针当前位置 -
读文件 read(), readline()
f = open('/Users/Zhen/Documents/hello.txt',encoding='utf-8') f = open('/Users/Zhen/Documents/hello.txt') f # <_io.TextIOWrapper name='/Users/Zhen/Documents/hello.txt' mode='r' encoding='utf-8'> f.read() # 不设置size参数,默认读入所有内容 f.read() # '', 因为现在文件指针在文档的末尾,所以返回'' f.tell() # 876, 返回当前文件指针的位置 f.seek(10, 0) # 0, 调整文件指针的位置,并返回修改后文件指针的文章 f.readline() # 读取一行 list(f) #直接把文件转换成列表,每行是一个元素 !!!!效率极低 # f本身就是可迭代的,所以可以直接遍历之 for each_line in f: print(each_line) f.close()
-
写文件 write(), 和 writeline()
# 要写入文件,确保以可写的模式打开文件/创建文件 f = open("/Users/Zhen/Desktop/write.txt", 'w') # write(str)写入字符串,返回写入字符的个数 f.write("hello world") # 11 # writeline(list_of_str), 写入字符串序列 f.writelines(["one", "two", "three", "four"])
-
refer more to link
第31节 IO-文件综合
任务:将文件(record.txt)中的数据进行分割并按照以下规律保存起来:
- 小甲鱼的对话单独保存为boy_*.txt的文件(去掉“小甲鱼:”)
- 小客服的对话单独保存为girl_*.txt的文件(去掉“小客服:”)
- 文件中总共有三段对话,分别保存为boy_1.txt, girl_1.txt,boy_2.txt,girl_2.txt, boy_3.txt, gril_3.txt共6个文件(提示:文件中不同的对话间已经使用“==========”分割)
# 要让python知道文件中使用的是什么编码形式,对于中文,可以用的常见编码有utf-8,gbk和gb2312等。只需在代码文件的最前端添加如下: # -*- coding: utf-8 -*-
# -*- coding: gbk -*-
f = open("/Users/Zhen/Desktop/record.txt", encoding="gbk")
fb1 = open("/Users/Zhen/Desktop/boy1.txt", 'w', encoding="gbk")
fg1 = open("/Users/Zhen/Desktop/girl1.txt",'w', encoding="gbk")
boy_tp = "小甲鱼:"
girl_tp = "小客服:"
sep_tp = "===="
for each_line in f:
if each_line[:4] == boy_tp:
fb1.write(each_line[4:] + '\n')
elif each_line[:4] == girl_tp:
fg1.write(each_line[4:] + '\n')
elif each_line[:4] == sep_tp:
break
else:
break
fg1.close()
fb1.close()
f.close()
# -*- coding: gbk -*-
f = open('record.txt')
boy = []
girl = []
count = 1
for each_line in f:
if each_line[:6] != '======':
(role, line_spoken) = each_line.split(':', 1)
if role == '小甲鱼':
boy.append(line_spoken)
if role == '小客服':
girl.append(line_spoken)
else:
file_name_boy = 'boy_' + str(count) + '.txt'
file_name_girl = 'girl_' + str(count) + '.txt'
boy_file = open(file_name_boy, 'w')
girl_file = open(file_name_girl, 'w')
boy_file.writelines(boy)
girl_file.writelines(girl)
boy_file.close()
girl_file.close()
boy = []
girl = []
count += 1
file_name_boy = 'boy_' + str(count) + '.txt'
file_name_girl = 'girl_' + str(count) + '.txt'
boy_file = open(file_name_boy, 'w')
girl_file = open(file_name_girl, 'w')
boy_file.writelines(boy)
girl_file.writelines(girl)
boy_file.close()
girl_file.close()
f.close()
小客服:小甲鱼,今天有客户问你有没有女朋友?
小甲鱼:咦??
小客服:我跟她说你有女朋友了!
小甲鱼:。。。。。。
小客服:她让你分手后考虑下她!然后我说:"您要买个优盘,我就帮您留意下~"
小甲鱼:然后呢?
小客服:她买了两个,说发一个货就好~
小甲鱼:呃。。。。。。你真牛!
小客服:那是,谁让我是鱼C最可爱小客服嘛~
小甲鱼:下次有人想调戏你我不阻止~
小客服:滚!!!
================================================================================
小客服:小甲鱼,有个好评很好笑哈。
小甲鱼:哦?
小客服:"有了小甲鱼,以后妈妈再也不用担心我的学习了~"
小甲鱼:哈哈哈,我看到丫,我还发微博了呢~
小客服:嗯嗯,我看了你的微博丫~
小甲鱼:哟西~
小客服:那个有条回复“左手拿著小甲魚,右手拿著打火機,哪裡不會點哪裡,so easy ^_^”
小甲鱼:T_T
================================================================================
小客服:小甲鱼,今天一个会员想找你
小甲鱼:哦?什么事?
小客服:他说你一个学生月薪已经超过12k了!!
小甲鱼:哪里的?
小客服:上海的
小甲鱼:那正常,哪家公司?
小客服:他没说呀。
小甲鱼:哦
小客服:老大,为什么我工资那么低啊??是时候涨涨工资了!!
小甲鱼:啊,你说什么?我在外边呢,这里好吵吖。。。。。。
小客服:滚!!!
def save_file(boy, girl, count):
file_name_boy = 'boy_' + str(count) + '.txt'
file_name_girl = 'girl_' + str(count) + '.txt'
boy_file = open(file_name_boy, 'w')
girl_file = open(file_name_girl, 'w')
boy_file.writelines(boy)
girl_file.writelines(girl)
boy_file.close()
girl_file.close()
def split_file(file_name):
f = open('record.txt')
boy = []
girl = []
count = 1
for each_line in f:
if each_line[:6] != '======':
(role, line_spoken) = each_line.split(':', 1)
if role == '小甲鱼':
boy.append(line_spoken)
if role == '小客服':
girl.append(line_spoken)
else:
save_file(boy, girl, count)
boy = []
girl = []
count += 1
save_file(boy, girl, count)
f.close()
split_file('record.txt')
第32节 IO-文件系统(os/os.path模块)
-
模块(可用代码段的打包): 模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。
-
模块的导入形式:
import xxx
import xxxxxx as xx
from xxxxx import oooooo as oo
-
os 模块常用函数,os.path 模块常用函数,refer to here
-
os模块
import os # 获取当前工作目录, os.getcwd() # '/Users/Zhen/Coding/pycharm/EAVNSIM' # 改变工作目录,需要(path)参数 os.chdir("/Users/Zhen/Desktop") # 列举制定目录中所有文件, 默认当前目录 os.listdir(path='.') # 创建单层目录,如果该目录已经存在则抛出异常, 需要(dir_path)参数 os.mkdir('temp_file') # 创建多层目录,如果该目录已经存在则抛出异常,需要(dir_path)参数 os.makedirs('temp_hello/hello') # 删除文件, 需要(file_path)参数 os.remove('test.txt') # 删除单层目录, 需要(dir_path)参数,如果该目录非空则抛出异常 os.rmdir('temp_file') # 递归删除目录, 需要(dir_path)参数,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常 os.removedirs('temp_hello/hello') # 给文件重命名 (old, new) os.rename('temp_hello', "temp_secret") # 运行系统的(command)命令 os.system('pwd') # 遍历(top_path)路径以下所有的子目录,返回一个三元组(路径,[包含目录],[包含文件]) os.walk(top_path) # 常用的量 os.curdir # 指代当前的目录 '.' os.pardir # 指代上一级目录 '..' os.sep # 操作系统特定的路径分隔符(win:\\, Unix:/) os.linesep # 当前平台使用的行终止符(win:\r\n, Unix:\n) os.name # 当前使用的操作系统
-
os.path 模块
import os.path as p # 1. 获取文件和路径信息 # 去掉目录路径,单独返回文件名 p.basename(path) # 去掉文件名,单独返回目录路径 p.dirname(path) # 返回指定文件的尺寸,单位是字节 p.getsize(file) # 返回指定文件的最近的访问时间 p.getatime(file) # 返回指定文件的创建时间 (浮点型秒数,可以用time模块的gmtime()或local time()函数换算) p.getctime(file) # 返回指定文件的最新的修改时间 p.getmtime(file) # 2. 路径的拼接和拆分 # 将path1 和 path2 组合成一个路径名 p.join(path1[, path2[,path3..]]) # 判断 path1 和 path2两个路径是否指向同一个文件 p.samefile(path1, path2) # 分割文件名和路径,返回(f_path, f_name)元组。如果完全适用目录,它也会将最后一个目录作为文件名分离,且不会判断文件或者目录是否存在 p.split(path) # 分离文件名和扩展名,返回(f_name, f_extension)元组 p.splitext(path) # 3. 判断文件和路径,返回 True / False # 判断指定路径(目录or文件)是否存在 p.exists(path) # 判断指定路径是否为 绝对路径 p.isabs(path) # 判断指定路径是否存在且是一个 目录 p.isdir(path) # 判断指定路径是否存在且是一个 文件 p.isfile(path) # 判断指定路径是否存在且是一个 符号链接 p.islink(path) # 判断指定路径是否存在且是一个 挂载点 p.ismount(path)
第33节 IO-序列化之pickle
-
pickle模块:为了方便从数据(列表,元组,整形,浮点,字符串)快速转换和存储为二进制文件(字节流)
-
两个基本的函数. 存放-pickling: 从所有对象转换为字节流, 读取-unpickling: 从字节流转换为对象
# 存数据 import pickle my_list = [1, 3.14, 520, "hello world", ['one', 'two', 'three']] pickle_file = open("my_list.pkl", 'wb') # 后缀名是不重要的, as in linux # dump函数 pickle.dump(my_list, pickle_file) pickle_file.close()
# 读数据 import pickle pickle_file = open("my_list.pkl", 'rb') # load 函数 my_list = pickle.load(pickle_file) print(my_list) pickle_file.close()
-
以后这种大型的字典,列表信息,直接存放处pickle形式会更好,更高效简洁
-
BUT,Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
第34节 IO-序列化之JSON
-
WHY JSON? Pickle只支持python,如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
-
JSON表示的对象就是标准的JavaScript语言的对象
-
JSON 和 python内置数据类型的对比
JSON类型 | Python类型 |
---|---|
{} | dict |
[] | list |
“string” | str |
1234.56 | int或float |
true/false | True/False |
null | None |
-
基本数据和JSON的转换
Python内置的
json
模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON:>>> 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
。要把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编码是UTF-8,所以我们总是能正确地在Python的
str
与JSON的字符串之间转换。 -
自定义对象和JSON的转换
Python的
dict
对象可以直接序列化为JSON的{}
,不过,很多时候,我们更喜欢用class
表示对象,比如定义Student
类,然后序列化: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))
运行代码,毫不留情地得到一个
TypeError
:Traceback (most recent call last): ... TypeError: <__main__.Student object at 0x10603cc50> is not JSON serializable
错误的原因是
Student
对象不是一个可序列化为JSON的对象。如果连
class
的实例对象都无法序列化为JSON,这肯定不合理!别急,我们仔细看看
dumps()
方法的参数列表,可以发现,除了第一个必须的obj
参数外,dumps()
方法还提供了一大堆的可选参数:https://docs.python.org/3/library/json.html#json.dumps
这些可选参数就是让我们来定制JSON序列化。前面的代码之所以无法把
Student
类实例序列化为JSON,是因为默认情况下,dumps()
方法不知道如何将Student
实例变为一个JSON的{}
对象。可选参数
default
就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为Student
专门写一个转换函数,再把函数传进去即可:def student2dict(std): return { 'name': std.name, 'age': std.age, 'score': std.score }
这样,
Student
实例首先被student2dict()
函数转换成dict
,然后再被顺利序列化为JSON:>>> print(json.dumps(s, default=student2dict)) {"age": 20, "name": "Bob", "score": 88}
不过,下次如果遇到一个
Teacher
类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class
的实例变为dict
:print(json.dumps(s, default=lambda obj: obj.__dict__))
因为通常
class
的实例都有一个__dict__
属性,它就是一个dict
,用来存储实例变量。也有少数例外,比如定义了__slots__
的class。同样的道理,如果我们要把JSON反序列化为一个
Student
对象实例,loads()
方法首先转换出一个dict
对象,然后,我们传入的object_hook
函数负责把dict
转换为Student
实例: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>
打印出的是反序列化的
Student
实例对象。