1. 系统库函数提供的基本文件IO

1.1 读取键盘/打印到终端 (标准化流设备)raw input() and input()

print()
demo code
# raw input(), 从标准输入读取一个行,并返回一个字符串(去掉结尾的换行符)
str = raw_input("请输入:")
print(str)
# input(), 和 raw_input([prompt]) 函数基本类似,但是 input 可以接收一个Python表达式作为输入,并将运算结果返回
str = input("请输入:") # 比如输入 [x*5 for x in range(2,10,2)]
print(str) # 比如返回 [10, 20, 30, 40]
# print(),没啥好说的,输出一个 string 到终端屏幕

1.2 文件操作-python内置的File对象 (属性->方法->实践)

主要是用于将字符串写入txt, 用到的file对象的最常见的属性如下:file.closed返回true如果文件已被关闭,否则返回false。

file.mode返回被打开文件的访问模式。

file.name返回文件的名称。

## 文件访问模式mode 如下

# 文件类型

't': 文本模式(默认)

'b': 二进制模式

# 读写模式

r: 只读

rb: 只读,二进制

r+: 读写, 文件不存在会报错

rb+: 读写, 文件不存在会报错

w: 覆盖写, 文件不存在会创建

wb: w的二进制版本

w+: 和w一致

wb+: 和wb一致

a: 追加写,如果文件不存在则创建

a+: 和a一致

ab+: a+的二进制版本file对象的方法 (本质一定是 增删改查以及它们的支持函数)open(), close(), read(), write()

demo code

# read(), 方法从一个打开的文件中读取一个字符串。需要重点注意的是,Python字符串可以是二进制数据

with open(file_path) as f:
f.read(count) # count是要从已打开文件中读取的字节计数。该方法从文件的开头开始读入,
# 如果没有传入count,它会尝试一次性读完整个文件,很可能内存溢出。
f.readline() # 读一行
f.write(string) #

# 默认是文件开头开始读入或者文件结束处开始操作

# tell(), 告诉你文件内的当前位置, 换句话说,下一次的读写会发生在文件开头这么多字节之后。

# seek(offset [,from])方法改变当前文件的位置。offset变量表示要移动的字节数。From变量指定开始移动字节的参考位置。

# 如果from被设为0,这意味着将文件的开头作为移动字节的参考位置。如果设为1,则使用当前的位置作为参考位置。如果它被设为2,那么该文件的末尾将作为参考位置。

position = fo.tell()
position = fo.seek(0, 0) # 把指针再次重新定位到文件开头
str = fo.read(10)

1.3 File-like 对象

python中主要具备 open() 并非返回具有 read() 的对象,都称为 file-like object. 比如 内存的字节流,网络流,自定义流; StringIO就是在内存中创建的file-like object,常用作临时缓冲 (但似乎相比读写磁盘文件,内存文件读写并不能加速,见[2], [3] )StringIO: 内存中读写str

BytesIO: 内存中读写二进制

# StringIO
from io import StringIO
with StringIO() as f:
f.write('Hello!\nHi!\nGoodbye!') # 写了3行, \n 换行
#
while True:
s = f.readline()
if s == '':
break
print(s.strip())
# Hello!
# Hi!
# nGoodbye!
# ------------------------------------------------------------- #
# BytesIO
from io import BytesIO
with BytesIO() as f:
f.write('中文'.encode('utf-8')) # 写入的不是str,而是经过UTF-8编码的bytes
with BytesIO() as f:
f.getvalue() # b'\xe4\xb8\xad\xe6\x96\x87'
f.read() # b'\xe4\xb8\xad\xe6\x96\x87'

1.4 对比几类流式接口及IO类型

#IO模块

IOBase

-RawIOBase,无缓存的字节流

-+FileIO,操作系统文件流

-BufferedIOBase,缓存的字节流

-+BytesIO

-+BufferedReader

-+BufferedWriter

-+BufferedRandom

-+BufferedRWPair

-TextIOBase,编码相关的文本流

-+StringIO,文本的内存流

-+TextIOWrapper

# --------------------------------------------------------------------------------- #

# (1) 文本I/O,即TextIOBase及其子类

# 读取一个str对象,得到一个str对象。有两种方式,官方没有说性能差异,默认没啥本质区别

f = open("myfile.txt", "r", encoding="utf-8") # 必须创建磁盘文件
f = io.StringIO("some initial text data") # 可以不创建磁盘文件

# (2) 字节I/O,即BufferedIOBase及其子类, 也称为缓存I/O。

# 读取一个bytes-like对象,得到一个bytes对象。有两种方式

f = open("myfile.jpg", "rb")

f = io.BytesIO(b"some initial binary data: \x00\x01")

# 综上,之前讨论的两种IO本质只是 是否创建磁盘文件的区别,本质没有太大差异

2. 复杂对象文件读写

2.1 个人用过的汇总pickle

json

hdf5

lmdb

2.2 pickle

注意哪些最佳实践?坑?注意用最高版本的 cpickle, 又快又好,注意 api中协议选择最快速的读写

# (1) demo code-1: 简单读写一个python对象

# (2) demo code-2:向一个文件中一次性写入和读取多个python对象

# (3) 完整的 github link: xxx

2.2 json

2.3 hdf5

2.4 lmdb

2.5 速度评测【注】非思考型,纯查api型的知识,一定要总结为: template, 方便下次直接调用,提高编码效率,避免重复搜, 搜这些没有思考型的资料,真的是体力活

3. 常见的文件/目录操作

3.1 最常用库overview (具体用, 还是要总结一个 code repo, 不用反复查api)os/os.path

shutil

pathlib

glob

3.2 os/os.path库

# 注意: 这些合并、拆分路径的函数并不要求目录和文件要真实存在,它们只对字符串进行操作。

# (1) 路径合成

os.path.join('/Users/michael', 'testdir')

# (2) 路径拆分, 把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名

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')

# (3) 重命名和删除文件

import os
os.rename( "test1.txt", "test2.txt" ) # 重命名文件test1.txt到test2.txt
os.remove("test2.txt") # 删除一个已经存在的文件test2.txt

# (4) 目录处理-增删改

os.mkdir("newdir") # 在当前目录下创建一个新目录test
os.makedirs("/the/path/to/newdir") # 递归地创建给定路径下的dirs以及中间的dirs
os.chdir("/home/newdir") # 将 当前工作目录 改为"/home/newdir"
os.getcwd() # 当前工作目录
os.rmdir('dirname') # 在删除这个目录之前,它的所有内容应该先被清除。
os.rmdir( "/tmp/test" ) # 删除“/tmp/test”目录

# (5) 列出文件

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

# 看来有必要总结一份常用os下面的api code 清单做成 repo, 方便自己反复copy-and-paste

3.3 shutil库

# 文件复制

copyfile()

# ...

3.4 pathlib

3.5 glob库

4. 一些特殊需求

4.1 读取非常大的文件基于buffer机制,不是一次性全部读完整个文件,而是每次只读一行

在python中一定要用 with 语句,使用系统自带的 缓冲IO(buffered IO)以及内存管理

简列两个 demo code

# 一种简单的写法 (系统自带的 缓冲IO(buffered IO)以及内存管理)

with open(filename, 'rb') as f:
for line in f:
# --------------------------------------------------------- #
# 自定义buffer, 以协程方式读取
def readInChunks(fileObj, chunkSize=4096):
"""Lazy function to read a file piece by piece.Default chunk size: 4kB."""
while 1:
data = fileObj.read(chunkSize)
if not data:
break
yield data
f = open('bigFile')
for chuck in readInChunks(f):
#do_something(chunk)
f.close()

4.2 xxxx

4.3

X. 参考