Python基础——I/O

1. 读、写文件:
open()将会返回一个file对象,基本语法格式如下:
open(filename, mode):filename —> 包含了你要访问的文件名称的字符串值    mode:决定了打开文件的模式,默认只读

mode描述
r 以只读方式打开文件,文件的指针将会放在文件的开头
rb以二进制格式打开一个文件用于只读,文件的指针将会放在文件的开头
r+打开一个文件用于读写,文件的指针将会放在文件的开头
rb+以二进制格式打开一个文件用于读写,文件的指针将会放在文件的开头
w打开一个文件只用于写入,如果该文件已存在则将其覆盖;如果文件不存在则创建新文件
wb以二进制格式打开一个文件只用于写入,如果文件已存在则将其覆盖;如果文件不存在则创建新文件
w+打开一个文件用于读写,如果该文件已存在则将其覆盖;如果文件不存在则创建新文件
wb+以二进制格式打开一个文件用于读写,如果该文件已存在则将其覆盖;如果文件不存在则创建新文件
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的末尾;如果文件不存在则创建新文件进行写入
ab以二进制格式打开一个文件用于追加。
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的末尾,文件打开时是追加模式;如果文件不存在则创建新文件
ab+

以二进制格式打开一个文件用于追加。

2. 文件对象的方法
· f.read():为了读取一个文件的内容,调用f.read(size),这将读取一定数目的数据,然后作为字符串或字节对象返回。size是一个可选的数字类型的参数,当size被忽略了或者为负,那么该文件所有的内容都将被读取并且返回
· f.readline():从文件中读取单独的一行。换行符为'\n',f.readline()如果返回一个空字符串,说明已经读到最后一行
· f.readlines():返回文件中包含的所有行。如果设置可选参数sizeint,则读取指定长度的字节,并且将这些字节按行分割
· f.write(string):将string写入到文件中,然后返回写入的字符数
· f.tell():返回文件对象当前所处的位置,它是从文件开头开始算起的字节数
· f.seek(offset, from_what):from_what的值:0表示开头,1表示当前位置,2表示文件的末尾。默认值为0
    seek(x, 0):从起始位置即文件首行首字符开始移动x个字符
    seek(x, 1):表示从当前位置往后移动x个字符
    seek(-x, 2):表示从文件结尾往前移动x个字符
· f.close():在文本文件中(那些打开文件模式没有b的),只会相对于文件起始位置进行定位。当你处理完一个文件后,调用f.close()来关闭文件并释放系统资源,如果尝试再调用该文件,则会抛出异常
当处理一个文件对象时,使用with关键字是非常好的方式,在结束后他会帮你正确关闭文件:

with open('input_ouput.txt') as f:  
    f.seek(16)  
    read_data = f.read(12)  
    print(read_data)  
# he loves cat 

迭代一个文件对象然后读取每行:

f =  open('input_ouput.txt')  
for line in f:  
    print(line, end='')  
# she loves cat.  
# he loves cat, too.  
# she also loves dog.  
# he love her.  
# he says he loves her whatever happens.

file.readlines([sizeint]):读取所有行并返回列表(可以测试一下不同sizeint的值,'\n'不计入sizeint)

with open('input_ouput.txt') as f:  
    f.readlines(1)  
# ['she loves cat.\n']  
with open('input_ouput.txt') as f:  
    f.readlines(15)  
# ['she loves cat.\n', 'he loves cat, too.\n']  
with open('input_ouput.txt') as f:  
    f.readlines(14)  
# ['she loves cat.\n']  

3. StringIO

很多时候,数据读写不一定是文件,也可以在内存中读写。

StringIO就是在内存中读写str:

>>> from io import StringIO
>>> sio = StringIO()
>>> sio.write('hello')
5
>>> sio.write(' ')
1
>>> sio.write('drq')
3
>>> sio.getvalue()    # 获取写入后的str
'hello drq'

4. 操作文件和目录

操作系统提供的命令只是简单地调用了操作系统提供的接口函数,Python内置的os模块也可以直接调用操作系统提供的接口函数。

>>> import os
>>> os.name
'nt'    # 如果是posix,说明系统是Linux、Unix或Mac OS X;如果是nt,就是Windows系统

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

获取某个环境变量的值:os.environ.get('key')

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

import os, os.path

# 查看当前目录的绝对路径
print('当前目录的绝对路径:', os.path.abspath('.'))
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来
os.path.join('.', 'newdir')
# 然后创建一个目录
os.mkdir('newdir')
print('新目录的绝对路径:', os.path.abspath('newdir'))
# 删掉一个目录
os.rmdir('newdir')
把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符。在Linux/Unix/Mac下,os.path.join()返回这样的字符串:part-1/part-2。而Windows下会返回这样的字符串:part-1\part-2。同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:
print(os.path.split('newdir\\test.txt'))
# ('newdir', 'test.txt')

获得文件扩展名:

print(os.path.splitext('newdir\\test.txt'))
# ('newdir\\test', '.txt')

对文件重命名和删除文件:

# 对文件重命名
os.rename('newdir\\test.txt', 'newdir\\test.py')
# 删除文件
os.remove('newdir\\test.py')

shutil模块提供了copyfile()的函数,你还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充。

# 列出当前目录下的所有目录
print([x for x in os.listdir('.') if os.path.isdir(x)])
# 列出当前目录下所有的'.py'文件
print([x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] == '.py'])

5. 序列化和反序列化

通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储

通过pickle模块的反序列化操作我们能够从文件中创建上一次程序保存的对象

>>> import pickle
# 序列化
>>> d = dict(name='yxh', age='20', favor='sdy')
>>> pickle.dumps(d)    # pickle.dumps()方法把任意对象序列化成一个bytes,然后,就可以把这个bytes写入文件。或者用另一个方法pickle.dump()直接把对象序列化后写入一个file-like Object
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00yxhq\x02X\x03\x00\x00\x00ageq\x03X\x02\x00\x00\x0020q\x04X\x05\x00\x00\x00favorq\x05X\x03\x00\x00\x00sdyq\x06u.'
>>> f = open('info.txt', 'wb')
>>> pickle.dump(d, f)
>>> f.close()
# 反序列化
>>> f = open('info.txt', 'rb')
>>> d = pickle.load(f)
>>> f.close()
>>> d
{'name': 'yxh', 'age': '20', 'favor': 'sdy'}

6. JSON

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

JSONPython
{}dict
[]list
"string"str
123.456int or float
true/falseTrue/False
nullNone

Python内置的json模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON:

>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)    # dumps()方法返回一个str,内容就是标准的JSON。类似的,dump()方法可以直接把JSON写入一个file-like Object。
'{"age": 20, "score": 88, "name": "Bob"}'

要把JSON反序列化为Python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化:

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

由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的str与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 0x10603cc50> is not JSON serializable
# 错误的原因是Student对象不是一个可序列化为JSON的对象。

看看dumps()方法的参数列表,可以发现,除了第一个必须的obj参数外,dumps()方法还提供了一大堆的可选参数。这些可选参数就是让我们来定制JSON序列化。前面的代码之所以无法把Student类实例序列化为JSON,是因为默认情况下,dumps()方法不知道如何将Student实例变为一个JSON的{}对象。可选参数default就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为Student专门写一个转换函数,再把函数传进去即可:

def student2dict(std):
    return {
        'name': std.name,
        'age': std.age,
        'score': std.score
    }

这样,Student实例首先被student2dict()函数转换成dict,然后再被顺利序列化为JSON:

>>> print(json.dumps(s, default=student2dict))
{"age": 20, "name": "Bob", "score": 88}

不过,下次如果遇到一个Teacher类的实例,照样无法序列化为JSON。我们可以偷个懒,把任意class的实例变为dict:

print(json.dumps(s, default=lambda obj: obj.__dict__))

同样的道理,如果我们要把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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值