真锋
永远保持一颗学习和专注的心
嵌入式视觉笔记

Python3 IO编程

Python IO编程值得是经常涉及到文件处理和操作得各种方法得应用,本文是学习笔记,主要参考廖雪峰《Python3教程》和部分网络学习资源。

IO 在计算机中指 Input/Output,也就是输入和输出。由于程序和运行时数据是在内存中驻留,由 CPU 这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘、网络等,就需要 IO 接口。
IO 编程简单理解指的是你的程序涉及到 cpu、内存和磁盘、网络的数据交互。因为 cpu、内存和磁盘、网络的速度有差异,所以在 IO 编程中,就存在速度严重不匹配的问题,比如网络爬虫的实例,网页解析可能只要 0.001秒,但是下载网页可能要 0.1s,为解决速度不匹配的问题,可以使用异步 IO,使用异步 IO 来编写程序性能会远远高于同步 IO,但是异步 IO的缺点是编程模型复杂
操作 IO 的能力都是由操作系统提供的,每一种编程语言都会把操作系统提供的低级 C 接口封装起来方便使用, Python 也不例外。

文件读写

文件读写是最常见的 IO 操作。 Python 内置了读写文件的函数,用法和C 是兼容的。读写文件前,我们清楚,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。(来源,《Python3教程》-廖雪峰)

读文件

(来源见这里)

Python 读取文件的一般“标准做法“是,首先使用 with open(fine_name) 上下文管理器的方式打开一个文件并获得文件对象,然后使用 for 循环迭代它,逐行获取文件里的内容,如果该文件无法被打开,会抛出 OSError。用法示例如下:

  try:
    with open(demo.txt, 'r') as f:
      lines = f.readlines()
      for idx ,line in enumerate(lines):
          print(line)  # 循环打印demo.txt的每一行内容
  except Exception as e:
    print(e)
    print(traceback.print_exc())

file 对象使用 open 函数创建,file 对象的常用函数如下:

  • file.readline() 可以每次读取一行内容,包括 “\n” 字符(f 指的是文件对象)。
  • file.readlines() 一次读取所有内容并按行返回 list,行字符串末尾也包含了换行符 “\n”,可用 strip(“\n”) 方法去除。
  • file.read(chunk_size) 返回从当前位置往后读取 chunk_size 大小的文件内容 。
  • file.read() 可以一次读取文件的全部内容到内存中,用一个 str 对象表示。

调用 read() 会一次性读取文件的全部内容,如果文件有 10G,内存就爆了,所以,要保险起见,可以反复调用 read(size) 方法,每次最多读取 size 个字节的内容。另外,调用 readline() 可以每次读取一行内容,调用 readlines() 一次读取所有内容并按行返回 list,因此,要根据需要决定怎么调用。

如果文件很小, read() 一次性读取最方便;如果不能确定文件大小,反复调用 read(size) 比较保险;如果是配置文件,调用 readlines()最方便。

file-like Object

像 open() 函数返回的这种有个 read() 方法的对象,在 Python 中统称为 file-like Object。除了 file 外,还可以是内存的字节流,网络流,自定义流等等。file-like Object 不要求从特定类继承,只要写个 read() 方法就行。

写文件

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

代码示例如下:

with open(txt_fpath, 'w') as f:
    # start write str sequence
      f2.writelines(line2s)
  • f.write(str):将字符串写入文件,返回的是写入的字符长度。
  • f.writelines(sequence):向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。

总结

open() 函数完整的语法格式如下:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

在 Python 中,文件的读写都是通过 open() 方法实现的,区别在于 mode 参数不同。在 Python 中,文件的读写都是通过 open() 方法实现的,区别在于 mode 参数不同;使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。

操作文件和目录

在 Python 中,操作文件和目录的函数一部分放在 os 模块中,一部分放在 os.path 中。os 模块是操作系统接口模块,该模块提供了一些方便使用操作系统相关功能的函数。 如果想读写一个文件,请参阅 open() 函数,如果你想操作路径,请参阅 os.path 模块,如果你想在命令行上读取所有文件中的所有行请参阅 fileinput 模块。 有关创建临时文件和目录的方法,请参阅 tempfile 模块,对于高级文件目录处理,请参阅 shutil 模块。

os.path 模块常用函数

os.path 模块主要用于获取文件的属性,os.path 模块的函数都仅接受(Unicode)字节或字符串对象(路径)作为其参数。如果返回路径或文件名,则结果是相同类型的对象。os.path 模块的几种常用函数如下,这些函数的灵活应用需要自己在涉及操作文件/目录中的实例中灵活应用和总结。

  • os.getcwd() 返回当前工作目录
  • os.path.realpath(path) 返回 path 的真实路径
  • os.path.abspath(path) 返回 path 的绝对路径
    • os.path.abspath(os.path.join(os.getcwd(), "..")) 返回当前目录的上一级目录的绝对路径
    • os.path.abspath(os.path.join(os.getcwd(), "../../")) 返回当前目录的上上级目录的绝对路径
  • os.path.basename(path) 返回文件名
  • os.path.splitext(filename) 返回文件路径和文件后缀分割后的字符串元组

实例代码如下:

import os
print(os.getcwd().replace('\\\\', '/'))
print(os.listdir('./'))  # 列出当前目录下的所有子目录和文件名
os.path.abspath('./opencv_demo.py')
print(os.path.realpath('./').replace('\\', '/'))
print(os.path.abspath('../').replace('\\', '/'))
# 当path存在软链接时,两者有所区别,其他时候无区别
# os.path.realpath 会返回指定文件的标准路径,而非软链接所在的路径

程序输出如下:

C:/Users/zhanghonggao/Documents/image_utils/tools
[‘.ipynb_checkpoints’, ‘crawl_images.py’, ‘daily_experiment.py’, ‘demo-image-classification-fastai’, ‘image_process.ipynb’, ‘input_nums.py’, ‘opencv_demo.py’, ‘pyqt5_demo.py’, ‘python3_practice.py’]
C:/Users/zhanghonggao/Documents/image_utils/tools
C:/Users/zhanghonggao/Documents/image_utils

os.path.exists() 和 os.path.isdir()、os.path.isfile() 等函数

  • os.path.exists(path) 方法可以直接判断文件/文件夹是否存在,功能相当于 os.path.isdir()、os.path.isfile() 的集合
  • os.path.isfile(path) 判断指定对象是否为文件。是返回 True,否则 False。
  • os.path.isdir(path) 判断指定对象是否为目录(文件夹)。是返回 True,否则 False。
  • os.path.islink(path) 判断路径是否为链接

os.path.basename 和 os.path.dirname 函数

  • os.path.basename(path)去掉目录路径,返回文件名
  • os.path.dirname(path)去掉文件名,返回目录路径

os.path.split() 和 os.path.splitext() 函数

  • os.path.split(path)返回( dirname(), basename())元组,basename是文件名(basename)
  • os.path.splitext(path)返回 (filename, extension) 元组,extension是文件后缀

os.path.getmtime() 和 os.path.getctime() 函数

  • os.path.getmtime(path) 返回最近文件修改时间
  • os.path.getctime(path) 返回 path 创建时间(windows系统),返回值是一个数,为纪元秒数(参考 time 模块)。如果该文件不存在或不可访问,则抛出 OSError 异常。

os.mkdir 和 os.makedirs 函数

path = '/test/path_01/path_02/path03/'
  • os.mkdir 函数只会创建 path 路径的最后一级目录
  • os.makedirs 函数递归地创建多层目录,如果 path 的四级目录都没有,则会自动递归创建全部 test、path_01、path_02、path_03 这 4 个目录

os.walk() 和 os.path.getsize() 函数

  • os.path.getsize(path) 返回文件大小,如果文件不存在就返回错误
  • os.walk(top, topdown=True, onerror=None, followlinks=False) 创建一个生成器,用以生成所要查找的目录及其子目录下的所有文件。

os.walk 函数可以得到一个三元tupple(dirpath, dirnames, filenames) generator,可 for 循环遍历这个 generaor,得到所有目录(包括子目录)的三元 tupletuple 第一个元素为起始路径,第二个为起始路径下的文件夹,第三个是起始路径下的文件。

  • dirpath 是一个 string,代表目录的路径。(文件夹路径)
  • dirnames 是一个 list,包含了 dirpath 下所有子目录的名字。(文件夹名字)
  • filenames 是一个 list,包含了非目录文件的名字。(文件名)

os.walk(root_dir) 先遍历 root_dir 目录下的第一个子目录,再依次遍历第二、第三、第 n 个目录,每遍历一个子目录都得到一个 generator。实例代码: python 获取文件夹大小。

"""python 获取指定文件夹大小"""
import os
f_dir = os.path.abspath(os.path.dirname(__file__))
def get_dir_size(dir):
    size = 0
    for root, dirs, files in os.walk(dir):
        size += sum([os.path.getsize(os.path.join(root, name)) for name in files])
    return size
if __name__ == '__main__':
    size = get_dir_size('../')
    print('Total size is: %.3f Mb'%(size/1024/1024))

序列化

我们把变量从内存中变成可存储或传输的过程称之为序列化,在 Python中叫 pickling,在其他语言中也被称之为 serialization, marshalling,flattening 等等,都是一个意思。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即 unpickling。 
Python中提供了pickle模块实现对象的序列化,常用方法如下:

  • pickle.dumps()方法把任意对象序列化成一个 bytes,然后,就可以把这个 bytes 写入文件
  • pickle.dump()方法直接把对象序列化后写入一个 file-like Object
  • pickle.loads()方法用于从bytes中反序列化出对象
  • pickle.load()方法从一个 file-like Object 中直接反序列化出对象,

**这些方法的应用,建议到实际工程代码中去练习,才能理解和灵活应用**。实例代码如下:

import pickle
d = dict(name='Bob', age=20, score=88)
with open('demo.txt', 'wb') as f:
    pickle.dump(d, f)
with open('demo.txt', 'rb') as f:
    d = pickle.load(f)
print(d)

程序输出如下:

{‘name’: ‘Bob’, ‘age’: 20, ‘score’: 88}

Json

  • json.loads()、 json.dumps()函数适用于json格式的字符串对象
  • json.load()、json.dump()函数适用于json文件,

dumps()方法返回一个 str,内容就是标准的 JSON。类似的, dump()方法可以直接把 JSON 写入一个 file-like Object。 
要把 JSON 反序列化为 Python 对象,用 loads()或者对应的 load()方法,前者把 JSON 的字符串反序列化,后者从 file-like Object 中读取字符串并反序列化

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

总结

Python官方的对象序列化模块是pickle,实际工程中发现使用pickle文件反序列化出对象速度更快,但如果要把序列化搞得更通用、更符合 Web 标准,建议使用 json 模块。

参考资料

《Python教程-廖雪峰》
Python 工匠:高效操作文件的三个建议

赞赏

发表评论

textsms
account_circle
email

嵌入式视觉笔记

Python3 IO编程
Python IO编程值得是经常涉及到文件处理和操作得各种方法得应用,本文是学习笔记,主要参考廖雪峰《Python3教程》和部分网络学习资源。 IO 在计算机中指 Input/Output,也就是输…
扫描二维码继续阅读
2019-07-10