爬蟲 (二十一) 最完整的文件操做(值得收藏) (十二)

一,打開文件
  python中打開文件的函數爲open('filename',mode='r',encode='None'),open函數默認返回文件的句柄,咱們能夠根據句柄來對文件進行增,刪,改,查的操做。將句柄賦給咱們定義的變量,假設咱們定義變量爲f,則f=open('filename',mode='r',encode='utf-8') 或者with open('filename') as f。python

注意點:linux

  1.python解釋器打開文件時,是對硬盤進行操做,須要內核態才能夠操做硬盤,故此時python解釋器是調用操做系統的文件讀取接口。windows中文版本默認使用GBK編碼表,linux默認使用utf-8,全部若是操做的文件在windows下,非GBK編碼的,須要在open函數中聲明編碼類型,使操做系統運用相應的編碼規則進行解碼讀取,防止串碼,亂碼現象。正則表達式

  2.open主要有三種模式,讀(r),寫(w),追加(a),其中,默認爲讀模式。各個模式的詳解,見下文。shell

二,關閉文件
關閉文件有兩組方式:windows

  1.使用f.close() ,f爲open返回的句柄賦值的變量名。dom

  2.程序結束後,自動關閉。第一個方法容易形成文件寫操做時,數據的丟失。緣由是寫數據時,數據會先保存在內存中,文件關閉時纔會寫入硬盤,此時若是文件未關閉,軟件由於異常崩潰,致使內存中的數據丟失,且未寫入硬盤中。做爲第一種關閉方法的優化,是使用:with open('filename') as f 。with會建立一個程序塊,將文件操做置於with程序塊下,這樣with控制塊結束,文件也會自動關閉。ide

語法以下:函數

with open('f1.txt') as f1 , open('f2.txt') as f2:
    ......

三,操做文件
3.1 file的基本方法oop

F.read([size])  size爲讀取的長度,以byte爲單位
F.readline([size]) 若是定義了size,有可能返回的只是一行的一部分 
F.readlines([size]) 把文件每一行做爲一個list的一個成員,並返回這個list。其實它的內部是經過循環調用readline()來實現的。若是提供size參數,size是表示讀取內容的總長,也就是說可能只讀到文件的一部分
F.write(str) 把str寫到文件中,write()並不會在str後加上一個換行符
F.writelines(seq) 把seq的內容所有寫到文件中。這個函數也只是忠實地寫入,不會在每行後面加上任何東西
F.close() 關閉文件。python會在一個文件不用後自動關閉文件,不過這一功能沒有保證,最好仍是養成本身關閉的習慣。若是一個文件在關閉後還對其進行操做會產生ValueError 

F.flush()把緩衝區的內容寫入硬盤 ,即將內存中的數據刷新到銀盤上
F.fileno() 返回一個長整型的」文件標籤「 
F.isatty()文件是不是一個終端設備文件(unix系統中的)

F.tell() 返回文件操做標記的當前位置,以文件的開頭爲原點 
F.next() 返回下一行,並將文件操做標記位移到下一行。把一個file用於for ... in file這樣的語句時,就是調用

F.seek(offset[,whence]) 將文件打操做標記移到offset的位置。這個offset通常是相對於文件的開頭來計算的,通常爲正數。但若是提供了whence參數就不必定了,whence能夠爲0表示從頭開始計算,1表示以當前位置爲原點計算。2表示以文件末尾爲原點進行計算。須要注意,若是文件以a或a+的模式打開,每次進行寫操做時,

F.truncate([size]) 把文件裁成規定的大小,默認的是裁到當前文件操做標記的位置。若是size比文件的大小還要大,依據系統的不一樣多是不改變文件,也多是用0把文件補到相應的大小,也多是以一些隨機的內容加上去。若是沒有指定 size,則從當前位置起截斷;截斷以後 size 後面的全部字符被刪除

3.2 文件的讀取、建立、追加、刪除、清空
一,用python建立一個新文件,內容是0到9的整數,每一個數字佔一行學習

f = open('f.txt','w')
for i in range(0,10):
    f.write(str(i)+'\n')
f.close()

二,文件內容追加,從0到9的10個隨機整數

import random
f = open('f.txt','a')
for i in range(0,10):
    f.write(str(random.randint(0,9)))
f.write('\n')
f.close()

3、文件內容追加,從0到9的隨機整數, 10個數字一行,共10行

import random
f = open('f.txt','a')
for i in range(0,10):
    for i in range(0,10):
        f.write(str(random.randint(0,9)))
    f.write('\n')
f.close()

4、把標準輸出定向到文件

import sys
sys.stdout = open('stdout.txt','w')

五,文件的讀寫
5.1,文件打開

f = file(name[, mode[, buffering]])
name 文件名
mode   選項,字符串
buffering   是否緩衝 (0=不緩衝,1=緩衝, >1的int數=緩衝區大小)

文件的讀寫屬性
file對象有本身的屬性和方法。先來看看file的屬性。(+和b能夠和其餘的字符組合成mode,例如rb以二進制只讀方式打開,mode參數是可選的,若是沒有默認爲r)
(注意:文件打開以後,應當被及時關閉,能夠查看f.closed屬性以確認文件是否被關閉)

r 只讀模式(默認,文件不存在,則發生異常)文件的指針將會放在文件的開頭
w 只寫模式(可讀,文件不存在則建立,存在則刪除內容,再打開文件)
a 追加模式(只能寫,文件不存在則建立,存在則追加內容)
r+ 可讀寫模式(可讀,可寫,可追加),若是文件存在,則覆蓋當前文件指針所在位置的字符,如原來文件內容是"Hello,World",打開文件後寫入"hi"則文件內容會變成"hillo, World"
b 以二進制方式打開(如:FTP發送上傳ISO鏡像文件,linux可忽略,windows處理二進制文件時需標註)
w+ 先寫再讀(可讀,可寫,可追加) 若是該文件已存在則將其覆蓋。若是該文件不存在,建立新文件
a+ 同a(可讀可寫,文件不存在則建立,存在則追加內容)。若是該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。若是該文件不存在,建立新文件用於讀寫
rb 以二進制讀方式打開,只能讀文件 , 若是文件不存在,會發生異常
wb 以二進制寫方式打開,只能寫文件, 若是文件不存在,建立該文件
ab 二進制追寫文件。 從文件頂部讀取內容 從文件底部添加內容 不存在則建立
rt 以文本讀方式打開,只能讀文件 , 若是文件不存在,會發生異常
wt 以文本寫方式打開,只能讀文件 , 若是文件不存在,建立該文件。若是文件存在。先清空,再打開文件
at 以文本讀寫方式打開,只能讀文件 , 若是文件不存在,建立該文件。若是文件存在。先清空,再打開文件
rb+ 以二進制讀方式打開,能夠讀、寫文件 , 若是文件不存在,會發生異常  
wb+ 以二進制寫方式打開,能夠讀、寫文件, 若是文件不存在,建立該文件.若是文件存在。先清空,再打開文件
ab+ 追讀寫二進制。從文件頂部讀取內容 從文件底部添加內容 不存在則建立

5.2,關閉文件

f.close()

當文件讀寫完畢後,應關閉文件
六,清空文件內容

f.truncate()

注意:僅當以 "r+" "rb+" "w" "wb" "wb+"等以可寫模式打開的文件才能夠執行該功能
七,文件的指針定位與查詢
7.1,文件指針:

文件被打開後,其對象保存在 f 中, 它會記住文件的當前位置,以便於執行讀、寫操做,這個位置稱爲文件的指針( 一個從文件頭部開始計算的字節數 long 類型 )。

7.2,文件打開時的位置:

以"r"   "r+"   "rb+" 讀方式, "w"   "w+"   "wb+"寫方式 打開的文件,
 一開始,文件指針均指向文件的頭部

7.3,獲取文件指針的值:

L = f.tell()

7.4,移動文件的指針

f.seek(   偏移量, 選項 )
      選項 =0 時, 表示將文件指針指向從文件頭部到 "偏移量"字節處
      選項 =1 時, 表示將文件指針指向從文件的當前位置,向後移動 "偏移量"字節
      選項 =2 時, 表示將文件指針指向從文件的尾部,,向前移動 "偏移量"字節

八,從文件讀取內容
8.1,文本文件(以"rt"方式打開的文件)的讀取

s = f.readline()
        返回值: s 是字符串,從文件中讀取的一行,含行結束符
        說明: (1)  若是 len( s ) =0 表示已到文件尾
              (2)   若是是文件的最後一行,有可能沒有行結束符

8.2,二進制文件(以"rb"、"rb+"、"wb+" 方式打開的文件)的讀取

s = f.read( n )
     說明: (1)  若是 len( s ) =0 表示已到文件尾
           (2)   文件讀取後,文件的指針向後移動 len(s) 字節
          (3)若是磁道已壞,會發生異常

九,向文件寫入一個字符串

f.write( s )
    參數: s 要寫入的字符串
    說明: (1)文件寫入後,文件的指針向後移動 len(s) 字節
          (2)若是磁道已壞,或磁盤已滿會發生異常
返回值: s 是字符串,從文件中讀取的內容

十,刪除文件

import os
os.remove(file)

3.3 python逐行讀取文件內容的兩種方法
方法一:

for line in open('f.txt'):
    print(line)

方法二:

f =open('f.txt','r')
lines =f.readlines()
for i in lines:
    print(i)

3.4文件定位
  tell()方法告訴你文件內的當前位置, 換句話說,下一次的讀寫會發生在文件開頭這麼多字節以後
  seek(offset [,from])方法改變當前文件的位置。Offset變量表示要移動的字節數。From變量指定開始移動字節的參考位置
  offset -- 偏移量,也就是表明須要移動偏移的字節數,注意是按照字節算的,字符編碼存每一個字符所佔的字節長度不同
    如「好好學習」 用gbk存是2個字節一個字,用utf-8就是3個字節,所以以gbk打開時,seek(4) 就把光標切換到了「飛」和「學」兩個字中間。
    但若是是utf8,seek(4)會致使,拿到了飛這個字的一部分字節,打印的話會報錯,由於處理剩下的文本時發現用utf8處理不了了,由於編碼對不上了。少了一個字節
  若是from被設爲0,這意味着將文件的開頭做爲移動字節的參考位置
  若是設爲1,則使用當前的位置做爲參考位置
  若是它被設爲2,那麼該文件的末尾將做爲參考位置

例子:

#打開一個文件
f =open('f.txt','r+')
str_read = f.read(10)
print("讀取的字符串是:%s" % str_read)
 
#查找當前位置
position = f.tell()
print("當前位置: %s" %position)
 
#把指針再次從新定位到文件開頭
position =f.seek(0,0)
str_read =f.read(10)
print("從新讀取讀取的字符串是:%s" % str_read)
 
#關閉文件
f.close()
 
結果:
讀取的字符串是:2204513940
當前位置: 10
從新讀取讀取的字符串是:2204513940

3.5 重命名和刪除文件
Python的os模塊提供了幫你執行文件處理操做的方法,好比重命名和刪除文件。
要使用這個模塊,你必須先導入它,而後才能夠調用相關的各類功能。
rename()方法:
rename()方法須要兩個參數,當前的文件名和新文件名。
語法:

os.rename(current_file_name, new_file_name)

例子:

import os
#重命名文件f.txt問哦file.txt
os.rename('f.txt','file.txt')

remove方法
你能夠用remove()方法刪除文件,須要提供要刪除的文件名做爲參數。
語法:

os.remove(file_name)

例子:

import os
os.remove('stdout.txt')

3.6 文件修改
  硬盤的存儲原理就是,當你把文件存到硬盤上,就在硬盤上劃了一塊空間,存數據,等你下次打開這個文件,會seek到一個位置,每改一個字,就是把原來的覆蓋掉,若是要插入,是不可能的,由於後面的數據在硬盤上不會總體向後移動,因此就會出現當前這個狀況,你要插入,卻變成把舊內容覆蓋掉。
  因此修改文件,就不要在硬盤上修改,把內容所有讀到內存裏,數據在內存裏能夠隨便增刪改查,修改以後,把內容所有寫回硬盤,把原來的數據所有覆蓋掉。
  固然了,若是有些文件特別大,好比5G,那麼一下吃掉這麼大內存,很是浪費資源,因此更好的方法就是,若是不像佔內存,那麼就邊讀邊寫,也就是不修改源文件,可是能夠打開丟文件的同時,生成一個新文件,邊從舊的裏面讀,邊往新的裏面寫,遇到須要修改的就改了再寫道新文件,這樣在內存裏面一直只存一行內容,就不佔內存了,可是也有一個缺點就是,雖然不佔內存,可是佔硬盤,每次修改,都要生成一份新文件,雖然改完後,能夠把舊的覆蓋掉,可是在改的過程當中,仍是有兩份數據
3.6.1文件修改佔硬盤
代碼:

f_name= 'file.txt'
f_new_name = 'file_new.txt'
old_str = '123'
new_str = '123123123'
f = open(f_name,'r',encoding='gbk')
f_new = open(f_new_name,'w',encoding='gbk')
for line in f:
    if old_str in line:
        line = line.replace(old_str,new_str)
    f_new.write(line)
f.close()
f_new.close()

上面的代碼會生成一個修改後的新文件,源文件不動,若想覆蓋源文件
代碼以下:

import os
os.replace(file_new_name,file_name)

3.6.2文件修改佔內存
  這樣不須要佔用兩個文件,只須要寫一個文件,直接r+就能夠,可是會出現一個問題,就是要是之前文件內容多,如今少了,那會出錯,爲了不這種錯誤的發生,使用truncate()就ok
userinfo.txt的內容:

1:www.baidu.com
2:www.google.com
3:www.tencent.com
4:www.tianmao.com
5:www.jingdong.com
f.truncate([size])
把文件裁成規定的大小,默認的是裁到當前文件操做標記的位置。
若是size比文件的大小還要大,依據系統的不一樣多是不改變文件,
也多是用0把文件補到相應的大小,也多是以一些隨機的內容加上去
file = open('userinfo.txt','r+',encoding='utf-8')
print('文件名爲:',file.name)
 
line =file.readline()
print('讀取第一行:%s' %line)
 
#截斷剩下的字符串
file.truncate()
 
#嘗試再次讀取數據
line =file.readline()
print('讀取數據:%s' %line)
 
file.close()
 
# 結果:
# 文件名爲: userinfo.txt
# 讀取第一行:1:www.baidu.com
#
# 讀取數據:2:www.google.com
file = open('userinfo.txt','r+',encoding='utf-8')
print('文件名爲:',file.name)
 
line =file.readline()
print('讀取第一行:%s' %line)
 
#截斷10的字符串
file.truncate(10)
 
#嘗試再次讀取數據
line =file.readline()
print('讀取數據:%s' %line)
 
file.close()
 
結果:
文件名爲: userinfo.txt
讀取第一行:1:www.baid
讀取數據:

四,補充內容
4.1 各類系統操做
  注意:雖然python中提供了各類拼接目錄的函數,可是,函數並不能保證字符編碼不出問題,很大可能致使程序錯誤。因此最好仍是本身拼接。

  python中對文件、文件夾(文件操做函數)的操做須要涉及到os模塊和shutil模塊

獲得當前工做目錄,即當前Python腳本工做的目錄路徑: os.getcwd()
 
返回指定目錄下的全部文件和目錄名:os.listdir()
 
函數用來刪除一個文件:os.remove()
 
刪除多個目錄:os.removedirs(r「c:\python」)
 
檢驗給出的路徑是不是一個文件:os.path.isfile()
 
檢驗給出的路徑是不是一個目錄:os.path.isdir()
 
判斷是不是絕對路徑:os.path.isabs()
 
檢查是否快捷方式os.path.islink ( filename )
 
檢驗給出的路徑是否真地存:os.path.exists()
 
返回一個路徑的目錄名和文件名:os.path.split() eg os.path.split('/home/swaroop/byte/code/poem.txt') 結果:('/home/swaroop/byte/code', 'poem.txt')
 
分離擴展名:os.path.splitext()
 
獲取路徑名:os.path.dirname()
 
獲取文件名:os.path.basename()
 
運行shell命令: os.system()
 
讀取和設置環境變量:os.getenv() 與os.putenv()
 
給出當前平臺使用的行終止符:os.linesep Windows使用'\r\n',Linux使用'\n'而Mac使用'\r'
指示你正在使用的平臺:os.name 對於Windows,它是'nt',而對於Linux/Unix用戶,它是'posix'
重命名:os.rename(old, new)
建立多級目錄:os.makedirs(r「c:\python\test」)
 
建立單個目錄:os.mkdir(「test」)
 
獲取文件屬性:os.stat(file)
 
修改文件權限與時間戳:os.chmod(file)
 
終止當前進程:os.exit()
 
獲取文件大小:os.path.getsize(filename)

4.2 各類目錄操做

os.mkdir("file") 建立目錄
 
複製文件:
shutil.copyfile("oldfile","newfile") oldfile和newfile都只能是文件
shutil.copy("oldfile","newfile") oldfile只能是文件夾,newfile能夠是文件,也能夠是目標目錄
 
複製文件夾:
shutil.copytree("olddir","newdir") olddir和newdir都只能是目錄,且newdir必須不存在
 
重命名文件(目錄)
os.rename("oldname","newname") 文件或目錄都是使用這條命令
 
移動文件(目錄)
shutil.move("oldpos","newpos")
 
刪除文件
os.remove("file")
 
刪除目錄
os.rmdir("dir")只能刪除空目錄
shutil.rmtree("dir") 空目錄、有內容的目錄均可以刪
 
轉換目錄
os.chdir("path") 換路徑
  
ps: 文件操做時,經常配合正則表達式:
img_dir = img_dir.replace('\\','/')

五,文件處理習題
  文件操做分爲讀,寫,修改

5.1 讀文件
舉例以下:

f = open(file=‘userinfo.txt',mode='r',encoding='utf-8')
 
data = f.read()
 
f.close()

上述操做語法解釋以下:

file=‘userinfo.txt'  表示文件路徑
mode='r'                                          表示只讀(能夠修改成其餘)
encoding='utf-8'                                  表示將硬盤上的 0101010 按照utf-8的規則去「斷句」,
    再將「斷句」後的每一段0101010轉換成unicode的 01010101,unicode對照表中有01010101和
    字符的對應關係。
f.read()                                          表示讀取全部內容,內容是已經轉換完畢的字符串。
f.close()                                         表示關閉文件

再看一個例子:

f = open(file='userinfo.txt',mode='rb')
data = f.read()
f.close()

上述操做語法解釋:

file='userinfo.txt'      表示文件路徑
mode='rb'                                            表示只讀(能夠修改成其餘)
f.read()                                             表示讀取全部內容,內容是硬盤上原來以某種編碼保存010101010,即:某種編碼格式的字節類型
f.close()                                            表示關閉文件

問:兩個例子的區別在哪?

  答:在於示例2打開文件時並未指定encoding,這是爲什麼?是由於直接以rb模式打開了文件 ,rb是指二進制模式,數據讀到內存裏直接是bytes格式,若是想內容,還須要手動decode,所以在文件打開階段,不須要指定編碼

  問:假設你不知道你要處理的文件是什麼編碼可怎麼辦?

import chardet
 
f = open('log',mode='rb')
data = f.read()
f.close()
 
result = chardet.detect(open('log',mode='rb').read())
print(result)

輸出:

{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}

注意:

文件操做時,以 「r」或「rb」 模式打開,則只能讀,沒法寫入;
硬盤上保存的文件都是某種編碼的0101010,打開時須要注意:
rb,直接讀取文件保存時原生的0101010,在Python中用字節類型表示
r和encoding,讀取硬盤的0101010,並按照encoding指定的編碼格式進行斷句,再將「斷句」後的每一段0101010轉換成unicode的 010101010101,在Python中用字符串類型表示

5.2文件操做的其餘功能

def fileno(self, *args, **kwargs): # real signature unknown
       返回文件句柄在內核中的索引值,之後作IO多路複用時能夠用到
 
   def flush(self, *args, **kwargs): # real signature unknown
       把文件從內存buffer裏強制刷新到硬盤
 
   def readable(self, *args, **kwargs): # real signature unknown
       判斷是否可讀
 
   def readline(self, *args, **kwargs): # real signature unknown
       只讀一行,遇到\r or \n爲止
 
   def seek(self, *args, **kwargs): # real signature unknown
       把操做文件的光標移到指定位置
       *注意seek的長度是按字節算的, 字符編碼存每一個字符所佔的字節長度不同。
       如「路飛學城」 用gbk存是2個字節一個字,用utf-8就是3個字節,所以以gbk打開時,seek(4) 就把光標切換到了「飛」和「學」兩個字中間。
       但若是是utf8,seek(4)會致使,拿到了飛這個字的一部分字節,打印的話會報錯,由於處理剩下的文本時發現用utf8處理不了了,由於編碼對不上了。少了一個字節
 
   def seekable(self, *args, **kwargs): # real signature unknown
       判斷文件是否可進行seek操做
 
   def tell(self, *args, **kwargs): # real signature unknown
       返回當前文件操做光標位置
 
   def truncate(self, *args, **kwargs): # real signature unknown
       按指定長度截斷文件
       *指定長度的話,就從文件開頭開始截斷指定長度,不指定長度的話,就從當前位置到文件尾部的內容全去掉。
 
   def writable(self, *args, **kwargs): # real signature unknown
       判斷文件是否可寫

5.3 例題
讀文件找到第9個字符,華 ,找到第二行的 實,刪除最後一行 寫入文件
桃之夭夭,灼灼其華。之子于歸,宜其室家。
桃之夭夭,有蕡其實。之子于歸,宜其家室。
桃之夭夭,其葉蓁蓁。之子于歸,宜其家人。

# 2.讀文件找到第9個字符,華 ,找到第二行的 實,刪除最後一行 寫入文件
# 桃之夭夭,灼灼其華。之子于歸,宜其室家。
# 桃之夭夭,有蕡其實。之子于歸,宜其家室。
# 桃之夭夭,其葉蓁蓁。之子于歸,宜其家人。
 
f = open('poem.txt', 'r+', encoding='utf-8')
# f.seek(3*8)
# print(f.read(1))
# f.seek(3*28+2)
# print(f.read(1))
data_list = f.readlines()
print(data_list)
data_list.pop()
print(data_list)
f.seek(0)
f.truncate()
f.write(''.join(data_list))

5.4 例題:讀取一個文件下的全部文件

import  os
 
def read_image(image_dir):
    photofile_list = os.listdir(image_dir)
    for i in range(len(photofile_list)):
        photo_path = os.path.join(image_dir,photofile_list[i])
        print(photo_path)

5.5 例題:斷定目錄是否存在,若不存在即建立

import os
if not os.path.isdir(dir_name):
    os.makedir(dir_name)

os.mkdir()建立路徑中的最後一級目錄,而若是以前的目錄不存在而且也須要建立的話,就會報錯。

os.makedirs()建立多層目錄,若是中間目錄都不存在的話,會自動建立。

5.6 讀取文件的行數

import csv
a=open("Train_A_wear.csv","r")
b=len(a.readlines())
print(b)

5.7 批量重命名文件名

import os
 
class BatchRename():
    # 批量重命名文件夾中的圖片文件
    def __init__(self):
        self.path_A = '../binary_variable/A'
        self.path_B = '../binary_variable/B'
 
 
    def rename(self):
        filelist_A = os.listdir(self.path_A)
        filelist_B = os.listdir(self.path_B)
        total_num_A = len(filelist_A)
        total_num_B = len(filelist_B)
        i = 1
        for item in filelist_A:
            # 初始的圖片的格式爲jpg格式的,或者png
            if item.endswith('.jpg') or item.endswith('png'):
                src = os.path.join(os.path.abspath(self.path_A), item)
                # 處理後的格式也爲jpg格式的,固然這裏也能夠改爲png格式
                dst = os.path.join(os.path.abspath(self.path_A), str(i) + '.jpg')
 
                try:
                    os.rename(src, dst)
                    i = i + 1
                except:
                    continue
 
        for item in filelist_B:
            # 初始的圖片的格式爲jpg格式的,或者png
            if item.endswith('.jpg') or item.endswith('png'):
                src = os.path.join(os.path.abspath(self.path_B), item)
                # 處理後的格式也爲jpg格式的,固然這裏也能夠改爲png格式
                dst = os.path.join(os.path.abspath(self.path_B), str(i) + '.jpg')
 
                try:
                    os.rename(src, dst)
                    i = i + 1
                except:
                    continue
 
if __name__ == '__main__':
    demo = BatchRename()
    demo.rename()

不經一番徹骨寒 怎得梅花撲鼻香

相關文章
相關標籤/搜索