file.seek()方法引出的文本文件和二進制文件問題

問題的原由

菜鳥教程上有一段關於file.seek()方法的講解,先簡短描述一下seek()方法:html

  • seek(offset, whence)方法用於移動文件讀取指針到指定位置
  • 參數offset--開始的偏移量,也就是表明偏移的字節數
  • 參數whence--可選,默認爲0。0表示從文件開頭算起,1表示從當前位置算起,2表示從文件末尾算起
  • 返回值:該方法沒有返回值

實例

文件runoob.txt的內容以下:python

1:www.runoob.com 2:www.runoob.com 3:www.runoob.com 4:www.runoob.com 5:www.runoob.com

循環讀取文件的內容:windows

#打開文件
fo = open("runoob.txt", "r+") print("文件名爲: ", fo.name) line = fo.readline() print("讀取的數據爲: %s" % line) #從新設置文件讀取指針到開頭
fo.seek(2, 1) line = fo.readline() print("讀取的數據爲: %s" % line) #關閉文件
fo.close()

運行一下發現報錯了:編碼

D:\Program\python34\python.exe D:/python_workshop/python6/study_file.py Traceback (most recent call last): 文件名爲: runoob.txt File "D:/python_workshop/python6/study_file.py", line 158, in <module> 讀取的數據爲: 1:www.runoob.com fo.seek(2, 1) io.UnsupportedOperation: can't do nonzero cur-relative seeks
 Process finished with exit code 1

分析緣由

文本文件和二進制文件

這要要從文本文件和二進制文件提及了。spa

從廣義(物理意義)上說,二進制文件包括了文本文件,由於計算機最終存儲的是二進制文件,因此物理意義上二者就是一回事,但從狹義(邏輯)上來講,二者存儲的方式又有所不一樣。操作系統

文本文件又叫ASCII文件,這種文件在磁盤上存放時,每一個字符(8個bit位)對應一個字節,用於存放對應的ASCII碼,例如:.net

ASCII 碼   00110101 00110110 00110111 00111000指針

               |              |               |             |code

     5     6     7     8
htm

共佔用了4個字節,ASCII文件可在屏幕上按字符顯示。

二進制文件,是按二進制編碼存放文件的,如5678的存儲方式爲:00010110 00101110,只佔用2個字節,二進制文件雖然也可在屏幕上顯示,但其內容沒法讀懂。C系統在處理這些文件時,並不區分類型,都當作是字符流,按字節進行處理。 輸入輸出字符流的開始和結束只由程序控制而不受物理符號(如回車符)的控制。 ,所以也把這種文件稱做"流式文件"。

讀寫的區別

在讀取文檔時,python認爲0x1A(26)是文檔結束符(EOF),因此有時使用"r"讀取二進制文件時,可能會出現讀取不全的現象,如:

二進制文件中存在以下從低位向高位排列的數據:7F 32 1A 2F 3D 2C 12 2E 76
若是使用'r'進行讀取,則讀到第三個字節,即認爲文件結束
若是使用'rb'按照二進制位進行讀取的,不會將讀取的字節轉換成字符,從而避免了上面的錯誤

在寫入文檔時,寫入'\n',windows操做系統會隱式的將'\n'轉換爲"\r\n",再寫入到文件中;讀的時候,會把「\r\n」隱式轉化爲'\n',再讀到變量中,而二進制文件是非解釋性的,一次處理一個字符,而且不轉換字符

r+和rb+

  • "r+"是打開一個文件用於讀寫。文件指針將會放在文件的開頭
  • "rb+"是以二進制格式打開一個文件用於讀寫。文件指針將會放在文件的開頭

python3.4的官方解釋

To change the file object’s position, use f.seek(offset, from_what). The position is computed from adding offset to a reference point; the reference point is selected by the from_what argument. A from_what value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as the reference point. from_what can be omitted and defaults to 0, using the beginning of the file as the reference point.

意思是,爲了改變文件對象的位置,可使用f.seek(offset, from_what)方法。最終位置等於參考點位置加上偏移量,參考點是由from_what參數決定的。from_what有三個值,0表明文件的開始位置,1表明使用當前的位置,2表明文件的末尾位置。from_what參數省略時,默認是0。

python官方文檔也給了一個實例:

>>> f = open('workfile', 'rb+') #咱們能夠看出,文件workfile是以二進制格式進行讀寫的 >>> f.write(b'0123456789abcdef') 16
>>> f.seek(5)     # Go to the 6th byte in the file
5
>>> f.read(1) b'5'
>>> f.seek(-3, 2) # Go to the 3rd byte before the end
13
>>> f.read(1) b'd'

In text files (those opened without a b in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking to the very file end with seek(0, 2)

在文本文件中,只有在文件開頭(即from_what默認是0時)進行偏移是被容許的。不容許在當前所在位置(from_what=1)和文件末尾(from_what=2)時進行偏移。

如今回頭看看咱們的第一個代碼和報錯信息,發現咱們的讀寫模式用了"r+",咱們的文件是文本文件,在使用fo.seek()時,將from_what的值設置爲1,因此報錯了。

#打開文件
fo = open("runoob.txt", "r+") print("文件名爲: ", fo.name) line = fo.readline() print("讀取的數據爲: %s" % line) #從新設置文件讀取指針帶開頭
fo.seek(2, 1) line = fo.readline() print("讀取的數據爲: %s" % line) #關閉文件
fo.close()
D:\Program\python34\python.exe D:/python_workshop/python6/study_file.py Traceback (most recent call last): 文件名爲: runoob.txt File "D:/python_workshop/python6/study_file.py", line 158, in <module> 讀取的數據爲: 1:www.runoob.com fo.seek(2, 1) io.UnsupportedOperation: can't do nonzero cur-relative seeks
 Process finished with exit code 1

延伸

若是咱們把讀寫模式改成"rb+",以二進制的方式進行讀寫,那麼是否是就能夠了,確實能夠,但不容忽視的一個小問題是,二進制文件不會對windows下的換行(\r\n, 0x0D 0x0A)進行轉化的,咱們看到的結果將是:

文件名爲: runoob.txt 讀取的數據爲: b'1:www.runoob.com\r\n' 讀取的數據爲: b'www.runoob.com\r\n'

參考

https://blog.csdn.net/timberwolf_2012/article/details/28499615

https://www.zhihu.com/question/19971994

https://docs.python.org/3.4/tutorial/inputoutput.html

http://bbs.fishc.com/thread-60449-1-1.html

https://www.cnblogs.com/kingleft/p/5142469.html

https://www.cnblogs.com/xisheng/p/7636736.html

https://bbs.csdn.net/wap/topics/350127738

https://www.cnblogs.com/pengwangguoyh/articles/3223072.html

https://blog.csdn.net/seu_xuxueqi/article/details/621904

http://www.xuebuyuan.com/367184.html

相關文章
相關標籤/搜索