一、文件IO常用操作

1、open打开、read读取、write写入、close关闭、readline行读取、readlines多行读取、seek文件指针操作、tell指针位置
2、open(file,mode="r",buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)
3、encoding='cp936'/‘utf-8’,一个是windows下的,一个linux下的
4、open的参数:
    1、file----打开或要创建的文件,如果不指定路径,默认是当前路径

    2、mode(模式)
        1、r,缺省的,表示只读打开,不写则r
        2、w,只写打开----如果文件在,则覆盖之前内容,如果文件不存在,则创建文件
        3、x,创建并写入一个新文件只写打开,原来有则创建失败
        4、a,写入打开,原来有则追加
        5、b,二进制模式,rb,wb
        6、t,缺省的,文本模式
        7、+读写打开一个文件,将缺少的权限补上,r+,w+,x+,a+
    3、mode=r指针起始在0
        mode=a指针起始在EOF,end of file
        tell()显示指针现在的位置
        seek(offset[,whence])移动指针位置,offset偏移多少字节,whence表示从哪里开始
    4、文本模式下:
        1、whence=0,缺省值,表示从头开始,offset只能接受正整数
        2、whence=1,表示从当前位置,offset只接受0
        3、whence=2,表示从EOF位置,offset只接受0

      

    5、二进制模式下:
        1、whence=0,缺省值,表示从头开始,offset只能是正整数
        2、whence=1,表示从当前位置,offset可正可负
        3、whence=2,表示从EOF位置,offset可正可负
        4、向前的负数,不可超界
5、buffering:缓冲区
    1、-1表示使用缺省大小,如果是二进制模式,使用io.DEFAULT_BUFFER_SIZE值,一般4096或8192
    2、文本模式,如果是终端,是行缓存,不是的话,按照二进制的缓存模式
    3、参数含义
        1、0只在二进制模式下使用,表示关闭buffer
        2、1只在文本模式使用,表示使用行缓冲,见到换行符就flush
        3、大于1用于指定buffersize,但是文本模式没什么用
    4、flush()将缓冲区数据写入磁盘,close()关闭前会flush一下
    5、写法
    import io
  f = open('text','w+b',16)
  print(io.DEFAULT_BUFFER_SIZE)
  f.write('magedu.com'.encode())
  f.seek(0)
  f.write('www.magedu.com'.encode())
  f.flush()
  f.close()
    6、文本模式行缓冲
    f = open('text','w+',1)
    f.write('mag')
    f.write('mag'*4)
    f.write('\n')
    f.write('edu')
    f.seek(0)
    f.read()
    f.close()
    7、无缓存的二进制文件,FIFO文件
    f = open('text','w+b',0)
    f.write(b'm')
    f.write(b'a')
    f.write(b'g')
    f.write('magedu'.encode()*4)
    f.write(b'\n')
    f.write(b'Hello\nPython')
6、文本模式,一般都用默认缓存大小
    二进制模式,是一个个字节的操作,可以指定buffer大小
    一般来说,默认缓冲大小是最好的选择
    一般编程中,需要写磁盘,调用flush(),不需要则在自动flush时或close()时
7、其他参数
    1、errors:什么样的编码错误将被捕获:None和strict表示有编码错误将抛出ValueError错误,ignore表示忽略
  2、newline:文本模式中,换行的转换,可以为None,"、","\r","\n","\r\n"读时,None表示上面符号都变成"\n",表示不会自动转换通用换行符,其他合法字符表示换行符就是指定字符,按照指定字符分行写时,None表示"\n"都会被替换为系统缺省行分隔符"os.linesep","\n"或""表示"\n"不替换,其他合法字符表示"\n"会被替换成指定字符
  3、closefd:关闭文件秒数符,True表示关闭,False表示在close后还保持这个秒数符
8、read(size=-1)
  read表示读取多少字符或字节,负数或None表示全部读取
9、readline(size=-1)
  一行行读取文件内容,size设置一次能读取行内几个字符或字节。
10、readlines(hint=-1)
  读取所有行的列表,指定hit返回指定的行数
11、其他:
  1、seekable()是否可seek
  2、readable()是否可读
  3、writable()是否可写
  4、closed是否已关闭
12、上下文管理
    1、使用finally来关闭文件
    f = open('test','r+')
  try:
      f.write('abc')
  finally:
     f.close()
  print(f.closed)
    2、使用with as关键字
  with open('test') as f:
      f.write('abc')
  print(f.closed)
    3、f = open('test','r+')
    with f:
        f.write('abc)
    print(f.closed)
二、StringIO
1、io模块中的类,在内存中开辟一个文本模式的buffer,可以像文件对象一样操作,close则关闭,内存足够少落地,提高效率
from io import StringIO
sio = StringIO()
print(sio.readable(),sio.seekable(),sio.writable())
sio.write('magedu\nPython')
sio.seek(0)
print(sio.readline())
sio.seek(0)
print(sio.readlines())
print(sio.getvalue())
sio.close()
print(sio.closed)
2、getvalue()
获得全部内容,跟指针没有关系
三、BytesIO
1、io模块中的类,开辟二进制的buffer,操作与StringIO类    
from io import BytesIO
bio = BytesIO()
print(bio.readable(),bio.writable(),bio.seekable())
bio.write(b'magedu\nPython')
bio.seek(0)
print(bio.readline())
print(bio.getvalue())
bio.close()
print(bio.closed)
四、file-like对象
1、类文件对象,可以像文件对象一样操作
2、socket对象、输入输出对象(stdin、stdout)都是类文件对象    
from sys import stdout
from sys import stdin
f = stdout
print(type(f))
print(f.write('abc'))
stdin不能写,stdout不能读
五、路径操作
1、路径操作模块
  3.4版本之前
  1、os.path模块
  from os import path
  p = path.join('/etc','sysconfig','network')
  print(type(p),p)
  print(path.exists(p))
  print(path.split(p))         #取*head,tail
  print(path.abspath('.'))     #绝对路径,当前工作路径,"."是当前路径
  p = path.join('o:/',p,'test.txt')
  print(path.dirname(p))       #当前路径
  print(path.basename(p))      #basename
  print(path.splitdrive(p))    #驱动器
  3.4版本之后
  2、pathlib模块       
  from pathlib import Path
  p = Path()
  print(type(p)) # windows和Linux不同
  print(p) # '.',两个系统一样
  print(p.absolute()) # 不同
  p = p.joinpath('a','b') # 路径操作
  print(p)
  print(p.absolute())
  p = p/'c'/'d' # 可以直接操作路径
  p/='e''/''f' # /=类似于+=
  print(p)
  p1 = Path('/etc') # 从根开始,绝对路径
  print(p1)
  print(p1.absolute())
  # p2 = '/etc'/'sysconfig' 字符串拼接,p2不在,不能直接操作
  p2 = Path('.')
  p2 = p2 / '/etc/' / 'sysconfig' # /etc,强行从根开始
  p3 = Path('a','b','c')
  print(p2)
  print(p2.parts) # 拿属性,生成元组,方便迭代
  p4 = p2.joinpath('a','b','c')
  print(p4)
  print(str(p4),'\n',bytes(p4)) # 路径字符串
  print(p4.parent)
  print(p4.parent.parent)
  print(p4.parents) # 可迭代对象
  print(list(p4.parents)) # 最亲的开始
  print(list(p4.parents)[0]) # 取第一个
  print(next(iter(p4.parents))) # list不可迭代,换成iter,a = iter(p4.parents)---->next(a)
  p5 = Path()
  print(list(p5.absolute().parents)) # p5是空的,用绝对路径包一下
    3、属性操作       
  from pathlib import Path
  p = Path('a','b','c','d')
  p /= 'e''/''f'
  p = p.joinpath('xx.ifg')
  p1 = Path(str(p) + '.gz')
  print(p1)
  print(p.name) # 目录的最后一部分,全部
  print(p.stem) # 目录的最后一个部分,没有后缀名
  print(p.suffix) # 目录的最后一部分的扩展名
  print(p1.suffixes) # 返回多个扩展名列表
  print(p1.with_suffix('.rgz')) # 替换扩展名
  print(p1.with_name('test.tgz')) # 替换name
  print(p1.parent/'test.tgz')  # 同上
    4、命令        
  from pathlib import Path
  p = Path()
  p = p/'/a'/'b'/'c'
  print(p.cwd()) # 当前工作路径,与描述的路径无关
  print(p.home()) # 当前home,与其他无关
  print(p.is_dir()) # 当前描述的路径是不是目录,不过目前没有,所以False
  print(p.is_file()) # 同上,不存在则False
  print(p.is_symlink()) # 软连接
  print(p.is_socket()) # socket文件
  print(p.is_block_device()) # 块设备
  print(p.is_char_device()) # 字符设备
  print(p.is_absolute()) # 绝对路径
  # print(p.resolve())
  # 返回一个新路径,是当前Path对象的绝对路径,如果是软连接,则被解析,但不存在的话,则报错
  # 临时可以用absolute,推荐使用resolve
  print(p.exists())
  # p.rmdir() # 删除空目录
  p1 = Path('')
  p1 /= p1/'D:/'/'QQLive'/'mysql.tar.gz'
  p1 = p1.with_name('test.txt')
  p1.touch()    #创建
  print(p1.resolve())
  5、
    print(p1.as_uri())  # 生成url
  p2.mkdir()  #创建目录,p2.mkdir(parents=True)
  Path().iterdir()   # 迭代当前目录,是个生成器
  for x in Path().iterdir():
      if x.is_dir():
          print(x)
    6、通配符,rglob(*.py)这个是递归获取,和最后一种一样
  print(list(Path('D:/','QQLive').glob('*.gz')))
  print(list(Path('D:/','QQLive').glob('*/*.gz')))  # 找本层和上一层
  print(list(Path('D:/','QQLive').glob('**/*.gz'))) # 找本层和任意层
  7、匹配 match      
  from pathlib import Path
  print(Path('a/b.py').match('.py'))
  print(Path('.py').match('*.py')) # .py是隐藏文件,用*是匹配0个
  print(Path('a/b/c.py').match('a/*py'))
  print(Path('a/b/c.py').match('a/*/*py')) # */,没有或一级
  print(Path('a/b/c.py').match('a/**/*py'))
    8、文件操作        
  from pathlib import Path
  p = Path('D:/QQlive/hello')
  p.mkdir()
  p = p/'hello.txt'
  p.touch()
  print(p.match('*txt'))
  # p.open('r+') # 没有则w+
  with p.open('r+') as f:
  f.write('abc')
  # 直接调用下面的也一样
  p.write_text('abc')
  p.read_text(2)
  p.write_bytes(b'hello')
  p.read_bytes()
2、os模块
    import os
  import sys
  print(os.name)
  # print(os.uname()) # linux的命令
  print(os.listdir('D:/')) # 返回目录内容列表
  print(sys.platform) # 显示win32,64
  print(os.listdir())
  print(os.stat('D:/')) # 获取权限等属性
  os.chmod('test',0o777)
  os.chown(path,uid,gid) # 改变属主,属组
3、shutil模块
    import os
  import shutil
  with open('o:/test','r+') as f1:
  f1.write('abcde')
  f1.flush()
  f1.seek(0)
  with open('0:/test1','w+') as f2:
  shutil.copyfileobj(f1,f2)
  # 复制内容
  shutil.copyfile('D:\QQLive/test.txt','D:\QQLive/test2.txt')
  # 复制内容,本质上还是obj的用法
  shutil.copymode('D:\QQLive/test.txt','D:\QQLive/test2.txt')
  # 仅仅复制权限
  shutil.copystat('test','test1')
  # 复制元数据,包括权限
  shutil.copytree('src','dst')
  # copy2可以拷贝权限属性内容,比copy多属性
  # src必须存在,dst必须不存在,递归复制目录,默认使用copy2,不拷贝隐藏文件
  shutil.rmtree('path')
  # 递归删除,慎用,不是原子操作,删到一半失败了,前面的没了
  os.rename('D:/QQlive/test2.txt','D:/dst')
  # 这就是move,从哪里改到哪里
二、csv文件
1、逗号分割的值,也可以自定义分割符
2、被行分隔符,列分隔符划分成行和列的文本文件
3、行分割符为、\r\n,最后一行可以没有换行符
4、列分隔符常为逗号或者制表符
5、每一行成为一条记录record
6、字段可以双引号括起来,也可以不使用,如果字段中出现了双引号,逗号,换行符必须使用双引号括起来,如果字段的值是双引号,使用两个双引号表示一个转义
7、
import os
s = """\    # 第一行换行去掉,小技巧
    1,tom,20,
    2,jerry,16,
    3"""
with open('D:/QQlive/test.csv','w') as f:
    for line in s.splitlines():
        f.write(line +"\n")
8、
import csv
from pathlib import Path
p = Path('D:/QQlive/test.csv')
if not p.parent.exists():
    p.parent.mkdir(parents=True)
s = '''\
  1,tom,20,
  2,jerry,16,
  3,,,
  '''
line1 = [1,"tom",20,'']
line2 = [2,"tom",20,'']
line3 = [line1, line2]
with open(str(p),'w') as f:
    writer = csv.writer(f)
  writer.writerow(line1)
  writer.writerow(line2)
  writer.writerows(line3)
with open(str(p)) as f:
    reader = csv.reader(f)
    for line in reader:
        if line:
            print(line)
9、ini文件,配置文件
from configparser import ConfigParser
cfg = ConfigParser()
cfg.read('D:/QQlive/test.ini')
cfg.sections()    # 区
for section in cfg.sections():
    for option in cfg.options(section):  # key
        print(section,option)
# for k,v in cfg.items():
    # print(k,v)
for k,v in cfg.items(section):
  print(k,v)
  if not cfg.has_section('test'):
    cfg.add_section('test')
     cfg.set('test','test1','123')
    cfg.set('test','test2','abc')
    # 内存中操作,没写入文件内,下面写进去
with open("D:/QQlive/test.ini",'w') as f:
  cfg.write(f)
  a = cfg.get('test','test1')
  print(a)
  b = cfg.getint('test','test1')
  print(b)
  cfg.remove_option('test','test2')
三、序列化和反序列化
1、serialization 序列化
将内存中对象存储下来,变成一个个字节--》二进制
2、deserialization 反序列化
将文件中的一个个字节恢复成内存中对象  《--二进制
3、序列化保存到文件就是持久化
可以将数据序列化后持久化,或者网络传输,也可以将文件中或者网络接受到的字节序列反序列化
4、pickle库,只解决python的序列化
dumps 对象序列化
dump 对象序列化到文件对象,就是存入文件
loads 对象反序列化
load 对象反序列化,从文件读取数据 
# 反序列化必须有对应的数据类型,否则报错,尤其是自定义类,必须远程得有
import pickle
lst = 'a b c'.split()
d = dict(zip('abc',range(3)))
with open("D:/QQlive/pickle",'wb') as f:
  pickle.dump(lst,f)    # 序列化,生成在上面文件中
  pickle.dump(d,f)
with open("D:/QQlive/pickle",'rb') as f:
  tmp = pickle.load(f)   # 反序列化,需要接住
  print(tmp)
  tmp = pickle.load(f)
  print(tmp)
四、json
1、值:双引号引起来的字符串"",数值123,true和false,null,对象{},数组[]
2、字符串,由双引号包起来的任意字符,包括中文
3、数值,正负,整数,浮点数
4、对象:无序的键值对的组合,格式:{key1:value1,..,keyn:valuen},key必须是字符串
5、数组,有序的值的组合:[value1,..,valuen]
6、json类型
Python类型   Json类型
True       true
False       false
None       null  一个空值
str        string
int        integer
float       float
list       array
dict       object
7、    
import json
d={'a':123,'b':['abc',{'c':234}],'d':True,'e':False,'f':None}
print(d)
class AA:
  def ser(self):
     return 'AA'
a = json.dumps(d)
print(a)
print(json.dumps(AA().ser()))
五、MessagePack二进制的序列化
import json
import msgpack
js = {'a':123,'b':['abc',{'c':234}],'d':True,'e':False,'f':None}
a = json.dumps(js)
print(a)
b = json.loads(a)
print(b)
c = msgpack.packb(js)
print(c)
d = msgpack.unpackb(c,encoding='utf-8') # encoding转换注意
print(d)