Learn Python 3:IO操作

一、读文件

1、读取整个文件

准备好一个非空的txt文件

# 通过绝对路径读取文件
>>> with open(r'C:\Users\dell\Desktop\io\zen.txt') as f:
...     print(f.read())
... 
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
>>>
# 通过相对路径读取文件
>>> with open(r'io\zen.txt') as f:
...     print(f.read())
...
# 通过文件名读取
>>> with open('zen.txt') as f:
...     print(f.read())
...

LinuxMac OS中,文件路径中使用斜杠(/),在Windows中,文件路径中使用反斜杠(\),但是为了防止反斜杠和后边跟的字母发生转义,建议在路径前加 r 符号或者使用双反斜杠(\\

使用绝对路径读取文件,Python将在指定的绝对路径查找文件。

使用相对路径读取文件,Python将在当前执行的文件
(即.py程序文件)所在目录的子目录中查找文件。

使用文件名读取文件,Python将在当前执行的文件
(即.py程序文件)所在目录中查找文件。

使用with语句打开文件,在文件不需要访问后会自动将其关闭。

由于read()方法会一次读取文件全部内容,如果文件太大,可能导致内存不够用,为此可以使用read(size)方法,每次最多读取size个字节的内容。

2、逐行读取
>>> with open('zen.txt') as f:
...     for line in f:
...         print(line)
...
Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

因为在这个文件中,每行的末尾都有一个看不见的换行符,而print语句也会加上一个换行符,因此每行末尾都有两个换行符,可以通过rstrip()方法去掉多余换行符。

print(line.rstrip())

每次读取一行文件:

>>> with open('zen.txt') as f:
...     print(f.readline().rstrip())
...     print(f.readline().rstrip())
...
Beautiful is better than ugly.
Explicit is better than implicit.

读取所有行:

>>> with open('zen.txt') as f:
...     for line in f.readlines():
...         print(line.rstrip())

readlines()方法会一次读取所有文件内容并按行返回一个list

3、字符编码

如果要读取指定编码格式的文件,给open()方法设置encoding参数,例如读取GBK编码的文件:

>>> with open('test.txt', 'r', encoding='GBK') as f:
...     print(f.read())
...
中国

如果在文本有一些非法编码的字符,可能出现UnicodeDecodeError错误,可给open()方法再设置一个errors参数,表示遇到错误后如何处理,常见参数值有如下几个可选:

  • ignore:忽略错误
  • strict:编码出错则抛出异常ValueError
  • replace:使用指定字符替代出错的字符
4、读取二进制文件

除了文本文件,还可以读取二进制文件,比如图片:

>>> with open(r'io\launcher.png', 'rb') as f:
...     print(f.read())
...
b'\x89PNG\r\n\x1a\n\x00\x00\x00......'

注意指定rb 打开模式

二、写文件

>>> with open(r'io\test.txt', 'w') as f:
...     print(f.write('Hello World'))
...
11

可以看到通过write()来写入文本,并返回了文本长度。这样在test.txt文件中写入了字符串Hello World

  • 如果要指定写入文本的编码格式,可给open()函数设置encoding参数,将文本自动转换成指定编码。

  • 打开文件时,可指定读取模式:r、 写入模式:w、 附加模式:a(如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件)、或能够读取和写入文件的模式:r+:。如果你省略了模式Python将以默认的只读模式打开文件。

  • 如果要写入的文件不存在,函数open()将自动创建它。如果以写入(w)模式打开文件时需要注意,若指定的文件已经存在, Python将在返回文件对象前清空该文件。

  • Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。

三、StringIO

StringIO可以是在内存中读写str

通过write()方法写入str,通过getvalue()获得写入的str

>>> from io import StringIO
>>> si = StringIO()
>>> si.write('Hello World')
11
>>> print(si.getvalue())
Hello World
>>> 

直接使用str初始化一个StringIO,类似读文件一样获得写入的str:

>>> from io import StringIO
>>> si = StringIO('Hello World')
>>> print(si.readline())
Hello World
>>>

四、BytesIO

BytesIO可以在内存中读写二进制数据(bytes

用法和StringIO类似:

>>> from io import BytesIO
>>> bi = BytesIO()
>>> bi.write('中国'.encode('utf-8'))
6
>>> print(bi.getvalue())
b'\xe4\xb8\xad\xe5\x9b\xbd'
>>>
>>> from io import BytesIO
>>> bi = BytesIO(b'\xe4\xb8\xad\xe5\x9b\xbd')
>>> bi.read()
b'\xe4\xb8\xad\xe5\x9b\xbd'
>>>

五、文件和目录操作

先导入osshutil模块:

import os, shutil
# 查看当前目录的绝对路径:
>>> os.path.abspath('.')
'C:\\Users\dell\\Desktop\\learn'
# 当前Python脚本工作的目录路径
>>> os.getcwd()
'C:\\Users\dell\\Desktop\\learn'
# 路径拼接
>>> os.path.join('learn', 'testdir')
'learn\\testdir'
# 路径拆分
>>> os.path.split(r'learn\a.txt')
('learn', 'a.txt')
# 获取文件后缀名
>>> os.path.splitext(r'learn\a.txt')
('learn\\a', '.txt')
# 创建一个目录:
>>> os.mkdir('testdir')
# 删除一个目录:
>>> os.rmdir('testdir')
# 重命名文件(a.txt ——> b.txt)
>>> os.rename('a.txt', 'b.txt')
# 删除文件:
>>> os.remove('b.txt')
# 返回指定目录下的所有文件和目录名,点号代表当前目录
>>> os.listdir('.')
['a.txt', 'launcher.png', 'testdir', 'zen.txt']
# 判断是否是文件
>>> os.path.isfile('a.txt')
True
# 判断是否是目录
>>> os.path.isdir('testdir')
True
# 获取文件大小
>>> os.path.getsize('launcher.png')
7718
# 判断是否是绝对路径
>>> os.path.isabs('testdir')
False
# 判断路径是否存在
>>> os.path.exists('testdir')
True
# 获取文件名
>>> os.path.basename(r'testdir\b.txt')
'b.txt'
# 复制文件,复制a.txt
>>> shutil.copyfile('a.txt', 'a2.txt')
'a2.txt'
# 将文件复制到文件夹,复制a.txt到testdir目录
>>> shutil.copy('a.txt', 'testdir')
'testdir\\a.txt'
# 复制文件夹,复制testdir文件夹,新文件夹名为test
>>> shutil.copytree('testdir', 'test')
# 移动原文件夹到目标文件夹,如果目标文件夹不存在则相当于重命名原文件夹
>>> shutil.move('testdir', 'test')
'test\\testdir'

六、序列化

1、pickle

Python中提供了 pickle模块来实现序列化。
首先导入pickle模块:

>>> import pickle
  • 将一个Python对象序列化:
>>> d = {'name': 'tom', 'age': 18}
>>> bs = pickle.dumps(d)
>>> bs
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00tomq\x02X\x03\x00\x0
0\x00ageq\x03K\x12u.'

可以看到通过dumps()方法把对象序列化成bytes。接下来通过loads()方法将bytes反序列化成对象:

>>> pickle.loads(bs)
{'name': 'tom', 'age': 18}
  • 将对象序列化后写入文件:
>>> d = {'name': 'tom', 'age': 18}
>>> with open(r'Desktop\learn\test.txt', 'wb') as f:
...     pickle.dump(d, f)
...

对象序列化后写入文件用dump()方法,从文件中反序列化用load()方法:

>>> with open(r'Desktop\learn\test.txt', 'rb') as f:
...     pickle.load(f)
...
{'name': 'tom', 'age': 18}

这种序列化方式只能用于Python,可能不同版本的Python都不兼容,可以用它来保存一些不重要的数据。

2、JSON

JSON(JavaScript Object Notation)格式最初是为JavaScript开发的,之后成了一种通用数据格式,可以被所有语言读取,方便地存储到磁盘、通过网络传输、直接在Web页面中读取、实现数据跨平台传输等。JSON的编码是UTF-8

相比pickleJSON就强大的多了,解决了pickle的问题,更加灵活方便。

Python中提供了 json模块来支持相关JSON操作。
首先导入json模块:

>>> import json
  • Python对象和JSON串相互转换:
>>> d = {'name': 'tom', 'age': 18}
>>> json.dumps(d)
'{"name": "tom", "age": 18}'

通过dumps()方法,将一个对象转换成JSON串,让然也可以通过loads()方法,将JSON串转换成Python对象:

>>> s = '{"name": "tom", "age": 18}'
>>> json.loads(s)
{'name': 'tom', 'age': 18}
  • 自定义类的对象序列化:
    先定义一个Cat类:
class Cat():
    def __init__(self, name, age):
        """初始化参数"""
        self.name = name
        self.age = age

默认情况下,dumps()方法不知道如何将Cat的对象转换成JSON,所以需要编写一个转换函数:

def cat2dict(cat):
    return {
        'name': cat.name,
        'age': cat.age
    }
>>> cat = Cat('tom', 2)
>>> json.dumps(cat, default=cat2dict)
'{"name": "tom", "age": 2}'

通常class类的实例都有一个__dict__属性,它是一个dict,用来存储实例变量,所以就有了序列化的捷径:

json.dumps(cat, default=lambda obj: obj.__dict__)
'{"name": "tom", "age": 2}'

当然也有少数类的实例没有__dict__属性,就不能使用这种方式了。

如果将JSON转换成Cat的对象,也需要编写一个转换函数:

def dict2cat(d):
    return Cat(d['name'], d['age'])
>>> s = '{"name": "tom", "age": 2}'
>>> json.loads(s, object_hook=dict2cat)
<__main__.Cat object at 0x000000000299DDA0>
  • 将对象序列化到文件:
>>> d = {'name': 'tom', 'age': 18}
>>> with open(r'Desktop\learn\test.txt', 'w') as f:
...     json.dump(d, f)
...

序列化到文件使用dump()方法,反序列化则使用load()方法:

>>> with open(r'Desktop\learn\test.txt', 'r') as f:
...     json.load(f)
...
{'name': 'tom', 'age': 18}

你可能感兴趣的:(Learn Python 3:IO操作)