• 中文
    • 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
    • 1.1k
    • 你又不囍赵睿宇ibigshot

      请登录之后再进行评论

      登录
    • 1
      55555
    • 0
      1
    • 赞助本站

      • 支付宝
      • 微信
      • QQ

      感谢一直支持本站的所有人!

      单栏布局 侧栏位置: