第95天:StringIO & BytesIO

by 吳刀釣魚

上一篇中我們介紹了文件的基本讀寫操作,但是很多時候數據的讀寫並不一定都是在文件中,我們也可以在內存中讀寫數據,因此引出我們今天的主要內容,即 StringIO 和 BytesIO,讓你學會在內存中進行數據的基本讀寫操作。

1 前言-內存與硬盤

在正式介紹 StringIO 和 BytesIO 之前,我們先來了解一下內存和硬盤的差異,以便更好的理解硬盤中文件的基本操作與 StringIO 和 BytesIO 對數據的基本操作兩者之間存在的意義。

內存與硬盤的差異:

差異點 內存 硬盤
形狀 長條形,所以有內存條之稱 四四方方的,內含盤片
容量(以 PC 機爲例) 4G 1T
功能 存儲任務管理器的進程 存儲文檔、軟件等數據
運行速度
特點 存放 CPU 運算的數據,一旦斷電數據就會消失 可以永久存儲數據

通俗點來講,我們電腦裏的 C 盤、D盤等都是硬盤,電腦關機後再次開機這些盤符裏面的數據依然還在。但是我們電腦任務管理器裏面跑的進程的數據都是存儲在內存中的,電腦關機後進程裏面的數據就不復存在了。

正是由於硬盤的讀取數據比較慢,CPU 如果在運行程序的時候所有數據都直接從硬盤中讀寫,那麼電腦的運行速度將會大打折扣。因此 CPU 會將運行軟件時要用到的數據一次性從硬盤中調到運行速度很快的內存中,然後 CPU 再與內存進行數據交換。一個很明顯的現象就是我們在打開一個軟件時會有一段時間延遲,但是打開之後軟件的運行速度就很快了。

好了,現在我們應該對在內存與硬盤上讀取數據大概有一個瞭解,開始進入我們的正題。

2 StringIO 和 BytesIO

StringIO 和 BytesIO 的作用簡單來說,就是在內存中虛擬一個文件的感覺,這個虛擬出來的文件操作方式與上一篇介紹的在硬盤中文件的基本操作類似。在 Python3 中,這兩“兄弟”現在已經歸入 IO 模塊。

2.1 StringIO

要把 str 字符串寫入內存中,我們需要創建一個 StringIO 對象,然後像文件一樣對讀取內容。其中 StringIO 中多了一個 getvalue() 方法,目的是用於獲取寫入後的 str。

示例 1:

# 定義一個 StringIO 對象,寫入並讀取其在內存中的內容
from io import StringIO

f = StringIO()

f.write('Python-100')
str = f.getvalue()
print('寫入內存中的字符串爲:%s' %str)

f.write('\n') # 追加寫入內容
f.write('堅持100天')
str = f.getvalue()  # getvalue() 可以讀取到 StringIO 中的所有內容
print('寫入內存中的字符串爲:\n%s' %str)

f.close() # 釋放內存中的數據,後續不可再對該 StringIO 進行內容的讀寫操作

# 輸出結果
# 寫入內存中的字符串爲:
# Python-100
# 寫入內存中的字符串爲:
# Python-100
# 堅持100天

示例 2:

# 當然也可以用 read()、readline() 等來讀取 StringIO 中寫入的字符串

from io import StringIO

str = 'Python-100' + '\n' + '堅持100天'

f = StringIO(str)

currentStr = f.read()
print('寫入內存中的字符串爲:\n%s' %currentStr)

f.close()

示例 3:

# 考慮一個場景,比如你需要對爬蟲爬取到的數據進行操作,但是你不想把數據寫入本地的硬盤上,這時候 StringIO 就派上用場了。

from io import StringIO

# 假設的爬蟲數據輸出函數 outputData()
def outputData():
    dataOne   = '我是 1 號爬蟲數據\n'
    dataTwo   = '我是 2 號爬蟲數據\n'
    dataThree = '我是 3 號爬蟲數據'
    data = dataOne + dataTwo + dataThree
    return data

# dataStr 爲爬蟲數據字符串
dataStr = outputData()

# 1. 將 outputData() 函數返回的內容寫入內存中
dataIO = StringIO(dataStr)

# 1.1 輸出 StringIO 在內存中寫入的數據
print('1.1內存中寫入的數據爲:\n%s' %dataIO.getvalue())

# 輸出結果:
# 1.1內存中寫入的數據爲:
# 我是 1 號爬蟲數據
# 我是 2 號爬蟲數據
# 我是 3 號爬蟲數據

# 1.2 按行輸出寫入的數據方式一
print('1.2按行輸出寫入的數據方式一:')
for data in dataIO.readlines():
    print(data.strip('\n')) # 去掉每行數據末尾的換行符

# 輸出結果:
# 1.2按行輸出寫入的數據方式一:
# 我是 1 號爬蟲數據
# 我是 2 號爬蟲數據
# 我是 3 號爬蟲數據

# 1.3 按行輸出寫入的數據方式二
# 由於上一步的操作,此時文件指針指向數據末尾(32),我們需要將指針指向起始位置
print('由於上一步操作的輸出,此時文件指針位置爲:%d' %dataIO.tell())

# 將文件指針指向起始位置,方便下面的演示
dataIO.seek(0)
print('1.3按行輸出寫入的數據方式二:')
for data in dataIO:
    print(data.strip('\n'))

# 輸出結果:
# 1.3按行輸出寫入的數據方式二:
# 我是 1 號爬蟲數據
# 我是 2 號爬蟲數據
# 我是 3 號爬蟲數據

# 2. 採用 write() 的方法將字符串寫入內存
dataWriteIO = StringIO()
dataWriteIO.write(dataStr)

# 2.1 輸出內存中寫入的數據
print('2.1內存中寫入的數據爲:\n%s' %dataIO.getvalue())

# 輸出結果:
# 2.1內存中寫入的數據爲:
# 我是 1 號爬蟲數據
# 我是 2 號爬蟲數據
# 我是 3 號爬蟲數據
 
# 2.2 按行輸出寫入的數據方式一
# 由於 write() 寫入字符串後,文件指針會指向寫入內容的結尾,需要將文件指針指向起始位置,否則未能輸出內容
print('2.2按行輸出寫入的數據方式一:')
print('輸出內容爲空!')
for data in dataIO:
    print(data.strip('\n'))
print('輸出內容爲空!')

# 輸出結果:
# 2.2按行輸出寫入的數據方式一:
# 輸出內容爲空!
# 輸出內容爲空!


# 2.3 按行輸出寫入的數據方式二
# 將指針指向起始位置重新按行輸出
dataIO.seek(0)
print('2.3按行輸出寫入的數據方式:')
for data in dataIO.readlines():
    print(data.strip('\n'))

# 輸出結果
# 2.3按行輸出寫入的數據方式:
# 我是 1 號爬蟲數據
# 我是 2 號爬蟲數據
# 我是 3 號爬蟲數據

Tips:
根據這個例子可以看出,當我們使用 StringIO(str) 方法向內存寫入數據時,文件指針是指向起始位置的,比如示例 3 的 1.2 場景中 readlines() 可以讀取到數據。當我們使用 write(str) 方法向內存寫入數據時,文件指針會指向寫入內容的結尾,讀取數據時需要將指針移動到起始位置,比如示例 3 的 2.3 場景。

2.2 BytesIO

BytesIO,顧名思義,就是將字節流寫入到內存中,其實它的操作方法與 StringIO 一樣,區別就在於前者寫入字節,後者寫入字符串。這邊就簡單舉個例子演示,不再具體介紹了。

示例:

# 定義一個 BytesIO 對象,寫入並讀取其在內存中的內容

from io import BytesIO

str = 'Python-100' + '\n' + '堅持100天'

f = BytesIO(str.encode('utf-8'))

print('寫入內存的字節爲:%s' %f.getvalue())

print('字節解碼後內容爲:\n%s' %f.getvalue().decode('utf-8'))

Tips:
根據示例可知,對於字節我們需要掌握其正確的編解碼方式,比如有 'utf-8'、'gbk' 等。

3 總結

本節給大家介紹了 Python 中 StringIO 和 BytesIO 的基本使用方法,掌握在內存中存取數據的基本操作,同時介紹了內存與硬盤的區別,讓大家明白在內存中存取數據的優勢,助力您在爬蟲的道路越走越遠。

示例代碼:Python-100-days-day95

參考資料

[1] https://www.cnblogs.com/minseo/p/11164921.html

[2] https://www.liaoxuefeng.com/wiki/1016959663602400/1017609424203904

關注公衆號:python技術,回覆"python"一起學習交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章