1. 程式人生 > >重拾Python學習(八)----------IO程式設計

重拾Python學習(八)----------IO程式設計

本文參考:廖雪峰的官方網站:https://www.liaoxuefeng.com

檔案讀寫

讀檔案

讀檔案的模式開啟一個檔案物件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>