pathlib 自 Python 3.4 以后成為了 Python 的標(biāo)準(zhǔn)庫(kù)以躯,該庫(kù)非常的好用,大大簡(jiǎn)化了目錄的管理刁标。但也有一些不足膀懈,可以對(duì)其進(jìn)行擴(kuò)展斩箫,使其更加好用。
擴(kuò)展的代碼
# 項(xiàng)目:standard python lib
# 模塊:path and file
# 作者:黃濤
# License:GPL
# Email:huangtao.sh@icloud.com
# 創(chuàng)建:2016-03-11 12:21
# 修改:2016-04-13 21:01
# 修改:2016-08-13 新增__iter__ 和 extractall功能
# 修訂:2016-11-19 修改Path的實(shí)現(xiàn)方式
import pathlib
import os
from codecs import BOM_UTF8,BOM_LE,BOM_BE
from .click import *
BOM_CODE={
BOM_UTF8:'utf_8',
BOM_LE:'utf_16_le',
BOM_BE:'utf_16_be',
}
DEFAULT_CODES='utf8','gbk','utf16','big5'
def is_installed(file_name):
'''
確認(rèn)指定的文件是否已被安裝狐血。
'''
from sysconfig import get_path
paths=[get_path(name) for name in ('platlib','scripts')]
if os.name=='nt':
file_name=file_name.lower()
paths=[path.lower() for path in paths]
return any([file_name.startswith(path) for path in paths])
def is_dev(cmd=None):
import sys
cmd=cmd or sys.argv[0]
if('wsgi' in cmd):
return False
return 'test' in cmd or (not is_installed(cmd))
def decode(d):
'''
對(duì)指定的二進(jìn)制易核,進(jìn)行智能解碼,適配適當(dāng)?shù)木幋a缀匕。返回解碼后的字符串乡小。
'''
for k in BOM_CODE:
if k==d[:len(k)]:
return d[len(k):].decode(BOM_CODE[k])
for encoding in DEFAULT_CODES:
try:
return d.decode(encoding)
except:
pass
raise Exception('解碼失敗')
_Parent= pathlib.WindowsPath if os.name=='nt' else pathlib.PosixPath
class Path(_Parent):
__slots__=()
def __new__(cls,path='.',*args,**kwargs):
if isinstance(path,str):
if path.startswith('~'): # 支持用戶目錄開(kāi)頭
path=os.path.expanduser(path)
elif path.startswith('%'): # 支持環(huán)境變量轉(zhuǎn)義
path=os.path.expandvars(path)
return super().__new__(cls,path,*args,**kwargs)
def read(self,*args,**kwargs):
'''以指定的參數(shù)讀取文件'''
with self.open(*args,**kwargs)as fn:
return fn.read()
def ensure(self,parents=True):
'''確保目錄存在满钟,如果目錄不存在則直接創(chuàng)建'''
if not self.exists():
self.mkdir(parents=parents)
@property
def text(self):
'''讀取文件湃番,并返回字符串'''
return decode(self.read('rb'))
@text.setter
def text(self,text):
'''寫入文本文件'''
self.write(text=text)
@property
def lines(self):
'''按行讀取文件'''
return self.text.splitlines()
@lines.setter
def lines(self,lines):
'''按行寫入文件'''
self.write(*lines)
def write(self,*lines,text=None,data=None,encoding='utf8',
parents=False):
'''寫文件'''
if parents:
self.parent.ensure()
if lines:
text="\n".join(lines)
if text:
data=text.encode(encoding)
if data:
with self.open('wb')as fn:
fn.write(data)
def sheets(self,index=None):
''' 提供讀取指定worksheet的功能,其中index可以為序號(hào)尊惰,
也可以為表的名稱泥兰。'''
import xlrd
book=xlrd.open_workbook(filename=str(self))
if isinstance(index,int):
sheet=book.sheet_by_index(index)
elif isinstance(index,str):
sheet=book.sheet_by_name(index)
return sheet and sheet._cell_values
def iter_sheets(self):
'''如果指定的文件為excel文件逾条,則可以迭代讀取本文件的數(shù)據(jù)。
返回:表的索引担孔、表名糕篇、數(shù)據(jù)'''
import xlrd
book=xlrd.open_workbook(filename=str(self))
for index,sheet in enumerate(book.sheets()):
yield index,sheet.name,sheet._cell_values
@property
def xmlroot(self):
'''如果指定的文件為xml文件酌心,則返回本文件的根元素'''
import lxml.etree
return lxml.etree.parse(str(self)).getroot()
def __iter__(self):
'''根據(jù)文件的不同安券,迭代返回不同的內(nèi)容。支持如下文件:
1鹦筹、文本文件址貌,按行返回文本
2、Excel文件遍蟋,返回表索引虚青、表名及表中數(shù)據(jù)
3、目錄钟些,則返回本目錄下所有文件
4绊谭、del文件达传,按行返回?cái)?shù)據(jù)迫筑。
5脯燃、csv文件,按行返回?cái)?shù)據(jù)欲主。
'''
if self.is_dir():
return self.glob('*')
suffix=self.lsuffix
if suffix.startswith('.xls'):
return self.iter_sheets()
elif suffix=='.xml':
return self.xmlroot.iterchildren()
elif suffix=='.del':
import re
none_pattern=re.compile(",(?=,)")
for line in self.lines:
if line:
yield eval(none_pattern.sub(",None",line))
elif suffix=='.csv':
import csv
with self.open() as fn:
yield from csv.reader(fn)
def extractall(self,path='.',members=None):
'''如本文件為tar打包文件扁瓢,則解壓縮至指定目錄'''
import tarfile
path=str(Path(path))
tarfile.open(str(self),'r').extractall(path,members)
@property
def lsuffix(self):
'''返回小寫的擴(kuò)展名'''
return self.suffix.lower()
@property
def pname(self):
'''返回不帶擴(kuò)展名的文件名'''
return self.with_suffix("").name
def rmtree(self):
'''刪除整個(gè)目錄'''
import shutil
shutil.rmtree(str(self))
def chdir(self):
if self.is_dir():
os.chdir(str(self))
@command(description='Windows 格式文件轉(zhuǎn)換為 Unix 文件格式')
@arg('files',nargs='*',help='待轉(zhuǎn)換的文件',metavar='file')
def convert(files):
for file in files:
Path(file).lines=Path(file).lines
print('轉(zhuǎn)換文件"%s"成功'%(file))
新增功能介紹
支持家目錄及目錄擴(kuò)展
支持自動(dòng)對(duì)目錄進(jìn)行擴(kuò)展引几,如果目錄中包含 "~"
或"%appdata%"
等內(nèi)容時(shí)挽铁,系統(tǒng)會(huì)自動(dòng)進(jìn)行擴(kuò)展。其好處是顯而意見(jiàn)的楣铁,如果不同操作系統(tǒng)的文件都放在相同的目錄民褂,那么我們不就用去管操作系統(tǒng)的差異。其使用代碼如下:
import os
print(Path('~/abc')
if os.name!='posix':
print(Path('%appdata%/abc')
增加 read 方法
用于讀取指定的文件面殖,其參數(shù)為open
所需要的參數(shù)哭廉。代碼示例如下:
fn=Path('~/abc.txt')
s=fn.read()
print(s)
增加 ensure 方法
對(duì)指定的目錄的進(jìn)行檢查遵绰,如指定的目錄不存在,則自動(dòng)創(chuàng)建乌企。代碼示例如下:
Path('~/abc').ensure()
增加 text 屬性
該屬性用于讀寫文本文件的內(nèi)容加酵。示例代碼如下:
Path('~/a.txt').text='This is a test.\nHello world.\n'
print(Path('~/a.txt').text)
** 注:文本文件在讀取時(shí),其編碼可以由系統(tǒng)自動(dòng)進(jìn)行只別哭当;寫入時(shí)編碼為 UTF8 猪腕。**
增加 lines 屬性
該屬性以行的方式讀取或?qū)懭胛谋尽4a如下:
lines=['This is a test.',
'Hello world']
Path('~/a.txt').lines=lines
print(*(Path('~/a.txt').lines),sep='\n')
增加 write 方法
寫入文件钦勘,可以按行寫入陋葡,按文本寫入、或直接寫數(shù)據(jù)彻采。示例代碼如下:
lines=['This is a test.',
'Hello world']
Path('~/a.txt').wreite(*lines)
print(*(Path('~/a.txt').lines),sep='\n')
增加 sheets 方法
如果指定的文件為 Excel 文件腐缤,根據(jù)工作表的名字或索引讀取該工作表的數(shù)據(jù)。示例代碼如下:
data=Path('~/abc.xlsx').sheets(0)
data=Path('~/abc.xls').sheets('Sheet1')
增加 iter_sheets 方法
for idx,name,data in Path('~/abc.xls').iter_sheets():
print(name,idx)
增加 xmlroot 屬性
如指定文件為 xml 文件肛响,則返回該文件的根元素柴梆。
for i in Path('a.xml').xlmroot:
print(i.tag)
增加 __iter__ 方法
根據(jù)指定目錄或文件的不同返回不同的內(nèi)容:
- 目錄终惑,則返回當(dāng)前目錄下所有的文或目錄绍在。示例代碼如下:
for d in Path('.'):
print(d)
- Excel文件,返回索引雹有、表名及表中的數(shù)據(jù)偿渡。示例代碼如下:
for idx,name,data in Path('~/abc.xlsx'):
print(idx,name)
- txt文本文件。則按行返回?cái)?shù)據(jù)霸奕。示例代碼如下:
for line in Path('a.txt'):
print(line)
增加 lsuffix 只讀屬性
返回指定文件的小寫擴(kuò)展名溜宽,便于判斷文件的類型。示例代碼如下:
if Path(filename).lsuffix in ('.xls','.xlsx','.xlsm'):
print('Excel 文件')
增加 pname 只讀屬性
返回指定文件的文件名(不含擴(kuò)展名)质帅。示例代碼如下:
print(Path('~/abc/def.txt').pname)
增加 chdir 方法
將指定的目錄作為當(dāng)前工作目錄适揉。示例代碼如下:
Path('~/SendTo').chdir()
增加 rmtree 方法
將指定的目錄全部刪除留攒。示例代碼如下:
Path('~/test').rmtree()