Python 學(xué)習(xí)筆記9 - IO編程

文件讀寫

讀寫文件就是請求操作系統(tǒng)打開一個(gè)文件對象(通常稱為文件描述符),然后,通過操作系統(tǒng)提供的接口從這個(gè)文件對象中讀取數(shù)據(jù)(讀文件),或者把數(shù)據(jù)寫入這個(gè)文件對象(寫文件)

讀文件

open() 函數(shù)用于打開一個(gè)文件對象

f = open('/Users/michael/test.txt', 'r')

標(biāo)示符'r'表示讀

如果文件不存在,open() 函數(shù)就會拋出一個(gè) IOError 的錯(cuò)誤

如果文件打開成功,調(diào)用 read()方法可以一次讀取文件的全部內(nèi)容,Python 把內(nèi)容讀到內(nèi)存,用一個(gè) str 對象表示

str1 = f.read()

最后一步是調(diào)用close()方法關(guān)閉文件

f.close()

為了確保文件能正確被關(guān)閉,可用 try ... finally

try:
    f = open('/path/to/file', 'r')
    print(f.read())
finally:
    if f:
        f.close()

with 語句來自動幫我們調(diào)用 close() 方法:

with open('/path/to/file', 'r') as f:
    print(f.read())
  • read() 會一次性讀取文件的全部內(nèi)容
  • read(size) 每次最多讀取size個(gè)字節(jié)的內(nèi)容
  • readline() 每次讀取一行內(nèi)容
  • readlines() 一次讀取所有內(nèi)容并按行返回list

file-like Object

open() 函數(shù)返回的這種有個(gè)read() 方法的對象,在 Python 中統(tǒng)稱為 file-like Object 。除了file外,還可以是內(nèi)存的字節(jié)流,網(wǎng)絡(luò)流,自定義流等等

file-like Object不要求從特定類繼承,只要寫個(gè)read()方法就行

字符編碼

指定讀取文件的編碼(默認(rèn) utf-8):

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')

遇到有些編碼不規(guī)范的文件,你可能會遇到 UnicodeDecodeError ,因?yàn)樵谖谋疚募锌赡軍A雜了一些非法編碼的字符

open() 函數(shù)還接收一個(gè) errors 參數(shù),表示如果遇到編碼錯(cuò)誤后如何處理

最簡單的方式是直接忽略:

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

二進(jìn)制文件

要讀取二進(jìn)制文件,用 'rb' 模式打開文件即可:

f = open('/Users/michael/test.jpg', 'rb')
f.read()

寫文件

寫文件調(diào)用 open() 函數(shù)時(shí),傳入標(biāo)識符 'w' 或者 'wb' 表示寫文本文件或?qū)懚M(jìn)制文件:

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

當(dāng)我們寫文件時(shí),操作系統(tǒng)往往不會立刻把數(shù)據(jù)寫入磁盤,而是放到內(nèi)存緩存起來,空閑的時(shí)候再慢慢寫入。只有調(diào)用close()方法時(shí),操作系統(tǒng)才保證把沒有寫入的數(shù)據(jù)全部寫入磁盤

StringIO 和 BytesIO

StringIO

把str寫入StringIO:

from io import StringIO

# 創(chuàng)建一個(gè)StringIO
f = StringIO()

# 返回字符數(shù)
f.write('hello')

# 獲得寫入后的str
print(f.getvalue())

像讀文件一樣讀取StringIO:

from io import StringIO

f = StringIO('Hello!\nHi!\nGoodbye!')

while True:
    s = f.readline()
    if s == '':
        break
    print(s.strip())

BytesIO

from io import BytesIO

f = BytesIO()

# 返回字節(jié)數(shù)
f.write('中文'.encode('utf-8'))

print(f.getvalue())
from io import BytesIO

f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')

f.read()

操作文件和目錄

Python 內(nèi)置的 os 模塊也可以直接調(diào)用操作系統(tǒng)提供的接口函數(shù)

import os

# 操作系統(tǒng)類型,如果是 posix,說明系統(tǒng)是Linux、Unix或Mac OS X,如果是nt,就是Windows系統(tǒng)
os.name

# 獲取詳細(xì)的系統(tǒng)信息,在Windows上不提供
os.uname()

# 獲取在操作系統(tǒng)中定義的環(huán)境變量
os.environ

# 獲取某個(gè)環(huán)境變量的值
os.environ.get('PATH')
os.environ.get('x', 'default')

操作文件和目錄

操作文件和目錄的函數(shù)一部分放在 os 模塊中,一部分放在 os.path 模塊中

# 查看當(dāng)前目錄的絕對路徑
os.path.abspath('.') ==> 'C:\\Users\\lianwx'

# 列出當(dāng)前路徑下的所有文件和子目錄
os.listdir('.')

# 判斷路徑下是否目錄
os.path.isdir('path')

# 判斷路徑下是否文件
os.path.isfile('path')

# 合并、拆分路徑的函數(shù)并不要求目錄和文件要真實(shí)存在,它們只對字符串進(jìn)行操作
# 在某個(gè)目錄下創(chuàng)建一個(gè)新目錄,首先把新目錄的完整路徑表示出來
os.path.join('C:\\Users\\lianwx', 'testdir')

# 拆分路徑
os.path.split('/Users/michael/testdir/file.txt') ==> ('/Users/michael/testdir', 'file.txt')

# 得到文件擴(kuò)展名
os.path.splitext('/path/to/file.txt') ==> ('/path/to/file', '.txt')

# 創(chuàng)建一個(gè)目錄
os.mkdir('/Users/michael/testdir')

# 刪掉一個(gè)目錄
os.rmdir('/Users/michael/testdir')

# 對文件重命名
os.rename('test.txt', 'test.py')

# 刪掉文件
os.remove('test.py')

# 復(fù)制文件
# 讀寫文件可以完成文件復(fù)制
# 使用 `shutil` 模塊的 `copyfile()` 函數(shù)

利用Python的特性來過濾文件

# 列出當(dāng)前目錄下的所有目錄
[x for x in os.listdir('.') if os.path.isdir(x)]

# 列出所有的.py文件
[x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']

序列化

Python提供了 pickle 模塊來實(shí)現(xiàn)序列化

pickle.dumps() 方法把任意對象序列化成一個(gè) bytes

pickle.dump() 直接把對象序列化后寫入一個(gè) file-like Object

把一個(gè) dict 序列化并寫入文件:

import pickle

d = dict(name='Bob', age=20, score=88)

# 得到一個(gè)bytes,然后,就可以把這個(gè)bytes寫入文件
pickle.dumps(d)


f = open('dump.txt', 'wb')

# 直接把對象序列化后寫入一個(gè)file-like Object
pickle.dump(d, f)

f.close()

反序列化:

pickle.loads() 方法把 bytes 反序列化出對象

pickle.load() 方法從一個(gè)file-like Object中直接反序列化出對象

f = open('dump.txt', 'rb')

d = pickle.load(f)

f.close()

JSON

Python 內(nèi)置的 json 模塊提供了非常完善的 Python 對象到 JSON 格式的轉(zhuǎn)換

json.dumps() 方法返回一個(gè) str ,內(nèi)容就是標(biāo)準(zhǔn)的 JSON

json.dump() 方法可以直接把 JSON 寫入一個(gè) file-like Object

import json

d = dict(name='Bob', age=20, score=88)

json.dumps(d)

json.loads() 方法把JSON的字符串反序列化

json.load() 方法從file-like Object中讀取字符串并反序列化

json_str = '{"age": 20, "score": 88, "name": "Bob"}'

json.loads(json_str)

JSON進(jìn)階

序列化一個(gè) class

默認(rèn)情況下,dumps() 方法不知道如何將一個(gè)實(shí)例變?yōu)橐粋€(gè) JSON 的 {} 對象

dumps() 方法還提供了一大堆的可選參數(shù) ,其中參數(shù) default 接受一個(gè)函數(shù),函數(shù)可傳入一個(gè)對象,返回一個(gè) dict,作為轉(zhuǎn)換函數(shù)

通常class的實(shí)例都有一個(gè) __dict__ 屬性,它就是一個(gè) dict ,用來存儲實(shí)例變量。也有少數(shù)例外,比如定義了slots的class。

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, default=lambda obj: obj.__dict__))

把JSON反序列化為一個(gè) Student 對象實(shí)例,loads() 方法首先轉(zhuǎn)換出一個(gè) dict 對象,然后,我們傳入的 object_hook 函數(shù)負(fù)責(zé)把 dict 轉(zhuǎn)換為 Student 實(shí)例:

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))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • IO編程概念 IO在計(jì)算機(jī)中指Input/Output,也就是輸入和輸出。由于程序和運(yùn)行時(shí)數(shù)據(jù)是在內(nèi)存中駐留,由C...
    時(shí)間之友閱讀 774評論 0 0
  • 本文是筆者學(xué)習(xí)廖雪峰Python3教程的筆記,在此感謝廖老師的教程讓我們這些初學(xué)者能夠一步一步的進(jìn)行下去.如果讀者...
    相關(guān)函數(shù)閱讀 1,541評論 2 9
  • 文件讀寫 讀寫文件是最常見的IO操作。Python內(nèi)置了讀寫文件的函數(shù),用法和C是兼容的。由于文件讀寫時(shí)都有可能產(chǎn)...
    時(shí)間之友閱讀 541評論 0 0
  • IO在計(jì)算機(jī)中是指input/output,也就是輸入和輸出。由于程序和運(yùn)行時(shí)數(shù)據(jù)是在內(nèi)存中駐留,由CPU這個(gè)超快...
    Sun_atom閱讀 1,770評論 0 0
  • 在 阿多尼斯的《門后的童年》里讀到這樣一段:自從你認(rèn)識了自己的路,你真正的失落便開始了:你把雙肩交付給誰,...
    blairbellac閱讀 271評論 0 1

友情鏈接更多精彩內(nèi)容