• 中文
    • English
  • 注册
  • 查看作者
  • 第十七章:IO编程

    一. 读文件

    读文件可以使用open()函数,传入文件名和标示符,标识符有以下几种:

    open('文件名','r'):读取UTF-8编码的文本文件

    open('文件名','rb'):读取二进制文件,比如图片、视频等

    open('文件名', 'r', encoding='gbk'):读取GBK编码的文本文件

    open('文件名', 'r', encoding='gbk', errors='ignore'):读取GBK编码的文本文件,并忽略错误编码

    f = open('/Users/zhangjia/Desktop/test.txt','r')
    print(f.read())
    f.close()

    读完文件后必须调用close方法关闭文件,但是如果我们访问不存在的文件就可能触发IOError,除了可以通过try捕获外,Python还引入了with语句来自动帮我们调用close()方法

    with open('/Users/zhangjia/Desktop/test.txt','r') as f:
        for line in f.readlines():
            print(line.strip())  # line存储了数组内容,通过strip把末尾的'\n'删掉

    open函数返回的对象可以调用以下几种用法:

    • read():一次性读取文件的全部内容

    • read(size):一次读取指定大小的文件内容

    • readlines():一次读取所有内容并按行返回list,适合读取配置文件

    像open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object,file-like Object不要求从特定类继承,只要写个read()方法就行,StringIO就是在内存中创建的file-like Object,常用作临时缓冲。

    二. 写文件

    写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件,以'w'模式写入文件时,如果文件已存在,会直接覆盖(相当于删掉后新写入一个文件)。通过传入'a'参数可以在文件末尾以追加(append)模式写入。

    # with open('/Users/zhangjia/Desktop/test.txt','w') as f:
    with open('/Users/zhangjia/Desktop/test.txt','a') as f:
        f.write("123456")

    三. StringIO和BytesIO

    在内存中读写str:

    >>> from io import StringIO
    >>> f = StringIO()
    >>> f.write('hello')
    5
    >>> f.write(' ')
    1
    >>> f.write('world!')
    6
    >>> print(f.getvalue())
    hello world!

    在内存中读写二进制数据:

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

    此外,要读取StringIO和BytesIO,还可以用一个str初始化,然后,像读文件一样读取

    >>> from io import StringIO
    >>> f = StringIO('Hello!\nHi!\nGoodbye!')
    
    >>> from io import BytesIO
    >>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')

    四. 操作文件和目录

    常见操作文件和目录的操作如下代码,注意,把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符,同理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数

    import  os
    import shutil
    print(os.name) # 操作系统类型
    print(os.uname) # 获取详细的系统信息
    print(os.environ) # 操作系统中定义的环境变量
    print(os.environ.get('PATH')) # 获取某个具体的环境变量的值
    # 查看当前目录的绝对路径:
    print(os.path.abspath('.')) # /Users/zhangjia/Personal/Python/Projects/Test
    # 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
    print(os.path.join('/Users/zhangjia/Desktop', 'newDir'))
    # 然后用上面的输出,创建一个目录:
    os.mkdir('/Users/zhangjia/Desktop/newDir')
    # 删掉一个目录:
    os.rmdir('/Users/zhangjia/Desktop/newDir')
    # 获取扩展名
    os.path.splitext('/Users/zhangjia/Desktop/text.txt')
    # 重命名文件
    os.rename('/Users/zhangjia/Desktop/text.txt', '/Users/zhangjia/Desktop/text2.txt')
    # 删除文件
    os.remove('/Users/zhangjia/Desktop/text2.txt')
    # 新建文件
    with open('/Users/zhangjia/Desktop/text3.txt','w') as f:
        f.write(123)
    # 复制文件
    shutil.copy('/Users/zhangjia/Desktop/text3.txt','/Users/zhangjia/Desktop/text4.txt')

    要列出当前目录下的所有目录,只需要一行代码:

    import  os
    print([x for x in os.listdir('.') if os.path.isdir(x)])

    要列出所有的.py文件,也只需一行代码

    import  os
    [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']

    五. 序列化

    我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。Python提供了pickle模块来实现序列化。

    方法一:pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件

    import pickle
    d = dict(name='Jia', age=20, score=88)
    print(pickle.dumps(d))

    方法二:pickle.dump()直接把对象序列化后写入一个file-like Object

    import pickle
    
    f = open('dump.txt', 'wb')
    d = dict(name='Bob', age=20, score=88)
    pickle.dump(d, f)
    f.close()

    当我们要把对象从磁盘读到内存时,可以先把内容读到一个bytes,然后用pickle.loads()方法反序列化出对象

    import pickle
    
    d = pickle.loads(b'\x80\x04\x95$\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x03Jia\x94\x8c\x03age\x94K\x14\x8c\x05score\x94KXu.')
    print(d)

    也可以直接用pickle.load()方法从一个file-like Object中直接反序列化出对象。

    import pickle
    
    f = open('dump.txt', 'rb')
    d = pickle.load(f)
    f.close()
    print(d)

    但Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据

    六. JSON

    JSON和Python内置的数据类型对应如下:

    第十七章:IO编程

    把Python对象转换成JSON:

    import json
    d = dict(name='Jia', age=20, score=88)
    print(json.dumps(d))

    dump()方法可以直接把JSON写入一个file-like Object

    把JSON转换为Python对象:

    import json
    json_str = '{"age": 20, "score": 88, "name": "Jia"}'
    print(json.loads(json_str))

    七. 序列化自定义类

    自定义序列化类是没法直接序列化的,需要写def student2dict(std)转换函数,也可以直接通过传参的方式转换:

    import json
    
    
    class Student(object):
        def __init__(self, name, age, score):
            self.name = name
            self.age = age
            self.score = score
    
    
    def student2dict(std):
        return {
            'name': std.name,
            'age': std.age, 
            'score': std.score
        }
    
    
    s = Student('Jia', 20, 88)
    # print(json.dumps(s)) #TypeError
    print(json.dumps(s, default=lambda obj: obj.__dict__))

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

    import json
    
    
    class Student(object):
        def __init__(self, name, age, score):
            self.name = name
            self.age = age
            self.score = score
    
    def dict2student(d):
            return Student(d['name'], d['age'], d['score'])
    
    j = '{"name": "Jia", "age": 20, "score": 88}'
    print(json.loads(j)) #{'name': 'Jia', 'age': 20, 'score': 88}
    print(json.loads(j,object_hook=dict2student)) #<__main__.Student object at 0x7fbb000a8250>

    参考资料

    [1] 廖雪峰-Python教程

  • 2
  • 2
  • 0
  • 2k
  • 你又不囍赵睿宇ibigshot

    请登录之后再进行评论

    登录
  • 1
    55555
  • 0
    1
  • 单栏布局 侧栏位置: