Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.3 IO 编程 #12

Open
ShannonChenCHN opened this issue Jul 16, 2018 · 4 comments
Open

4.3 IO 编程 #12

ShannonChenCHN opened this issue Jul 16, 2018 · 4 comments

Comments

@ShannonChenCHN
Copy link
Owner

ShannonChenCHN commented Jul 16, 2018

  • 文件读写
  • StringIO和BytesIO
  • 操作文件和目录
  • 序列化

参考

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 16, 2018

文件读写

在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。

  • 文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的。
  • 由于文件读写时都有可能产生 IOError,一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来实现。
try:
    f = open('/path/to/file', 'r')
    print(f.read())
finally:
    if f:
        f.close()

每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:

with open('/path/to/file', 'r') as f:
    print(f.read())

几个常用方法:

  • read()
  • read(size)
  • readline()
  • readlines()

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

跟读文件一样,你可以反复调用write() 来写入文件,但是务必要调用 f.close() 来关闭文件,否则有可能导致没有把要保存的数据全部写入文件。

try:
    f = open('/Users/michael/test.txt', 'w')
    f.write('Hello, world!')
finally:
    if f:
        f.close()

写文件时也可以使用更保险、更简洁的 with 语句:

with open('/Users/michael/test.txt', 'w') as f:
    f.write('Hello, world!')

'w' 模式写入文件时,如果文件已存在,会直接覆盖(相当于删掉后新写入一个文件)。如果我们希望追加到文件末尾,可以传入'a'以追加(append)模式写入。

file-like Object

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

StringIO 就是在内存中创建的 file-like Object,常用作临时缓冲。

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 16, 2018

StringIO 和 BytesIO

在内存中读写 str 时,用 StringIO。
在内存中读写 bytes 时,用 BytesIO。

示例

读写 str:

from io import StringIO

f = StringIO()
f.write('hello\n')
f.write('Hi!\n')
f.write('world!')
print(f.getvalue())

读写 bytes:

from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue())

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 16, 2018

操作文件和目录

如果我们要操作文件、目录,可以在命令行下面输入操作系统提供的各种命令来完成。比如dir、cp等命令。

如果要在Python程序中执行这些目录和文件的操作怎么办?其实操作系统提供的命令只是简单地调用了操作系统提供的接口函数,Python内置的os模块也可以直接调用操作系统提供的接口函数。

1. os 模块

查看操作系统相关信息:

print(os.name)
print(os.uname())

查看环境变量:

# 查看当前目录的绝对路径
abspath = os.path.abspath('.')
print(abspath)

2. 操作文件和目录

2.1 查看、创建、删除、重命名目录

注:把两个路径合成一个时,不要直接拼字符串,而要通过 os.path.join() 函数,这样可以正确处理不同操作系统的路径分隔符。

# 查看当前目录的绝对路径
abspath = os.path.abspath('.')
print(abspath)

# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来
# 这里不能用 home dir 的符号 ~
joinedpath = os.path.join(abspath, 'testdir')
print(joinedpath)

# 用户目录
homedir = os.path.expanduser('~')
print(homedir)

# 判断目录是否存在
if os.path.exists(joinedpath):
    os.rmdir(joinedpath) # 删掉一个目录

# 创建一个目录
os.mkdir(joinedpath)

# 重命
newpath = joinedpath + 'new'
os.rename(joinedpath, newpath)

# 删掉一个目录
os.rmdir(newpath)

# 拆分路径
print(os.path.split('/Users/michael/testdir/file.txt'))

# 扩展名
print(os.path.splitext('/path/to/file.txt'))

2.2 读取、创建、删除、重命名、复制文件

注:

  • 文件的读取和创建见文件读写部分。
  • os模块没有提供文件复制的功能,不过 shutil 模块提供了 copyfile() 的函数可供复制。
# 复制
import  shutil
licensepath = '../../LICENSE'
copypath = licensepath + 'new'
shutil.copy(licensepath, copypath)

# 删除
os.remove(copypath)

2.3 查看当前目录下的文件列表

# 查看当前目录下的文件列表

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

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

参考

@ShannonChenCHN ShannonChenCHN changed the title IO 编程 4.3 IO 编程 Jul 16, 2018
@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 17, 2018

序列化

序列化(pickling),又叫 serialization,是指把变量从内存中变成可存储或传输的数据的过程。
反过来,把序列化的数据重新转成内存里的变量内容称之为反序列化(unpickling)

序列化成 bytes

Python提供了pickle模块来实现序列化。

import pickle, os

# 序列化
d = dict(name='Bob', age=20, score=88)
print(pickle.dumps(d))

# 写入文件
filepath = 'dump.txt'
f = open(filepath, 'wb')
pickle.dump(d, f)
f.close()

# 读取文件,反序列化
readfile = open(filepath, 'rb')
d = pickle.load(readfile)
print(d)
readfile.close()

os.remove(filepath)

序列化成 JSON

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON(JavaScript Object Notation),因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

JSON标准规定JSON编码是UTF-8。

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

JSON类型 Python类型
{} dict
[] list
"string" str
1234.56 int或float
true/false True/False
null None
# 序列化
print(json.dumps(d))

# 反序列化
json_str = '{"name": "Bob", "age": 20, "score": 88}'
result_dict = json.loads(json_str)
print(result_dict)

自定义 class 类型的 JSON 序列化

本质:JSON 的序列化本质上是 JSON 字符串与 Python dict 之间的相互转换。

import json

class Student(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

s = Student('Bob', 21, 89)
print(json.dumps(s, default=lambda obj: obj.__dict__)) 


def dict2student(d):
    return Student(d['name'], d['age'], d['score'])
print(json.loads(json_str, object_hook=dict2student))

注:定义了 __slot__ 方法的 class 是拿不到 __dict__属性的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant