pathlib 自 Python 3.4 以后成为了 Python 的标准库,该库非常的好用,大大简化了目录的管理。但也有一些不足,可以对其进行扩展,使其更加好用。
扩展的代码
# 项目:standard python lib
# 模块:path and file
# 作者:黄涛
# License:GPL
# Email:[email protected]
# 创建:2016-03-11 12:21
# 修改:2016-04-13 21:01
# 修改:2016-08-13 新增__iter__ 和 extractall功能
# 修订:2016-11-19 修改Path的实现方式
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):
'''
确认指定的文件是否已被安装。
'''
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):
'''
对指定的二进制,进行智能解码,适配适当的编码。返回解码后的字符串。
'''
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('~'): # 支持用户目录开头
path=os.path.expanduser(path)
elif path.startswith('%'): # 支持环境变量转义
path=os.path.expandvars(path)
return super().__new__(cls,path,*args,**kwargs)
def read(self,*args,**kwargs):
'''以指定的参数读取文件'''
with self.open(*args,**kwargs)as fn:
return fn.read()
def ensure(self,parents=True):
'''确保目录存在,如果目录不存在则直接创建'''
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可以为序号,
也可以为表的名称。'''
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文件,则可以迭代读取本文件的数据。
返回:表的索引、表名、数据'''
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):
'''根据文件的不同,迭代返回不同的内容。支持如下文件:
1、文本文件,按行返回文本
2、Excel文件,返回表索引、表名及表中数据
3、目录,则返回本目录下所有文件
4、del文件,按行返回数据。
5、csv文件,按行返回数据。
'''
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):
'''返回小写的扩展名'''
return self.suffix.lower()
@property
def pname(self):
'''返回不带扩展名的文件名'''
return self.with_suffix("").name
def rmtree(self):
'''删除整个目录'''
import shutil
shutil.rmtree(str(self))
def chdir(self):
if self.is_dir():
os.chdir(str(self))
@command(description='Windows 格式文件转换为 Unix 文件格式')
@arg('files',nargs='*',help='待转换的文件',metavar='file')
def convert(files):
for file in files:
Path(file).lines=Path(file).lines
print('转换文件"%s"成功'%(file))
新增功能介绍
支持家目录及目录扩展
支持自动对目录进行扩展,如果目录中包含 "~"
或"%appdata%"
等内容时,系统会自动进行扩展。其好处是显而意见的,如果不同操作系统的文件都放在相同的目录,那么我们不就用去管操作系统的差异。其使用代码如下:
import os
print(Path('~/abc')
if os.name!='posix':
print(Path('%appdata%/abc')
增加 read 方法
用于读取指定的文件,其参数为open
所需要的参数。代码示例如下:
fn=Path('~/abc.txt')
s=fn.read()
print(s)
增加 ensure 方法
对指定的目录的进行检查,如指定的目录不存在,则自动创建。代码示例如下:
Path('~/abc').ensure()
增加 text 属性
该属性用于读写文本文件的内容。示例代码如下:
Path('~/a.txt').text='This is a test.\nHello world.\n'
print(Path('~/a.txt').text)
** 注:文本文件在读取时,其编码可以由系统自动进行只别;写入时编码为 UTF8 。**
增加 lines 属性
该属性以行的方式读取或写入文本。代码如下:
lines=['This is a test.',
'Hello world']
Path('~/a.txt').lines=lines
print(*(Path('~/a.txt').lines),sep='\n')
增加 write 方法
写入文件,可以按行写入,按文本写入、或直接写数据。示例代码如下:
lines=['This is a test.',
'Hello world']
Path('~/a.txt').wreite(*lines)
print(*(Path('~/a.txt').lines),sep='\n')
增加 sheets 方法
如果指定的文件为 Excel 文件,根据工作表的名字或索引读取该工作表的数据。示例代码如下:
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__ 方法
根据指定目录或文件的不同返回不同的内容:
- 目录,则返回当前目录下所有的文或目录。示例代码如下:
for d in Path('.'):
print(d)
- Excel文件,返回索引、表名及表中的数据。示例代码如下:
for idx,name,data in Path('~/abc.xlsx'):
print(idx,name)
- txt文本文件。则按行返回数据。示例代码如下:
for line in Path('a.txt'):
print(line)
增加 lsuffix 只读属性
返回指定文件的小写扩展名,便于判断文件的类型。示例代码如下:
if Path(filename).lsuffix in ('.xls','.xlsx','.xlsm'):
print('Excel 文件')
增加 pname 只读属性
返回指定文件的文件名(不含扩展名)。示例代码如下:
print(Path('~/abc/def.txt').pname)
增加 chdir 方法
将指定的目录作为当前工作目录。示例代码如下:
Path('~/SendTo').chdir()
增加 rmtree 方法
将指定的目录全部删除。示例代码如下:
Path('~/test').rmtree()