文件操作
文件操作
文件操作
冯诺依曼体系架构
CPU由控制器和运算器组成.
运算器: 完成各种算数运算,逻辑运算,数据传输等数据加工处理;
控制器: 控制程序的执行;
存储器: 用于记忆程序和数据,例如内存等;
输入设备: 将数据或者程序输入到计算机中,例如键盘,鼠标等;
输出设备: 将数据或程序的处理结果展示给用户,例如显示器,打印机等.
一般的IO操作, 指文件IO, 如果指的是网络IO,都会直接说网络IO.
文件操作
文件IO常用操作:
open, read, write, close
readline: 行读取;
readlines: 多行读取;
seek: 文件指针操作;
tell: 指针位置.
打开操作:
open(file, mode='r', buffering=-1, encoding=None, newline=None, closefd=True, opener=None)
打开一个文件,返回一个文件对象(流对象)和文件描述符,打开文件失败,则返回异常.
文件操作中, 最常用的操作就是读和写.
文件访问的模式有两种: 文本模式和和二进制模式, 不同模式,操作函数不同,表现结果也不一样.
open操作的参数:
file: 打开或者要创建的文件名, 如果不指定路径,默认是当前路径.
mode模式:
r: 缺省,表示只读打开, 文件不存在或使用write方法, 会抛异常.
w: 只写打开,读取则抛异常,文件不存在则创建,反之清空文件内容.
x: 创建并写入一个新文件,只读方式打开, 文件存在则抛异常.
a: 写入打开,文件存在则追加;
b: 二进制模式; 将文件按字节理解,与字符编码无关,二进制模式操作时,字节操作使用bytes类型.
t: 缺省的,文本模式,字符流,将文件字节按某种字符编码理解,按字符操作,open的默认mode是rt.
+: 读写打开一个文件, 给原来只读,只写文件打开提供缺失的读或写的功能,不能单独使用.
rb 二进制文件
w或wt 文本模式写,打开前文件存储被清空;
wb 二进制写,文件存储同样被清空;
a+ 可读写模式,写只能写在文件末尾;
w+ 可读写,与a+的区别是要清空文件内容;
r+ 可读写,与a+的区别是可以写到文件任何位置;
文件指针:
mode=r, 指针起始在0;
mode=a, 指针起始在EOF;
tell(), 显示指针当前位置.
seek(offset[, whence])
移动文件指针位置. offset偏移多少字节, whence从哪里开始.
文本模式下:
whence 0 缺省值,表示从头开始, offset只能是正整数.
whence 1 表示从当前位置, offset只接受0.
whence 2 表示从EOF开始,offset只接受0.
二进制模式下:
whence 0 缺省值, 表示从头开始, offset只能是正整数.
whence 1 表示从当前位置, offset可正可负.
whence 2 表示从EOF开始, offset可正可负.
二进制模式支持任意起点的偏移,从头,从尾,从中间位置开始.
向后seek可以超界,但是向前seek的时候,不能超界,否则抛异常.
bufferint: 缓冲区
-1表示使用缺省大小的buffer.如果是二进制模式,使用io.DEFAULT_BUFFER_SIZE值,默认是4096或者8192.如果是文本模式/终端设备,是行缓存方式,反之则使用二进制模式策略.
0只在二进制模式使用,表示关buffer.
1只在文本模式使用,表示使用行缓冲,意思是见到换行符就flush.
大于1用于指定buffer的大小.
buffer缓存区:
缓冲区一个内存空间,一般来说是一个FIFO队列,到缓冲区满了或达到阈值,数据才会flush到磁盘.
flush()将缓冲区数据写入磁盘.
close()关闭前会调用flush().
io.DEFAULT_BUFFER_SIZE缺省缓冲区大小,字节.
总结:
1, 文本模式,一般都用默认缓冲区大小;
2, 二进制模式,是一个个字节的操作,可以指定buffer的大小;
3, 一般,默认缓冲区大小是个比较好的选择,除非明确知道,否则不调用它;
4, 一般编程中,明确知道需要写磁盘了,都会手动调用一次flush,而不是等到自动flush或者close的时候.
encoding:编码, 仅文本模式使用.
encoding表示的是返回的数据采用何种编码,一般采用utf8或者gbk;
Nome表示使用缺省编码,依赖操作系统.
其他参数:
errors: 什么样的编码错误将被捕获.
None和strict表示有编码错误将抛出ValueError异常; ignore表示忽略.
newline: 文本模式中,换行的转换. 可以为None, '', '\r', '\n', '\r\n'.
读时, None表示'\r', '\n', '\r\n'都会被转换成'\n'; ''表示不会自动转换通用换行符;其他合法字符表示换行符就是指定字符,就会按照指定字符分行.
写时, None表示'\n'都会被替换为系统缺省分隔符os.sleep; '\n'或表示'\n'不替换; 其他合法字符表示'\n'会被替换为指定的字符.
closefd: 关闭文件描述符,True表示关闭它, False会在文件关闭后保持这个描述符.
fileobj.fileno() 查看.
read:
read(size = -1)
size表示读取的多少个字符或字节; 负数或者None表示读取到EOF.
行读取:
readline(size = -1)
一行行读取文件内容. size设置一次能读取行内几个字符或字节;
readlines(hint = -1)
读取所有行的列表, 指定hint则返回指定的行数.
write:
write(s), 把字符串s写入到文件中并返回字符的个数;
flush:
将文件写入到硬盘.
close:
flush并关闭文件对象;
文件已经关闭, 再次关闭没有任何效果.
其他:
seekable(), 是否可seek.
readable(), 是否可读写.
writeable(), 是否可写.
closed(), 是否已经关闭.
上下文管理:
问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Linux下执行: (env353) [ames@ames python3.5.3]$ ipython3 Python 3.5.3 (default, Sep 11 2017, 14:06:47) Type 'copyright', 'credits' or 'license' for more information IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: lst = []
In [2]: for _ in range(100000): ...: lst.append(open('test')) ...: --------------------------------------------------------------------------- OSError Traceback (most recent call last) <ipython-input-2-dbd507030346> in <module>() 1 for _ in range(100000): ----> 2 lst.append(open('test')) 3
OSError: [Errno 24] Too many open files: 'test'
In [3]: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
(env353) [ames@ames python3.5.3]$ lsof -p 1399 | grep test | wc -l 0 (env353) [ames@ames python3.5.3]$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 7283 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 65535 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 7283 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited (env353) [ames@ames python3.5.3]$ |
解决办法:
1, 异常处理:
当出现异常时,拦截异常,但是因为很多代码都可能出现OSError异常,不好判断异常就是因为资源限制产生的.
使用finally可以保证打开的文件可以被关闭.
1 2 3 4 5 |
f = open('test'): try: f.write('abc') # 文件只读,写入失败. finally: f.close() # 这样才行. |
2, 上下文管理:
一种特殊的语法,交给解释器去释放文件对象.
上下文管理:
1, 使用with ... as关键字.
2, 上下文管理的语句并不会开启新的作用域.
3, with语句执行完时,会自动关闭文件对象.
另一种写法:
1 2 3 4 5 6 |
f1 = open('test') with f1: f1.write('abc') # 文件只读, 写入失败.
# 测试f是否关闭. f1.closed # f1的作用域. |
对于类似于文件对象的IO对象,一般来说都需要在不使用时关闭,注销,以释放资源. IO被打开时,会获得一个文件描述符. 计算机资源有限,所以操作系统都会做限制.
就是为了保护计算机的资源不要被完全耗尽,计算资源是共享的,非独占. 一般情况下,除非特别明确知道资源情况,否则不要提高资源的限制值来解决此类问题
StringIO和BytesIO
StringIO:
IO模块中的类: from io import StringIO
内存中,开辟一个文本模式的buffer,可以像文件对象一样操作它.
当close方法被调用时,这个buffer会被释放.
StringIO操作:
getvalue()获取全部内容,跟文件指针没有关系.
1 2 3 4 5 6 7 8 |
from io import StringIO # 内存中构建. sio = StringIO() # 像文件对象一样操作. print(sio.readable(), sio.writable(), sio.seekable()) sio.seek(0) print(sio.readline()) print(sio.getvalue()) # 无视指针,输出全部内容. sio.close() |
StringIO好处:
一般来说,磁盘操作比内存操作要慢很多,内存足够情况下,一般的优化思路是少落地,减少磁盘IO的过程,可以大大提高程序的运行效率.
BytesIO:
io模块中的类: from io import BytesIO
内存中,开辟一个二进制模式的buffer,可以像文件对象一样操作它.
当close方法被调用时,这个buffer会被释放.
bytesIO操作:
1 2 3 4 5 6 7 8 |
from io import BytesIO # 内存中构建.
bio = BytesIO() print(bio.readable(), bio.writable(), bio.seekable()) bio.seek(0) print(bio.readline()) print(bio.getvalue()) # 无视指针,输出全部内容. bio.close() |
file-like对象:
类文件对象, 可以像文件对象一样操作;
socket对象, 输入输出对象(stdin, stdout)都是类文件对象.
1 2 3 4 |
from sys import stdout f = stdout print(type(f)) f.write('python') |
路径操作
3.4版本开始, 建议使用pathlib模块, 提供Path对象来操作, 包括目录和文件.
pathlib模块: from pathlib import Path
目录操作:
初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
In [2]: from pathlib import Path
In [3]: p = Path() # 等同于 p = Path('.')
In [4]: p Out[4]: PosixPath('.')
In [5]: p = Path('a', 'b', 'c/d')
In [6]: p Out[6]: PosixPath('a/b/c/d')
In [7]: p = Path('/etc')
In [8]: p Out[8]: PosixPath('/etc')
In [9]: |
路径拼接和分解:
操作符: '/'
Path对象/Path对象.
Path对象/字符串 或者 字符串/Path对象.
分解:
parts属性,可以返回路径中的每一个部分;
joinpath:
joinpath(*other) 连接多个字符串到Path对象中;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
In [9]: p = Path()
In [10]: p = p / 'a'
In [11]: p Out[11]: PosixPath('a')
In [12]: p1 = 'b' / p
In [13]: p1 Out[13]: PosixPath('b/a')
In [14]: p2 = Path('c')
In [15]: p2 Out[15]: PosixPath('c')
In [16]: p3 = p2 / p1
In [17]: p3 Out[17]: PosixPath('c/b/a')
In [18]: p3.parts Out[18]: ('c', 'b', 'a')
In [19]: p3.joinpath('etc', 'init.d', Path('httpd')) Out[19]: PosixPath('c/b/a/etc/init.d/httpd')
In [20]: |
获取路径:
str获取路径字符串.
bytes获取路径字符串的bytes.
1 2 3 4 5 6 |
In [20]: p = Path('/etc')
In [21]: str(p), bytes(p) Out[21]: ('/etc', b'/etc')
In [22]: |
父目录:
parent目录的逻辑父目录;
parents父目录序列.
1 2 3 4 5 6 7 8 9 |
In [22]: p = Path('/a/b/c/d')
In [23]: p.parent.parent Out[23]: PosixPath('/a/b')
In [24]: [x for x in p.parents] Out[24]: [PosixPath('/a/b/c'), PosixPath('/a/b'), PosixPath('/a'), PosixPath('/')]
In [25]: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
In [25]: p = Path('/etc/mysqlinstall/mysql.tar.gz')
In [26]: p.name Out[26]: 'mysql.tar.gz'
In [27]: p.suffix Out[27]: '.gz'
In [28]: p.suffixes Out[28]: ['.tar', '.gz']
In [29]: p.stem Out[29]: 'mysql.tar'
In [30]: p.with_name('mysql-5.tar') Out[30]: PosixPath('/etc/mysqlinstall/mysql-5.tar')
In [31]: p = Path('README')
In [32]: p.with_suffix('.txt') Out[32]: PosixPath('README.txt')
In [33]: |
name, stem, suffix, suffixes, with_suffix(suffix), with_name(name)
name目录的最后一个部分.
suffix目录中最后一个部分的扩展名;
stem目录最后一个部分,没有后缀;
suffixes返回多个扩展名列表;
with_suffix(suffix)补充扩展名到路径尾部,返回新的路径,扩展名存在则无效;
with_name(name)替换目录最后一个部分并返回一个新的路径; |
cwd()返回当前工作目录;
home()返回当前家目录;
is_dir() 是否是目录;
is_file() 是否是普通文件;
is_symlink() 是否是软链接;
is_socket() 是否是socket文件;
is_block_device() 是否是块设备;
is_char_device() 是否是字符设备;
is_absolute() 是否是绝对路径;
resolve() 返回一个新的路径, 这个新路径就是当前Path对象的绝对路径,如果是软链接则直接被解析;
absolute() 也可以获取绝对路径,但是推荐使用resolve().
exists() 目录或文件是否存在.
rmdir() 删除空目录, 没有提供判断目录为空的方法;
touch(mode=0o666, exist_ok=True) 创建一个文件;
as_uri() 将路径返回成URI, 例如'file:///etc/passwd'.
mkdir(mode=0o777, parents=False, exist_ok=False)
parents, 是否创建父目录, True等同于mkdir -p; False时, 父目录不存在,则抛出FileNotFoundError.
exist_ok参数,在3.5版本加入; False时,路径存在,抛出FileExistsError; True时,FileExistsError被忽略.
iterdit() 迭代当前目录;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
In [34]: p = Path()
In [35]: p Out[35]: PosixPath('.')
In [36]: p /= 'a/b/c/d' # p = p / 'a/b/c/d'
In [37]: p Out[37]: PosixPath('a/b/c/d')
In [38]: p.exists() Out[38]: False
In [39]:
In [39]: p.mkdir() --------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) <ipython-input-39-4c751e65273b> in <module>() ----> 1 p.mkdir()
~/.pyenv/versions/3.5.3/lib/python3.5/pathlib.py in mkdir(self, mode, parents, exist_ok) 1212 if not parents: 1213 try: -> 1214 self._accessor.mkdir(self, mode) 1215 except FileExistsError: 1216 if not exist_ok or not self.is_dir():
~/.pyenv/versions/3.5.3/lib/python3.5/pathlib.py in wrapped(pathobj, *args) 369 @functools.wraps(strfunc) 370 def wrapped(pathobj, *args): --> 371 return strfunc(str(pathobj), *args) 372 return staticmethod(wrapped) 373
FileNotFoundError: [Errno 2] No such file or directory: 'a/b/c/d'
In [40]: p.mkdir(parents=True)
In [41]: p.exists() Out[41]: True
In [42]: p.mkdir(parents=True) --------------------------------------------------------------------------- FileExistsError Traceback (most recent call last) <ipython-input-42-09435c472033> in <module>() ----> 1 p.mkdir(parents=True)
~/.pyenv/versions/3.5.3/lib/python3.5/pathlib.py in mkdir(self, mode, parents, exist_ok) 1218 else: 1219 try: -> 1220 self._accessor.mkdir(self, mode) 1221 except FileExistsError: 1222 if not exist_ok or not self.is_dir():
~/.pyenv/versions/3.5.3/lib/python3.5/pathlib.py in wrapped(pathobj, *args) 369 @functools.wraps(strfunc) 370 def wrapped(pathobj, *args): --> 371 return strfunc(str(pathobj), *args) 372 return staticmethod(wrapped) 373
FileExistsError: [Errno 17] File exists: 'a/b/c/d'
In [43]: p.mkdir(parents=True, exist_ok=True)
In [44]: p /= 'readme.txt'
In [45]: p Out[45]: PosixPath('a/b/c/d/readme.txt')
In [46]: p.parent.rmdir()
In [47]: p.parent.exists() Out[47]: False
In [48]: p.mkdir() --------------------------------------------------------------------------- FileNotFoundError Traceback (most recent call last) <ipython-input-48-9edfab0e3b54> in <module>() ----> 1 p.mkdir()
~/.pyenv/versions/3.5.3/lib/python3.5/pathlib.py in mkdir(self, mode, parents, exist_ok) 1212 if not parents: 1213 try: -> 1214 self._accessor.mkdir(self, mode) 1215 except FileExistsError: 1216 if not exist_ok or not self.is_dir():
~/.pyenv/versions/3.5.3/lib/python3.5/pathlib.py in wrapped(pathobj, *args) 369 @functools.wraps(strfunc) 370 def wrapped(pathobj, *args): --> 371 return strfunc(str(pathobj), *args) 372 return staticmethod(wrapped) 373
FileNotFoundError: [Errno 2] No such file or directory: 'a/b/c/d/readme.txt'
In [49]: p.mkdir(parents=True)
In [50]: p Out[50]: PosixPath('a/b/c/d/readme.txt')
In [51]: |
遍历, 并判断文件类型,如果为目录,是否可以判断其是否为空:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
from pathlib import Path
p = Path() p /= 'a/b/c/d'
for x in p.parents[len(p.parents)-1].iterdir(): print(x, end='\t') if x.is_dir(): flag = False for _ in x.iterdir(): flag = True break # for是否可以使用else子句? print('dir', 'Not Empty' if flag else 'Empty', sep='\t') elif x.is_file(): print('file') else: print('other file') |
通配符:
glob(pattern) 通配给定的模式;
rglob(pattern) 通配给定的模式,递归目录;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
In [4]: from pathlib import Path
In [5]: p = Path()
In [6]: list(p.glob('test*')) # 返回当前目录对象下的test开头的文件; Out[6]: [PosixPath('test')]
In [7]: list(p.glob('**/*.py')) # 递归所有目录,等同于rglob. Out[7]: []
In [8]: list(p.rglob('*.py')) Out[8]: []
In [9]: |
匹配:
match(pattern)
模式匹配,成功返回True.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
In [1]: from pathlib import Path
In [2]: Path('/a/b/c.py').match('b/*.py') Out[2]: True
In [3]: Path('/a/b.py').match('*.py') Out[3]: True
In [4]: Path('/a/b/c.py').match('a/*.py') Out[4]: False
In [5]: Path('/a/b/c.py').match('a/*/*.py') Out[5]: True
In [6]: Path('/a/b/c.py').match('a/**/*.py') Out[6]: True
In [7]: Path('/a/b/c.py').match('**/*.py') Out[7]: True
In [8]: |
文件操作:
open(mode='r', buffering=-1, ending=None, errors=None, newline=None)
使用方法类似内建函数open. 返回一个文件对象.
py3.5增加的新函数:
read_bytes()
以'rb'读取路径对应文件,并返回二进制流. 具体看源码.
read_text(encoding=None, errors=None)
以'rt'方式读取路径对应文件,返回文本.
Path.write_bytes(data)
以'wb'方式写入数据到路径对应文件.
write_text(data, encoding=None, errors=None)
以'wt'方式写入字符串到路径对应文件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
from pathlib import Path
p = Path('my_binary_file') p.write_bytes(b'Binary file contents') p.read_bytes() # b'Binary file contents'
p = Path('my_text_file') p.write_text('Text file contents') p.read_text() # 'Text file contents'
p = Path(r'C:\Users\31948\Desktop\test.py') p.write_text('hello python') print(p.read_text) with p.open() as f: print(f.read(5)) |
shutil, csv, ini
os.name -> windows是nt, linux是posix.
os.uname() -> Linux支持显示.
sys.platform -> windows显示win32, linux显示linux.
os.listdir('o:/temp') -> 返回目录内容文件.
os也有open, read, write等方法, 但太低级,建议使用内建函数open, read, write.
os.stat(path, *, dir_fd=None, follow_symlinks=True)
调用linux系统的stat.
path: 路径的string或者bytes, 后者fd.
follow_symlinks True 返回文件本身信息, False且如果是软链接则显示软链接本身.
os.chown(path, uid, gid) -> 改变文件的属主,属组,但需要足够的权限.
shutil模块
目前为止,文件的拷贝,使用打开2个文件对象,源文件读取内容,写入目标文件中来完成拷贝过程,但这样会丢失stat数据信息(权限等),因为根本就没复制过去.
python提供了一个方便的库shutil(高级文件操作).
copy复制:
copyfileobj(fsrc, fdst[, length])
文件对象的复制,fsrc和fdst是open打开的文件对象,复制内容,fdst要求可写.
length指定了表示buffer的大小;
1 2 3 4 5 6 7 8 |
import shutil
with open(r'C:\Users\31948\Desktop\test\one.txt', 'r+') as f1: f1.write('abcd\n1234') f1.seek(0) f1.flush() with open(r'C:\Users\31948\Desktop\test\first.txt', 'w+') as f2: shutil.copyfileobj(f1, f2) |
copyfile(src, dst, *, follow_symlinks=True)
复制文件内容,不含元数据; src, dst为文件的路径字符串;
本质上调用的就是coppyfileobj, 所以不带元数据二进制内容复制.
copymode(src,dst,*,follow_symlinks=True) -> 仅仅复制权限.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# windows下,进入src和dst文件的父目录下: In [1]: import shutil, os
In [2]: shutil.copymode('one.txt', 'first.txt')
In [3]: os.stat('one.txt') Out[3]: os.stat_result(st_mode=33206, st_ino=23643898043816899, st_dev=3188908737, st_nlink=1, st_uid=0, st_gid=0, st_size=10, st_atime=1509104520, st_mtime=1509109637, st_ctime=1509104520)
In [4]: os.stat('first.txt') Out[4]: os.stat_result(st_mode=33206, st_ino=37999121856060367, st_dev=3188908737, st_nlink=1, st_uid=0, st_gid=0, st_size=10, st_atime=1509104525, st_mtime=1509109637, st_ctime=1509104520)
In [5]: |
copystat(src, dst, *, follow_symlinks=True) -> 复制元数据,stat包含权限.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# Linux下操作: (env353) [python@ames test]$ stat ont.txt stat: cannot stat ‘ont.txt’: No such file or directory (env353) [python@ames test]$ ls first.txt one.txt Untitled.ipynb (env353) [python@ames test]$ (env353) [python@ames test]$ stat one.txt File: ‘one.txt’ Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd00h/64768d Inode: 1087835 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1001/ python) Gid: ( 1001/ python) Context: unconfined_u:object_r:user_home_t:s0 Access: 2017-10-27 09:55:08.379019965 -0400 Modify: 2017-10-27 09:55:08.379019965 -0400 Change: 2017-10-27 09:55:08.379019965 -0400 Birth: - (env353) [python@ames test]$ stat first.txt File: ‘first.txt’ Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd00h/64768d Inode: 1087717 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1001/ python) Gid: ( 1001/ python) Context: unconfined_u:object_r:user_home_t:s0 Access: 2017-10-27 09:56:08.836225291 -0400 Modify: 2017-10-27 09:56:08.836225291 -0400 Change: 2017-10-27 09:56:08.836225291 -0400 Birth: - (env353) [python@ames test]$ # 打开ipython In [1]: import shutil
In [2]: shutil.copystat('first.txt', 'one.txt')
In [3]:
# 再次查看: (env353) [python@ames test]$ stat one.txt File: ‘one.txt’ Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd00h/64768d Inode: 1087835 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1001/ python) Gid: ( 1001/ python) Context: unconfined_u:object_r:user_home_t:s0 Access: 2017-10-27 09:56:08.836225291 -0400 Modify: 2017-10-27 09:56:08.836225291 -0400 Change: 2017-10-27 10:01:04.778385230 -0400 Birth: - (env353) [python@ames test]$ |
copy(src, dst, *, follow_symlinks=True) -> 复制文件内容,权限和部分元数据,不包括创建时间和修改时间;
本质上调用的是:
copyfile(src, dst, follow_symlinks=follow_symlinks)
copymode(src, dst, follow_symlinks=follow_symlinks)
copy2比copy多了复制全部元数据,但需要平台支持.
本质上调用的是:
copyfile(src, dst, follow_symlinks=follow_symlinks)
copystat(src, dst, follow_symlinks=follow_symlinks)
copytree(src, dst, symlinks=False, ignore=Nore, copy_function=copy2, ignore_dangling_symlinks=False)
递归复制目录. 默认使用copy2, 也就是带更多的元数据复制.
src, dst必须是目录, src必须存在, dst必须不存在.
ignore=func, 提供一个callable(src, names) -> ignore_names. 提供一个函数, 它会被调用. src是源目录, names是os.listdir(src)的结果, 就是列出src中的文件名, 返回值是要被过滤的文件名的set类型数据.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# Linux下操作: (env353) [python@ames test]$ tree tmp tmp ├── a └── b
2 directories, 0 files (env353) [python@ames test]$ (env353) [python@ames test]$ tree tt tt [error opening dir]
0 directories, 0 files (env353) [python@ames test]$ (env353) [python@ames test]$ ipython Python 3.5.3 (default, Sep 12 2017, 03:35:37) Type 'copyright', 'credits' or 'license' for more information IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import shutil
In [2]: def ignore(src, names): ...: ig = filter(lambda x: x.startswith('a'), names) ...: return set(ig) ...:
In [3]: shutil.copytree('tmp', 'tt/o', ignore=ignore) Out[3]: 'tt/o' (env353) [python@ames test]$ tree tt tt └── o └── b
2 directories, 0 files (env353) [python@ames test]$ |
rm删除
shutil.rmtree(path, ignore_errors=False, onerror=None)
递归删除. 如同rm -rf一样危险,慎用.
它不是原子操作,有可能删除错误,就会中断,已经删除的就删除了.
ignore_errors为true,忽略错误. 当为False或omitted时, onerror生效.
onerror为callable,接受函数function, path和execinfo.
1 |
Shutil.rmtree('o:/tmp') # 类似 rm -rf操作. |
move移动
move(src, dst, copy_function=copy2)
递归移动文件/目录到目标, 返回目标.
本身使用的是os.rename方法.
如果不支持rename,如果是目录则想copytree再删除源目录.
默认使用copy2方法.
1 2 |
os.rename('o:/t.txt', 'o:/temp/t') os.rename('test3', '/tmp/py/test300') |
shutil还支持打包功能,生成tar并压缩,支持zip,gz,bz,xz.
csv文件
csv文件简介:
逗号分隔符 Comma-Separated Values.
CSV是一个被行分割符,列分割符划分成行和列的文本文件.
没有指定的字符编码.
参考: http://www.ietf.org/rfc/rfc4180.txt
行分隔符为\r\n,最后一行可以没有换行符.
列分隔符常为逗号或制表符.
每一行成为一条记录record.
字段可以使用双引号括起来,也可不使用.如果字段中出现双引号/逗号,换行符必须用双引号括起来,如果字段值是双引号,使用两个双引号表示一个转义.
表头可选,和字段列对齐.
手动生成csv文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
In [5]: pwd Out[5]: '/home/python/test'
In [6]: from pathlib import Path
In [7]: p = Path('/home/python/test/t.csv')
In [8]: parent = p.parent
In [9]: if not parent.exists(): ...: parent.mkdir(parents=True) ...:
In [10]: csv_body = '''\ ...: id, name, age, comment ...: 1, zs, 18, "I'm 18" ...: 2, ls, 20, "this is a ""test"" string." ...: 3, www, 23, "中国 ...: 国庆 ...: " ...: '''
In [11]: p.write_text(csv_body) Out[11]: 108
In [12]: cat t.csv id, name, age, comment 1, zs, 18, "I'm 18" 2, ls, 20, "this is a ""test"" string." 3, www, 23, "中国 国庆 "
In [13]: |
csv模块:
reader(csvfile, dialect='excel', **fmtparams)
返回DictReader的实例,是个行迭代器.
delimiter列分隔符,逗号.
lineterminator行分隔符\r\n.
quuotechar字段的引用符号,缺省为双引号("").
双引号的处理:
doublequote双引号的处理,默认为True.如果和quotechar为同一个,True则使用2个双引号表示,False表示使用转义字符将作为双引号的前缀.
escapechar一个转义字符,默认为None.
quoting指定双引号的规则. QUOTE_ALL所有字段; QUOTE_MINIMAL特殊字符字段;
QUOTE_NONNUMERIC非数字字段; QUOTE_NONE都不使用引号.
writer(csvfile, dialect='excel', **fmtparams)
返回DictWriter的实例.
主要方法有writerow, writerows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# linux下: In [15]: import csv
In [16]: from pathlib import Path
In [17]: p = Path('t.csv')
In [19]: row = [4, 'tom', 22, 'tom']
In [20]: rows = [(5, 'jerry', 24, 'jerry'), (6, 'justin', 22, 'just\t"int')]
In [21]: with open(str(p), 'a+') as f: ...: writer = csv.writer(f) ...: writer = writerow(row) ...: writer.writerows(rows) ...: --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-21-2dde75aff59c> in <module>() 1 with open(str(p)) as f: 2 writer = csv.writer(f) ----> 3 writer = writerow(row) 4 writer.writerows(rows) 5
NameError: name 'writerow' is not defined
In [23]: with open(str(p), 'a+') as f: ...: writer = csv.writer(f) ...: # writer = writerow(row) ...: writer.writerows(rows) ...:
In [24]: (env353) [python@ames test]$ cat t.csv
5,jerry,24,jerry 6,justin,22,"just ""int" (env353) [python@ames test]$ |
ini文件处理:
作为配置文件,ini格式的文件很流行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[root@ames ~]# cat /etc/my.cnf [client] #password = your_password port = 3306 socket = /tmp/mysql.sock
[mysqldump] quick max_allowed_packet = 16M
[mysql] no-auto-rehash
[myisamchk] key_buffer_size = 8M sort_buffer_size = 8M
[mysqlhotcopy] interactive-timeout |
中括号里面的部分称为section.
每一个section内,都是key-value形成的键值对,key称为option选项.