• python基础-I/O


    一、文件读写:

      1.读文件

      2.二进制文件

      3.字符编码

      4.写文件

    二、操作文件和目录:

      1、环境变量

      2、操作文件和目录

    三、序列化

      1、pickle

      2、json

      3、json进阶

    ------------------------------------------------------------------------------------

    一、文件读写:

      磁盘上读写文件由操作系统提供,操作系统一般不允许程序直接操作磁盘,

      读写文件就是请求操作系统打开一个文件对象(文件描述符),通过文件描述符读/写数据.

      1、读文件:

        以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符:

    >>> f = open('/Users/michael/test.txt', 'r')

        文件不存在,open()会抛出IOError 

    >>> f=open('/Users/michael/notfound.txt', 'r')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IOError: [Errno 2] No such file or directory: '/Users/michael/notfound.txt'

        文件存在,调用read()一次读取文件的全部内容,读到内存,用一个str对象表示:

    >>> f.read()
    'Hello, world!'

         文件使用完毕后必须关闭,调用close(),因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也有限:

    >>> f.close()

        使用文件的过程中,可能会出现异常,那么就需要使用finally来关闭文件描述符:

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

        with语句可以自动帮我们调用close()方法:

    with open('/path/to/file', 'r') as f:    #和try ... finally是一样的
        print f.read()

        调用read()会一次性读取文件的全部内容,

        调用read(size)方法,每次最多读取size个字节的内容,

        调用readline()可以每次读取一行内容,

        调用readlines()一次读取所有内容并按行返回list

        因此,要根据需要决定怎么调用。例如:

    for line in f.readlines():
        print(line.strip()) # 把末尾的'
    '删掉

        参考:这里

      2、二进制文件:

        读取二进制文件,比如图片、视频等等,用'rb'模式打开文件:

    >>> f = open('/Users/michael/test.jpg', 'rb')
    >>> f.read()
    'xffxd8xffxe1x00x18Exifx00x00...' # 十六进制表示的字节

      3、字符编码

        读取非ASCII编码的文本文件,必须以二进制模式打开,再解码。比如GBK编码的文件:

    >>> f = open('/Users/michael/gbk.txt', 'rb')
    >>> u = f.read().decode('gbk')          #decode()解码,encode()编码.
    >>> u
    u'u6d4bu8bd5'
    >>> print u
    测试

        如果每次都这么手动转换编码嫌麻烦(写程序怕麻烦是好事,不怕麻烦就会写出又长又难懂又没法维护的代码),Python提供了一个codecs模块在读文件时自动转换编码,直接读出unicode:

    import codecs
    with codecs.open('/Users/michael/gbk.txt', 'r', 'gbk') as f:
        f.read() # u'u6d4bu8bd5'

      4、写文件:

        写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件:

    >>> f = open('/Users/michael/test.txt', 'w')
    >>> f.write('Hello, world!')
    >>> f.close()

        可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件。

        当写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。

        只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。

        忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。

        所以,还是用with语句来得保险:

    with open('/Users/michael/test.txt', 'w') as f:    #当然也可以指定编码来写入.
        f.write('Hello, world!')

    二、操作文件和目录:

        Python内置的os模块可以直接调用操作系统提供的接口函数:

    >>> import os
    >>> os.name # 操作系统名字
    'posix'

        posix,说明系统是LinuxUnixMac OS X;nt,就是Windows系统。

    >>> os.uname()    #获取详细信息
    ('Darwin', 'iMac.local', '13.3.0', 'Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64', 'x86_64')

        os模块的某些函数是跟操作系统相关,比如uname()函数在Windows上不提供.

      1、环境变量:操作系统中定义的环境变量,全部保存在os.environ这个dict中.

    >>> os.environ
    {'VERSIONER_PYTHON_PREFER_32_BIT': 'no', 'TERM_PROGRAM_VERSION': '326', 'LOGNAME': 'michael', 'USER': 'michael', 'PATH': '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin', ...}

        获取某个环境变量的值,调用os.getenv()

    >>> os.getenv('PATH')
    '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin'

      2、操作文件和目录:操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中

    # 查看当前目录的绝对路径:
    >>> os.path.abspath('.')
    '/Users/michael'
    # 在某个目录下创建一个新目录,
    # 首先把新目录的完整路径表示出来:
    >>> os.path.join('/Users/michael', 'testdir') #不要直接拼字符串,可以正确处理不同操作系统的路径分隔符
    '/Users/michael/testdir'
    # 然后创建一个目录:
    >>> os.mkdir('/Users/michael/testdir')
    # 删掉一个目录:
    >>> os.rmdir('/Users/michael/testdir')

        在Linux/Unix/Mac 和 windows下目录的分隔符是不一样的。分别为/-posix 和 -nt

        在拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:

    >>> os.path.split('/Users/michael/testdir/file.txt')
    ('/Users/michael/testdir', 'file.txt')

        os.path.splitext()可以直接让你得到文件扩展名,很多时候非常方便:

    >>> os.path.splitext('/path/to/file.txt')
    ('/path/to/file', '.txt')

        合并、拆分路径的函数并不要求目录和文件要真实存在,它们只对字符串进行操作。(比如从网络,文件中获取的路径,可以分析.)

        文件操作使用下面的函数。参考:这里;假定当前目录下有一个test.txt文件:

    # 对文件重命名:
    >>> os.rename('test.txt', 'test.py')
    # 删掉文件:
    >>> os.remove('test.py')

        shutil模块可以看做是os模块的补充,提供了很多os模块中没有功能,比如文件复制,就有copyfile()函数.

        利用os模块中的特性来过滤文件:

    #列出当前目录下的所有目录
    >>> [x for x in os.listdir('.') if os.path.isdir(x)]
    ['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Adlm', 'Applications', 'Desktop', ...]
    #列出所有的.py文件
    >>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
    ['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']

        os模块封装了操作系统的目录和文件操作,要注意这些函数有的在os模块中,有的在os.path模块中,详情参考:这里

        问题:编写一个search(s)的函数,能在 当前目录 以及当前目录的所有 子目录 下查找 文件名 包含 指定字符串 的文件,并打印出完整路径,例如:

    $ python search.py test
    unit_test.log
    py/test.py
    py/test_os.py
    my/logs/unit-test-result.txt

        解答:

    #!/usr/bin/python
    #coding:utf-8
    
    def listDictory(path):
        return [x for x in os.listdir(path) ]
    
    def searchStrInFile(s,path):
        dictory = listDictory(path)
        for x in dictory:
            xx = os.path.join(path,x)
            if os.path.isdir(xx):
                searchStrInFile(s,xx)
            elif s in x:
                print xx
    
    def search(str):
        searchStrInFile(str,".")
    
    if __name__ == '__main__':
        search("txt")

    三、序列化:

       变量从内存中变成可存储或传输的过程称之为序列化,Python中叫pickling,在其他语言中被称之为serializationmarshallingflattening等等

      变量序列化后,可以把内容写入磁盘,或者通过网络传输到别的机器上。

      反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling

      有两个模块可以实现序列化:cPickle和pickle.两个模块功能一样,区别是cPickle为C语言写的,速度较块,pickle为Python写的,速度慢,可以先尝试导入cPickle,导入失败再导入pickle.

    try:
        import cPickle as pickle
    except ImportError:
        import pickle

      尝试把一个对象序列化并写入文件:

    >>> d = dict(name='Bob', age=20, score=88)
    >>> pickle.dumps(d)
    "(dp0
    S'age'
    p1
    I20
    sS'score'
    p2
    I88
    sS'name'
    p3
    S'Bob'
    p4
    s."

      pickle.dumps()把任意对象序列化成str类型对象,可以把这个对象写入文件,传输网络,打印等等.

      或者直接使用pickle.dump()把对象写入一个文件对象:

    >>> f = open('dump.txt', 'wb')
    >>> pickle.dump(d, f)
    >>> f.close()

      反序列化在文件中的对象时,可以先读到一个str.然后用pickle.loads()载入内存.也可以直接用pickle.load()直接载入文件对象中的信息到内存:

    >>> f = open('dump.txt', 'rb')
    >>> d = pickle.load(f)
    >>> f.close()
    >>> d
    {'age': 20, 'score': 88, 'name': 'Bob'}

      Pickle只能用于python,并且可能不同的版本间还不兼容.

      2、JSON格式:

        JSON格式可以在不同的编程语言之间传递对象,并且比XML格式等更好,更快的序列化和传输.可以直接在web中读取.

        JSON表示的对象就是标准的JavaScript语言的对象.

    JSON类型 Python类型
    {} dict
    [] list
    "string" 'str'或u'unicode'
    1234.56 int或float
    true/false True/False
    null None

        

        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写入一个文件对象。

        JSON反序列化为Python对象,用loads()或者对应的load()方法. 参考:这里

    >>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
    >>> json.loads(json_str)
    {u'age': 20, u'score': 88, u'name': u'Bob'}

      反序列化得到的字符串对象默认都是unicode而不是str。JSON标准规定JSON编码是UTF-8,所以总是能正确地在Python的strunicode与JSON的字符串之间转换。

      3、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 0x10aabef50> is not JSON serializable

        原因是Student对象不是一个可序列化为JSON的对象,,参考:这里

        可选参数default就是把任意一个对象变成一个可序列为JSON的对象,只需要为Student专门写一个转换函数,再把函数传进去即可:

    def student2dict(std):  #Student实例首先被student2dict()函数转换成dict,然后再被顺利序列化为JSON
        return {
            'name': std.name,
            'age': std.age,
            'score': std.score
        }
    
    print(json.dumps(s, default=student2dict))

        不过,下次遇到一个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>  #结果为一个实例在内存中.
  • 相关阅读:
    信息安全系统设计基础第八周期中复习总结
    layui下各种富文本的冲突情况
    TP3.2+find_set_in 以及 find_set_in和like的区别
    tp5+linux+apache php7.1.30环境下,上传图片报错:mkdir():permission denied
    一次基于老古董thinkPHP3.1的修改尝试
    微信网页开发 thinkphp5.0的try-catch和重定向
    CentOS 7.2下服务器配置(linux+apache+php+mysql)
    微信小程序踩坑(不定时更新)
    PHP 定时自动执行代码
    PHP TP5 文章评论+积分+签到
  • 原文地址:https://www.cnblogs.com/xccnblogs/p/4924098.html
Copyright © 2020-2023  润新知