文件和目录操作(os,os.path),文件读写(open,with),序列化(pickle,json)

IO

  • Input/Output,也就是输入和输出;IO编程中,Stream(流)是一个很重要的概念
  • 方式
    • 同步IO
    • 异步IO
    • 同步和异步的区别就在于是否等待IO执行的结果;使用异步IO来编写程序性能会远远高于同步IO,但是异步IO的缺点是编程模型复杂
    • 操作IO的能力都是由操作系统提供的,每一种编程语言都会把操作系统提供的低级C接口封装起来方便使用
  • 此处的IO编程都是同步模式

操作目录和文件(os,os.path)

  • 操作目录和文件所需的模块os

    import os
    print(os.name) #操作系统名称
    print(os.environ) #环境变量
    ...
    
  • 更多操作见-os的源代码

操作文件和目录

  • Python的os模块封装了操作系统的目录和文件操作,要注意这些函数有的在os模块中,有的在os.path模块中

  • os.path 模块的几种常用方法

    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中包含的" n a m e " 和 " name"和" 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路径名

文件读写(open)

  • 在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)
  • open()函数,返回值是IO对象

常见格式

  • open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)
open(file, mode='r')

完整格式

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
  • file: 必需,文件路径(相对或者绝对路径)
  • mode: 可选,文件打开模式
  • buffering: 设置缓冲
  • encoding: 一般使用utf8
  • errors: 报错级别
  • newline: 区分换行符
  • closefd: 传入的file参数类型
  • opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符
file打开模式mode
模式描述
t文本模式 (默认)。
x写模式,新建一个文件,如果该文件已存在则会报错。
b二进制模式。
+打开一个文件进行更新(可读可写)。
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+打开一个文件用于读写。文件指针将会放在文件的开头。
rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
  • 默认为文本模式,如果要以二进制模式打开,加上 b 。
file常用的函数
方法及描述
file.close()关闭文件。关闭后文件不能再进行读写操作。
file.flush()刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
file.fileno() 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。
file.read(size])从文件读取指定的字节数,如果未给定或为负则读取所有。
file.readline(size)读取整行,包括 “\n” 字符。
file.readlines(sizeint)读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。
file.seek(offset, whence)移动文件读取指针到指定位置
file.tell()返回文件当前位置。
file.truncate(size)从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小。
file.write(str)将字符串写入文件,返回的是写入的字符长度。
file.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。

注意

  • 说明注意使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。

StringIO和BytesIO

  • 所在模块为IO模块

StringIO

  • 在内存中读写str

    from io import StringIO
    
    f = StringIO()
    f.write('write string')
    print(f.getvalue())
    
    # 结果
    write string
    
    from io import StringIO
    
    f = StringIO('this\nis\nstring')
    while True:
        s = f.readline() #也会读取\n
        if s == '':
            break
        print(s.strip()) # strip()会将\n剥掉
    
    # 结果
    this
    is
    string
    

BytesIO

  • 在内存中读写二进制

    from io import BytesIO
     
    f = BytesIO()
    f.write('二进制'.encode('utf-8')) # 对字符串进行编码encode为二进制
    print(f.getvalue())
    
    # 结果
    b'\xe4\xba\x8c\xe8\xbf\x9b\xe5\x88\xb6'
    
    from io import BytesIO
    
    f = BytesIO(b'\xe4\xba\x8c\xe8\xbf\x9b\xe5\x88\xb6')
    bytes_res = f.read()
    str_res = bytes_res.decode('utf-8') #对二进制进行解码decode为字符串
    print(bytes_res)
    print(str_res)
    
    # 结果
    b'\xe4\xba\x8c\xe8\xbf\x9b\xe5\x88\xb6'
    二进制
    

序列化(pickle,json)

  • 序列化所在模块pickle

序列化

其他语言的serialization等表示同一个意思

  • 序列化:从内存中变成可存储或传输的过程

    • 作用对象:Python中自身的数据类型,如变量,类,对象等…
  • 序列化用pickle.dumps(待序列化变量)pickle.dump(待序列化变量, 文件对象)

    import pickle
        
    d = dict(name='Bob', age=20)
    dump_res = pickle.dumps(d) #序列化,返回值是序列化的结果
    print(dump_res)
    
    # 将dump结果写入文件
    with open('dump_res.txt', 'wb') as f:
        f.write(dump_res)
    # 结果
    b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00Bobq\x02X\x03\x00\x00\x00ageq\x03K\x14u.'
    
    import pickle
        
    d = dict(name='Bob', age=20)
    f = open('dump_res.txt', 'wb')
    dump_res = pickle.dump(d, f) #在序列化的同时,把序列的结果存在文件里
                                 #返回值是None
    print(dump_res)
    f.close()
    
    # 结果
    None
    
    • 注意
      • pickle.dumps(变量)仅仅是序列化,返回序列化的结果
      • pickle.dump(变量, 文件对象)是将变量进行序列化并存入文件中,返回值是None

反序列化

  • 反序列化:把变量内容从序列化的对象重新读到内存里

  • 序列化用pickle.loads(序列化后的变量)pickle.load(文件对象)

    import pickle
    
    d = dict(name='Bob', age=20)
    dump_res = pickle.dumps(d) 
    load_res = pickle.loads(dump_res) #反序列化,返回值是反序列化的结果
    print(load_res)
    
    # 结果
    {'name': 'Bob', 'age': 20}
    
    import pickle
       
    with open('dump_res.txt', 'rb') as f:
        d = pickle.load(f) #反序列化
    print(d)    
    
    # 结果
    {'name': 'Bob', 'age': 20}
    

注意

  • Pickle的问题只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

Json(dumps,loads)

所在模块json

  • 如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON

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

  • JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下

    JSON类型Python类型
    {}dict
    []list
    “string”str
    1234.56int或float
    true/falseTrue/False
    nullNone
  • json模块的dumps()loads()函数是定义得非常好的接口的典范。当我们使用时,只需要传入一个必须的参数。但是,当默认的序列化或反序列机制不满足我们的要求时,我们又可以传入更多的参数来定制序列化或反序列化的规则

Json序列化基本数据类型
  • 由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的str与JSON的字符串之间转换。
序列化
  • json.dumps(基本数据类型)json.dump(基本数据类型, 文件对象)
import json

d = dict(name='Bob', age=20)
json_dump_res = json.dumps(d) #序列化,返回值是Json格式的数据
print(json_dump_res)

# 将dump结果写入文件
with open('json_dump_res.txt', 'w') as f:
    f.write(json_dump_res)

# 结果
{"name": "Bob", "age": 20}
import json
    
d = dict(name='Bob', age=20)
f = open('dump_res.txt', 'w')
json_dump_res = json.dump(d, f) #在序列化的同时,把序列的结果存在文件里
                                #返回值是None
print(json_dump_res)
f.close()

# 结果
None
反序列化
  • json.load(文件对象)
import json

with open('json_dump_res.txt', 'r') as f:
    res = json.load(f) #反序列化,并将反序列化的结果返回
print(res)

# 结果
{'name': 'Bob', 'age': 20}
Json序列化实例对象
  • Python的dict对象可以直接序列化为JSON的{}

  • 不过更多时候用class表示对象,然后序列化实例对象

    json序列化链接

需要定制Json序列化
  • json.dumps(基本数据类型, default=定制序列化函数名)
  • json.dump(基本数据类型, default=定制序列化函数名, fp=要保存进的文件名)
    • 因为默认情况下,json的dump方法不知道如何将实例变为一个JSON的{}对象,只需要为类专门写一个转换函数,再把函数传进去即可
import json

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

#自定义对象转化为json的函数,而非实例方法
def stu2dict(stu):
    return {
        'name':stu.name,
        'age':stu.age
    }

stu = Student('Alice', 20)
json_dumps_res = json.dumps(stu, default=stu2dict)#使用dumps()的 `default=定制转换函数名`
print(json_dumps_res)

# 结果
{"name": "Alice", "age": 20}
  • 因为通常class的实例都有一个__dict__属性,它就是一个dict;把任意class的实例变为dict
import json

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

stu = Student('Alice', 20)
json_dumps_res = json.dumps(stu, default=lambda obj: obj.__dict__)
print(json_dumps_res)

# 结果
{"name": "Alice", "age": 20}
# 保存到文件中
import json

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

#自定义对象转化为json的函数,而非实例方法
def stu2dict(stu):
    return {
        'name':stu.name,
        'age':stu.age
    }

stu = Student('Alice', 20)
with open('json_dump_obj_res.txt', 'w') as f:
    json_dumps_res = json.dump(stu, fp=f, default=stu2dict)#使用dumps()的 `default=定制转换函数名`
print(json_dumps_res)

# 结果
None
反序列化
  • json.dumps(Json字符串,object_hook=定制反序列化函数名),返回值反序列化的实例对象
  • json.dump(fp=json字符串文件,object_hook=定制反序列化函数名)
需要定制Json反序列化函数
import json

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

#自定义jso转化为dict的函数,而非实例方法
def dict2student(s):
    return Student(s['name'], s['age'])

json_str = '{"name": "Alice", "age": 12}'
json_dumps_res = json.loads(json_str, object_hook=dict2student)#object_hook=定制转换函数名
print(json_dumps_res)

# 结果
<__main__.Student object at 0x00000149AC4B9668>
# 从文件中读取
import json

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

#自定义jso转化为dict的函数,而非实例方法
def dict2student(s):
    return Student(s['name'], s['age'])

with open('json_dump_obj_res.txt', 'r') as f:
    json_dumps_res = json.load(fp=f, object_hook=dict2student)#object_hook=定制转换函数名
print(json_dumps_res)

# 结果
<__main__.Student object at 0x0000020C237D34A8>

说明

  • pickle用于Python特有的序列化操作,可以保存Python中任何数据类型。序列化结果使用二进制进行读写
  • json多用于数据交换,可以实现Json字符串与Python数据类型之间的序列化。序列化结果使用字符进行读写
  • dumpsloads分别用于在内存中的序列化;dumpload分别用于文件中的序列化

常见的文件操作

  • 一般文件打开模式只用r/w/a,一般不用**可读可写(+)**的模式

  • 自动关闭文件的方式:with

    with open('te.txt',mode='r',encoding = 'utf-8') as f:
    	f.read()
    	pass
    

读操作

f.readline()  # 读取一行内容,光标移动到第二行首部参数 

f.readlines()  # 读取每一行内容,存放于列表中,返回的结果是一个列表。

f.read(num)  # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾,是一个整形数值,表示一次性读入的字符数
  • 文件对象 f 也是一个 可迭代对象 在遍历文件对象的时候,默认一次拿一行
  • f.read()f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入

写操作

f.write(s) #s表示字符串类型

f.writelines(lines) #lines表示:内容为字符串类型的可迭代数据

f.truncate(num) #写入指定num个字节数的数据截取出来写入文件,原数据中的其他数据被情况
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值