問(wèn)題一:如何讀寫文本文件?
問(wèn)題內(nèi)容:
某文件編碼格式已知(如UTF-8,GBK,BIG5),在python2.X和python3.X中分別如何讀取該文件?
解決方案:
我們首先明確下2到3的一些語(yǔ)義變化:
在python2中字符串有兩種形式:str和Unicode。str表面上抽象的是字符串,實(shí)際上抽象的是連續(xù)的字節(jié),對(duì)應(yīng)python3中的bytes,只有這些字節(jié)存儲(chǔ)到物理設(shè)備上。而Unicode才是真正的字符串,對(duì)應(yīng)python3中的str。
python2.x:寫入文件前對(duì)Unicode編碼,讀入文件后對(duì)二進(jìn)制字符串解碼。
python3.x:open函數(shù)指定't'的文本模式,encoding指定編碼格式。
在python2下,我沒(méi)安裝python2,來(lái)看截圖吧:
在python3中:
在python3中定義bytes需要前面加小 b ,而python2只要字節(jié)串。
In [1]: b'dfghjdfg'
Out[1]: b'dfghjdfg'
在python3中定義Unicode,前面不需要加小 u ,而python2中需要。
In [2]: '你好'
Out[2]: '你好'
文本文件的操作:
In [2]: f = open('py3.txt','wt',encoding='utf8')
In [3]: f.write('你好,我是王二小')
Out[3]: 8
In [4]: f.close()
In [5]: f = open('py3.txt','rt',encoding='utf8')
In [6]: s = f.read()
In [7]: print(s)
你好,我是王二小
文件寫入的時(shí)候是以字節(jié)寫入,不過(guò)編碼為了utf8,文件讀取的時(shí)候也是轉(zhuǎn)碼為utf8。
問(wèn)題二:如何處理二進(jìn)制文件
這段后續(xù)補(bǔ)充
In [9]: f = open('syst.wav','rb')
In [10]: info = f.read(44)
In [11]: info
Out[11]: b'RIFF\xf4\x04\x92\x02WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00D\xac\x00\x00\x10\xb1\x02\x00\x04\x00\x10\x00data\xd0\x04\x92\x02'
In [12]: import struct
In [13]: struct.unpack?
Docstring:
unpack(fmt, buffer) -> (v1, v2, ...)
Return a tuple containing values unpacked according to the format string
fmt. The buffer's size in bytes must be calcsize(fmt). See help(struct)
for more on format strings.
Type: builtin_function_or_method
In [14]: struct.unpack('h','\x01\x02')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-4b76b634ada8> in <module>()
----> 1 struct.unpack('h','\x01\x02')
TypeError: a bytes-like object is required, not 'str'
In [15]: struct.unpack('h',info[22:24])
Out[15]: (2,)
In [16]: struct.unpack('i',info[24:28])
Out[16]: (44100,)
問(wèn)題三:如何設(shè)置文件緩沖
問(wèn)題內(nèi)容:
將文件內(nèi)容寫入到硬件設(shè)備時(shí),使用系統(tǒng)調(diào)用,這類I/O操作的時(shí)間很長(zhǎng)。為了減少I/O操作的次數(shù),文件通常使用緩沖區(qū)。(有足夠多的數(shù)據(jù)才進(jìn)行系統(tǒng)調(diào)用)文件的緩沖行為,分為全緩沖,行緩沖,無(wú)緩沖。如何沒(méi)有緩沖會(huì)造成資源的浪費(fèi)(未寫滿一個(gè)塊,依舊寫入,使用緩沖,只有當(dāng)寫滿之后,才會(huì)插入)
如何設(shè)置python中文件的緩沖行為?
解決方案:
全緩沖:open函數(shù)的buffering設(shè)置為大于1的整數(shù)n,n為緩沖區(qū)大小
行緩沖:open函數(shù)的buffering設(shè)置為1
無(wú)緩沖:open函數(shù)的buffering設(shè)置為0
關(guān)于行緩沖:
In [29]: f = open('demo3.txt','w',buffering=1)
In [30]: f.write('abcd')
Out[30]: 4
In [31]: f.write('1234')
Out[31]: 4
In [32]: f.write('\n')
Out[32]: 1
我們使用tail 監(jiān)控輸入,只有我們輸入了 '\n'之后,數(shù)據(jù)才真正的寫入。
tail -f demo3.txt
abcd1234
關(guān)于無(wú)緩沖:
In [36]: f = open('demo4.txt','w',buffering=0)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-36-7b816614dabf> in <module>()
----> 1 f = open('demo4.txt','w',buffering=0)
ValueError: can't have unbuffered text I/O
In [37]: f = open('demo4.txt','wb',buffering=0)
python3中文本文件不能設(shè)置buffering = 0,而二進(jìn)制文件可以。
問(wèn)題四:如何將文件映射到內(nèi)存?
問(wèn)題內(nèi)容:
1,在訪問(wèn)某些二進(jìn)制文件時(shí)(通常使用read()和write()方法的時(shí)候,都是以流的形式讀寫,一個(gè)字節(jié)一個(gè)字節(jié)的順序進(jìn)行),希望能把文件映射到內(nèi)存中,(像數(shù)組一樣訪問(wèn))可以實(shí)現(xiàn)隨機(jī)訪問(wèn)。(framebuffer設(shè)備文件)
2,某些嵌入式設(shè)備,寄存器被編址到內(nèi)存地址空間,我們可以映射/dev/mem某范圍,去訪問(wèn)這些寄存器。
3,如果多個(gè)進(jìn)程映射同一個(gè)文件,還能實(shí)現(xiàn)進(jìn)程通信的目的。
解決方案:
使用標(biāo)準(zhǔn)庫(kù)中mmap()函數(shù),它需要一個(gè)打開的文件描述符作為參數(shù)。
首先我們創(chuàng)建大小為1M,全部?jī)?nèi)容為0的二進(jìn)制文件。
dd if=/dev/zero of=demo.bin bs=1024 count=1024
我們查看文件內(nèi)容:
od -x demo.bin
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
4000000
我們查看下mmap函數(shù)的使用:
In [1]: import mmap
In [2]: mmap.mmap
Out[2]: mmap.mmap
In [3]: mmap.mmap?
Init signature: mmap.mmap(self, /, *args, **kwargs)
Docstring:
Windows: mmap(fileno, length[, tagname[, access[, offset]]])
Maps length bytes from the file specified by the file handle fileno,
and returns a mmap object. If length is larger than the current size
of the file, the file is extended to contain length bytes. If length
is 0, the maximum length of the map is the current size of the file,
except that if the file is empty Windows raises an exception (you cannot
create an empty mapping on Windows).
Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])
Maps length bytes from the file specified by the file descriptor fileno,
and returns a mmap object. If length is 0, the maximum length of the map
will be the current size of the file when mmap is called.
flags specifies the nature of the mapping. MAP_PRIVATE creates a
private copy-on-write mapping, so changes to the contents of the mmap
object will be private to this process, and MAP_SHARED creates a mapping
that's shared with all other processes mapping the same areas of the file.
The default value is MAP_SHARED.
To map anonymous memory, pass -1 as the fileno (both versions).
File: /usr/local/lib/python3.5/lib-dynload/mmap.cpython-35m-x86_64-linux-gnu.so
Type: type
函數(shù)的第一個(gè)參數(shù)為文件的描述符,由系統(tǒng)調(diào)用的open()函數(shù)產(chǎn)生。
In [4]: import os
In [5]: os.open?
Signature: os.open(path, flags, mode=511, *, dir_fd=None)
Docstring:
Open a file for low level IO. Returns a file descriptor (integer).
If dir_fd is not None, it should be a file descriptor open to a directory,
and path should be relative; path will then be relative to that directory.
dir_fd may not be implemented on your platform.
If it is unavailable, using it will raise a NotImplementedError.
Type: builtin_function_or_method
在這里我們使用python的open()函數(shù)和fileno()函數(shù)產(chǎn)生文件描述符:
In [7]: f = open("demo.bin",'r+b')
In [8]: f.fileno()
Out[8]: 11
函數(shù)的第二個(gè)參數(shù)是指映射大小,當(dāng)為0的時(shí)候?yàn)槿坑成洹5谌齻€(gè)參數(shù)為權(quán)限。
In [9]: mmap.mmap(f.fileno(),0,access=mmap.
mmap.ACCESS_COPY mmap.MAP_ANONYMOUS mmap.PAGESIZE
mmap.ACCESS_READ mmap.MAP_DENYWRITE mmap.PROT_EXEC
mmap.ACCESS_WRITE mmap.MAP_EXECUTABLE mmap.PROT_READ
mmap.ALLOCATIONGRANULARITY mmap.MAP_PRIVATE mmap.PROT_WRITE
mmap.error mmap.MAP_SHARED
mmap.MAP_ANON mmap.mmap
以上為權(quán)限的列表。
In [9]: m = mmap.mmap(f.fileno(),0,access=mmap.ACCESS_WRITE)
In [10]: type(m)
Out[10]: mmap.mmap
In [11]: m[0]
Out[11]: 0
In [12]: m[10:20]
Out[12]: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
返回一個(gè)mmap對(duì)象,把內(nèi)存映射為一個(gè)數(shù)組,可以進(jìn)行切片等操作。
問(wèn)題五:如何訪問(wèn)文件的狀態(tài)?
問(wèn)題內(nèi)容:
1,文件的類型(普通文件,目錄,符號(hào)連接,設(shè)備文件。。。)
2,文件的訪問(wèn)權(quán)限
3,文件的最后的訪問(wèn)/修改/節(jié)點(diǎn)狀態(tài)更改時(shí)間
4,普通文件的大小
解決方法:
方法一:使用標(biāo)準(zhǔn)庫(kù)os模塊下的三個(gè)系統(tǒng)調(diào)用stat,fstat,lstat獲取文件狀態(tài)。
方法二:標(biāo)準(zhǔn)庫(kù)中os.path下一些函數(shù),使用起來(lái)更加簡(jiǎn)潔
問(wèn)題六:如何使用臨時(shí)文件?
問(wèn)題內(nèi)容:
某項(xiàng)目,我們從傳感器采集數(shù)據(jù),每收集1G數(shù)據(jù)后,做數(shù)據(jù)分析,最終只保存分析結(jié)果。這樣很大的臨時(shí)數(shù)據(jù)如果常駐內(nèi)存,將消耗大量?jī)?nèi)存資源,我們可以使用臨時(shí)文件存儲(chǔ)這些臨時(shí)數(shù)據(jù)(外部存儲(chǔ))。
臨時(shí)文件不用命名,且關(guān)閉后會(huì)自動(dòng)被刪除。
解決方案:
可以使用標(biāo)準(zhǔn)庫(kù)中tempfile下的temporaryFile,NamedTemporaryFile。
In [1]: from tempfile import TemporaryFile ,NamedTemporaryFile
In [2]: TemporaryFile?
Signature: TemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None)
Docstring:
Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
'mode' -- the mode argument to io.open (default "w+b").
'buffering' -- the buffer size argument to io.open (default -1).
'encoding' -- the encoding argument to io.open (default None)
'newline' -- the newline argument to io.open (default None)
The file is created as mkstemp() would do it.
Returns an object with a file-like interface. The file has no
name, and will cease to exist when it is closed.
File: /usr/local/lib/python3.5/tempfile.py
Type: function
默認(rèn)是以二進(jìn)制打開文件的
In [3]: f = TemporaryFile('w+t')
In [4]: f.write('abcdef' * 10000)
Out[4]: 60000
In [5]: f.seek(0)
Out[5]: 0
In [6]: f.read(100)
Out[6]: 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd'
使用TemporaryFile()創(chuàng)建的文件,不能在文件系統(tǒng)中查找到,只能通過(guò)文件對(duì)象 f 訪問(wèn)。
使用NamedTemporaryFile()創(chuàng)建的臨時(shí)文件則可以在文件系統(tǒng)中查找得到。
In [7]: NamedTemporaryFile?
Signature: NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True)
Docstring:
Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
'mode' -- the mode argument to io.open (default "w+b").
'buffering' -- the buffer size argument to io.open (default -1).
'encoding' -- the encoding argument to io.open (default None)
'newline' -- the newline argument to io.open (default None)
'delete' -- whether the file is deleted on close (default True).
The file is created as mkstemp() would do it.
Returns an object with a file-like interface; the name of the file
is accessible as its 'name' attribute. The file will be automatically
deleted when it is closed unless the 'delete' argument is set to False.
File: /usr/local/lib/python3.5/tempfile.py
Type: function
In [8]: ntf = NamedTemporaryFile("w+t")
In [9]: ntf.
File "<ipython-input-9-adee75e8b522>", line 1
ntf.
^
SyntaxError: invalid syntax
In [10]: ntf.
ntf.close ntf.file
ntf.delete ntf.name
In [10]: ntf.name
Out[10]: '/tmp/tmp7ggfe3br'
name屬性就是文件路徑
In [11]: ntf = NamedTemporaryFile("w+t")
In [12]: ntf.name
Out[12]: '/tmp/tmp9gbuotxm'
我們發(fā)現(xiàn)兩次的name屬性值不同,是因?yàn)槊看侮P(guān)閉之后,前面的文件會(huì)被刪除掉
我們可以指定Signature: NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True)
函數(shù)參數(shù)里面的 delete= 為False。則關(guān)閉后之前的文件不會(huì)被刪除。
In [13]: ntf = NamedTemporaryFile("w+t", delete=False)
In [14]: ntf.name
Out[14]: '/tmp/tmpgfps1wco'
In [15]: ntf = NamedTemporaryFile("w+t", delete=False)
In [16]: ntf.name
Out[16]: '/tmp/tmpbm6a_0ze'
tmpbm6a_0ze
tmpgfps1wco
我們可以看到之前創(chuàng)建的tmpgfps1wco并沒(méi)有在文件關(guān)閉之后刪除。
使用NamedTemporaryFile()創(chuàng)建的文件可以被多個(gè)進(jìn)程訪問(wèn),而被TemporaryFile()創(chuàng)建的文件只能被當(dāng)前進(jìn)程訪問(wèn)。