重拾Python學習(八)----------IO程式設計
檔案讀寫
讀檔案
讀檔案的模式開啟一個檔案物件open()
一次讀取檔案的全部內容read()
關閉檔案close()
>>> f = open('/Users/michael/test.txt', 'r')
>>> f.read()
'Hello, world!'
>>> f.close()
with
語句來自動幫我們呼叫close()
方法
with open('/path/to/file', 'r') as f:
print (f.read())
read()
會一次性讀取檔案的全部內容,保險起見,可以反覆呼叫read(size)
方法,每次最多讀取size個位元組的內容
readline()
可以每次讀取一行內容
readlines()
一次讀取所有內容並按行返回list
如果檔案很小,
read()
一次性讀取最方便;如果不能確定檔案大小,反覆呼叫read(size)
比較保險;如果是配置檔案,呼叫readlines()
最方便
for line in f.readlines():
print(line.strip()) # 把末尾的'\n'刪掉
二進位制檔案
讀取二進位制檔案,比如圖片、視訊,'rb'
>>> f = open('/Users/michael/test.jpg', 'rb')
>>> f.read()
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六進位制表示的位元組
字元編碼
open()
函式傳入encoding
引數
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
>>> f.read()
'測試'
寫檔案
傳入識別符號'w'
或者'wb'
with open('/Users/michael/test.txt' , 'w') as f:
f.write('Hello, world!')
以'w'
模式寫入檔案時,如果檔案已存在,會直接覆蓋(相當於刪掉後新寫入一個檔案),傳入'a'
以追加(append)模式寫入
與C語言中的open()、read()、write()的檔案操作非常類似
StringIO和BytesIO
StringIO
StringIO就是在記憶體中讀寫str
把str寫入StringIO:
>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5
>>> f.write(' ')
1
>>> f.write('world!')
6
>>> print(f.getvalue())
hello world!
getvalue()
方法用於獲得寫入後的str
讀取StringIO:
>>> from io import StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
... s = f.readline()
... if s == '':
... break
... print(s.strip())
...
Hello!
Hi!
Goodbye!
BytesIO
StringIO操作的只能是str
,如果要操作二進位制資料,就需要使用BytesIO
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'
寫入的不是str
,而是經過UTF-8編碼的bytes
>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
StringIO和BytesIO是在記憶體中操作str和bytes的方法,使得和讀寫檔案具有一致的介面
操作檔案和目錄
os
模組
>>> import os
>>> os.name # 作業系統型別
'posix'
>>> os.uname() # 獲取詳細的系統資訊
posix.uname_result(sysname='Darwin', nodename='MichaelMacPro.local', release='14.3.0', version='Darwin Kernel Version 14.3.0: Mon Mar 23 11:59:05 PDT 2015; root:xnu-2782.20.48~5/RELEASE_X86_64', machine='x86_64')
>>> os.environ # 環境變數
environ({'VERSIONER_PYTHON_PREFER_32_BIT': 'no', 'TERM_PROGRAM_VERSION': '326', 'LOGNAME': 'michael', 'USER': 'michael', 'PATH': '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin', ...})
操作檔案和目錄
os
模組,os.path
模組
# 檢視當前目錄的絕對路徑:
>>> os.path.abspath('.')
'/Users/michael'
# 在某個目錄下建立一個新目錄,首先把新目錄的完整路徑表示出來:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 然後建立一個目錄:
>>> os.mkdir('/Users/michael/testdir')
# 刪掉一個目錄:
>>> os.rmdir('/Users/michael/testdir')
把兩個路徑合成一個時os.path.join()
拆分路徑時os.path.split()
>>> 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')
檔案操作
# 對檔案重新命名:
>>> os.rename('test.txt', 'test.py')
# 刪掉檔案:
>>> os.remove('test.py')
shutil
模組中找到很多實用函式,它們可以看做是os
模組的補充,如copyfile()
列出當前目錄下的所有目錄:
>>> [x for x in os.listdir('.') if os.path.isdir(x)]
['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Applications', 'Desktop', ...]
列出所有的.py檔案:
>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']
序列化
把變數從記憶體中變成可儲存或傳輸的過程稱之為序列化,pickle
模組
Java稱之為serialization
把任意物件序列化成一個bytespickle.dumps()
,就可以把這個bytes寫入檔案
>>> import pickle
>>> d = dict(name='Bob', age=20, score=88)
>>> pickle.dumps(d)
b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x14X\x05\x00\x00\x00scoreq\x02KXX\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Bobq\x04u.'
直接把物件序列化後寫入一個file-like Objectpickle.dump()
>>> f = open('dump.txt', 'wb')
>>> pickle.dump(d, f)
>>> f.close()
反序列化出物件pickle.loads()
,從一個file-like Object中直接反序列化出物件pickle.load()
>>> f = open('dump.txt', 'rb')
>>> d = pickle.load(f)
>>> f.close()
>>> d
{'age': 20, 'score': 88, 'name': 'Bob'}
JSON
Python物件變成一個JSON:
>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)
'{"age": 20, "score": 88, "name": "Bob"}'
dumps()
方法返回一個str,內容就是標準的JSON,dump()
方法可以直接把JSON寫入一個file-like Object
JSON反序列化為Python物件,用loads()
或者對應的load()
方法
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> json.loads(json_str)
{'age': 20, 'score': 88, 'name': 'Bob'}
JSON進階
class的例項物件序列化為JSON
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))
Traceback (most recent call last):
...
TypeError: <__main__.Student object at 0x10603cc50> is not JSON serializable
dumps()
方法不知道如何將Student
例項變為一個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}
把任意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>