StringIO和BytesIO
很多時(shí)候咸作,數(shù)據(jù)讀寫不一定是文件浙值,也可以在內(nèi)存中讀寫羔巢。
StringIO顧名思義就是在內(nèi)存中讀寫str。
要把str寫入StringIO吴叶,我們需要先創(chuàng)建一個(gè)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实束,可以用一個(gè)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构订,如果要操作二進(jìn)制數(shù)據(jù),就需要使用BytesIO避矢。
BytesIO實(shí)現(xiàn)了在內(nèi)存中讀寫bytes悼瘾,我們創(chuàng)建一個(gè)BytesIO,然后寫入一些bytes:
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'
請注意审胸,寫入的不是str亥宿,而是經(jīng)過UTF-8編碼的bytes。
和StringIO類似砂沛,可以用一個(gè)bytes初始化BytesIO烫扼,然后,像讀文件一樣讀劝帧:
>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
操作文件和目錄
如果我們要操作文件映企、目錄,可以在命令行下面輸入操作系統(tǒng)提供的各種命令來完成静浴。比如dir堰氓、cp等命令。
如果要在Python程序中執(zhí)行這些目錄和文件的操作怎么辦马绝?其實(shí)操作系統(tǒng)提供的命令只是簡單地調(diào)用了操作系統(tǒng)提供的接口函數(shù)豆赏,Python內(nèi)置的os模塊也可以直接調(diào)用操作系統(tǒng)提供的接口函數(shù)。
打開Python交互式命令行富稻,我們來看看如何使用os模塊的基本功能:
>>> import os
>>> os.name # 操作系統(tǒng)類型
'posix'
如果是posix,說明系統(tǒng)是Linux白胀、Unix或Mac OS X椭赋,如果是nt,就是Windows系統(tǒng)或杠。
要獲取詳細(xì)的系統(tǒng)信息哪怔,可以調(diào)用uname()函數(shù):
>>> 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')
注意uname()函數(shù)在Windows上不提供,也就是說向抢,os模塊的某些函數(shù)是跟操作系統(tǒng)相關(guān)的认境。
- 環(huán)境變量
在操作系統(tǒng)中定義的環(huán)境變量,全部保存在os.environ這個(gè)變量中挟鸠,可以直接查看:
>>> 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', ...})
要獲取某個(gè)環(huán)境變量的值叉信,可以調(diào)用os.environ.get('key'):
>>> os.environ.get('PATH')
'/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin'
>>> os.environ.get('x', 'default')
'default'
- 操作文件和目錄
操作文件和目錄的函數(shù)一部分放在os模塊中,一部分放在os.path模塊中艘希,這一點(diǎn)要注意一下硼身。查看硅急、創(chuàng)建和刪除目錄可以這么調(diào)用:
# 查看當(dāng)前目錄的絕對路徑:
>>> os.path.abspath('.')
'/Users/michael'
# 在某個(gè)目錄下創(chuàng)建一個(gè)新目錄,首先把新目錄的完整路徑表示出來:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 然后創(chuàng)建一個(gè)目錄:
>>> os.mkdir('/Users/michael/testdir')
# 刪掉一個(gè)目錄:
>>> os.rmdir('/Users/michael/testdir')
把兩個(gè)路徑合成一個(gè)時(shí)佳遂,不要直接拼字符串营袜,而要通過os.path.join()
函數(shù),這樣可以正確處理不同操作系統(tǒng)的路徑分隔符丑罪。在Linux/Unix/Mac下荚板,os.path.join()
返回這樣的字符串:
part-1/part-2
而Windows下會返回這樣的字符串:
part-1\part-2
同樣的道理,要拆分路徑時(shí)吩屹,也不要直接去拆字符串跪另,而要通過os.path.split()
函數(shù),這樣可以把一個(gè)路徑拆分為兩部分祟峦,后一部分總是最后級別的目錄或文件名:
>>> os.path.split('/Users/michael/testdir/file.txt')
('/Users/michael/testdir', 'file.txt')
os.path.splitext()
可以直接讓你得到文件擴(kuò)展名罚斗,很多時(shí)候非常方便:
>>> os.path.splitext('/path/to/file.txt')
('/path/to/file', '.txt')
這些合并、拆分路徑的函數(shù)并不要求目錄和文件要真實(shí)存在宅楞,它們只對字符串進(jìn)行操作针姿。
文件操作使用下面的函數(shù)。假定當(dāng)前目錄下有一個(gè)test.txt文件:
# 對文件重命名:
>>> os.rename('test.txt', 'test.py')
# 刪掉文件:
>>> os.remove('test.py')
但是復(fù)制文件的函數(shù)居然在os模塊中不存在厌衙!原因是復(fù)制文件并非由操作系統(tǒng)提供的系統(tǒng)調(diào)用距淫。理論上講,我們通過上一節(jié)的讀寫文件可以完成文件復(fù)制婶希,只不過要多寫很多代碼榕暇。
幸運(yùn)的是shutil模塊提供了copyfile()的函數(shù),你還可以在shutil模塊中找到很多實(shí)用函數(shù)喻杈,它們可以看做是os模塊的補(bǔ)充彤枢。
最后看看如何利用Python的特性來過濾文件。比如我們要列出當(dāng)前目錄下的所有目錄筒饰,只需要一行代碼:
>>> [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']
小結(jié)
Python的os模塊封裝了操作系統(tǒng)的目錄和文件操作,要注意這些函數(shù)有的在os模塊中瓷们,有的在os.path模塊中业栅。
練習(xí)
1.利用os模塊編寫一個(gè)能實(shí)現(xiàn)dir -l輸出的程序。
在我的Mac上dir -l等同于ls -l,以下是顯示效果:
這里就寫一個(gè)簡化的谬晕,前面幾項(xiàng)權(quán)限碘裕、hard link數(shù)目等等就省了:
import os
import time
for file in os.listdir('.'):
fileSize = os.path.getsize(file)
rawTime = os.path.getmtime(file)
mTime = time.localtime(rawTime)
modifyTime = time.strftime('%Y-%m-%d %H:%M', mTime)
fileName = file
print("%d %s %s" % (fileSize, modifyTime, fileName))
效果:
2.編寫一個(gè)程序,能在當(dāng)前目錄以及當(dāng)前目錄的所有子目錄下查找文件名包含指定字符串的文件攒钳,并打印出相對路徑帮孔。
import os
import time
# 獲取當(dāng)前目錄路徑
cwd = os.getcwd()
def search_file(name):
file_list = [x for x in os.listdir(cwd) if os.path.isfile(x)]
for file in file_list:
if name in file.split('.')[0]:
print(os.path.abspath(file))
def search(name):
search_file(name)
dir_list = [x for x in os.listdir() if os.path.isdir(x)]
for d in dir_list:
os.chdir(d)
search(name)
os.chdir('..')
name = input("Please enter the file name:\n")
search(name)
效果: