走近Linux之走近文件
任何语言都离不开对文件的操作,Python语言是如何来操作和管理文件的。掌握文件的基本概念、基本操作,了解文件属性、 linux 系统的文件管理机制及os模块对文件和目录的处理等相关内容。
- [√]慕课网Meshare_huang老师:Python文件处理
文件简介
Python的文件处理:
初学者:推荐使用虚拟机VMwareStation
+ Deepin
必备前置条件知识储备:
- Linux系统知识
- Linux下Python开发环境
- 掌握Python基础知识
Python文件概念:
文件: Python中文件是对象依赖我们的具体系统。
Linux文件:一切设备都可以看成文件
- 例如:磁盘文件,管道,网络Socket,外设等。
文件属性:用户
,读
,写
,执行权限
;
在Linux控制台输入命令:
1 | #cd进一个空目录 |
使用i
进入insert模式
进行插入代码。
插入完成后使用esc
退出编辑模式,输入:wq
进行保存。
通过ls -l
命令可以看到文件的一些基本属性:
- 第一个横杠代表是一个文件,还是一个目录。
-
代表是一个文件,d
代表是一个目录
如下图1为一个目录。
- 第一组
rw-
代表当前用户对于当前文件有读
有写
没有执行权限
。(-
代表没有权限,x
为可执行) - 第二组
r--
:表示当前用户组对该文件有读r
没有写w
的权限,没有执行权限x
第三组
r--
:表示其他用户对该文件有读r
权限,但没有写w
和执行x
权限第一个
mtianyan
代表文件的拥有者是mtianyan
- 第二个
mtianyan
代表这个文件所属的用户组是mtianyan
21
代表文件的大小是21字节
后面的时间是文件的创建时间。后面是文件名。
可以看到我们最为当前用户现在没有该文件执行权限。
使用chmod
为文件增加权限说明:
- 如果给所有人添加可执行权限:
chmod a+x 文件名
; - 如果给文件所有者添加可执行权限:
chmod u+x 文件名
; - 如果给所在组添加可执行权限:
chmod g+x 文件名
; - 如果给所在组以外的人添加可执行权限:
chmod o+x 文件名
;
可以看到我们通过chmod +x hello.py
为当前用户
,用户组
,其他用户
都添加了执行权限
Linux下首行一定要加这句话:!/usr/bin/Python
,!/usr/bin/Python
是告诉操作系统执行这个脚本的时候,调用/usr/bin
下的python解释器。
打印出了Helloworld
好像有点问题。以后对Linux熟了再回来看。
python
命令是可以正常执行的。
文件基础操作
主要讲解文件打开及文件不同的打开方式、使用read
,readlines
及迭代器
访问文件、文件写入方式及写缓存
处理、文件关闭及由不关闭导致的问题、文件指针及文件指针操作
文件打开方式
open()
1 | open(name [,mode[buf]]) |
name
: 文件路径mode
: 打开方式buf
: 缓冲buffering大小
mode
方式有:只读
,只写
。读写
。
read()
1 | read([size]) |
读取文件(读取size个字节
,默认读取全部)
- 如果文件长度大于size,我们就读size个长度。
- 如果文件长度小于size,我们就把文件读完。
- 如果没有设置size,默认全部读完。
readline()
1 | readline([size]) |
读取一行
readlines()
1 | readlines([size]) |
读取完文件(看到后面你就知道并不是),返回每一行所组成的列表。我们就可以使用列表访问的方式,使用文件。
弊端:一次性读完,占用很大内存。
write()
1 | write(str) |
将字符串写入文件
writelines()
1 | writelines(sequence_of_strings) : 写多行到文件 |
sequence_of_strings
是一个由字符型组成的列表。一次性写入多行。
输入ipython
进入ipython环境
type(f)
可以看到打开的文件类型就是一个文件对象。
拥有的方法可以使用f.
+ Tab
自动补齐
1 | Error:File not open for writing |
这里因为我们使用的是默认无参数打开,此时我们并不拥有写权限。
Python文件打开方式
mode | 说明 | 说明 |
---|---|---|
‘r’ | 只读方式打开 | 文件必须存在 |
‘w’ | 只写方式打开 | 文件不存在创建文件;存在则清空内容 |
‘a’ | 追加方式打开 | 文件不存在创建文件 |
‘r+’/‘W+’ | 读写方式打开 | |
‘a+’ | 追加和读写方式打开 |
'rb'
,'wb'
,'ab'
,'rb+'
,'wb+'
,'ab+'
:都是采用二进制方式打开。
练习'r'
'w'
'a'
'r+'
- 不带参数的
open
是用只读方式打开的,所以文件不存在会报错。
- 请注意关闭文件
f.close()
否则cat
时文件内容会为空。
- 当我们再次打开文件使用
w
方式。已存在的文件会被清空才打开。
- 我们以
a
方式打开此时我们可以对于文件进行追加操作,原有内容并没有被清空
新增内容被添加到了最后。
- 当我们以
r+
方式打开,我们新增的内容会从文件开始替换原有内容的一部分。
- 当我们以
w+
方式打开,文件可以被读写。但是文件内容被清空。
- 此时新文件可以被读写。
使用二进制方式打开的使用方法与上面介绍的基本一致。
意义在于: 比如读取一张图片的EXIF信息读取图片的长宽拍照日期
如果我们以普通方式打开是以文本方式打开,不能读取到正确的内容。
当我们以二进制打开我们就可以读取到正确的EXIF信息
。
学习了打开文件,读取文件,写入文件。文件打开方式的不同。
文件读取方式
read()
1 | read([size]) |
读取文件(读取size个字节
,默认读取全部)
- 如果文件长度大于size,我们就读size个长度。
- 如果文件长度小于size,我们就把文件读完。
- 如果没有设置size,默认全部读完。
readline()
1 | readline([size]) |
读取一行
示例操作
首先使用touch mtianyan.txt
和 vi mtianyan.txt
创建并写入内容:
1 | blog.mtianyan.cn |
可以看出
1 | readline(size): |
readlines()
1 | readlines([size]) |
读取完文件(整数个buffer左右字节),返回每一行所组成的列表。我们就可以使用列表访问的方式,使用文件。
弊端:一次性读完,占用很大内存。
示例操作:
虽然设置了size
为1
,但是还是把所有都读出来了。
输入help(f.readlines)
查看定义:重复的调用readline()
然后返回一个读到的行所组成的列表。
读取文件的大小:
- 如果
size
小于缓冲区
的大小,则读取缓冲区大小
的数据 - 如果
size
大于缓冲区
的大小,读取size大小
的数据,但不是完全的等于size的大小,一般读取比size大的整行的数据.
这个设置是python解释器内部的一个变量。
1 | import io |
设置参数小于8192
每次能读取8192
个字节。
- 设置参数
大于
一个8192
小于2*8192=16384
。则读取两个buffer
值. BUFFER
都是一整个一整个读
Linux命令使用
使用vi
打开文件。y
是复制当前行,yy
是复制光标所在的一整行.
如果复制了一行,则p
是在光标所在行的下一行粘贴,10000p
就是粘贴10000次
命令
yy,10000p
复制10000
行 .然后:set nu
显示行数gg
:- 跳转到文件头
:1
或gg
- 跳转到
文件末尾行数+gg
:$
Shift+g
- 跳转到指定行,例跳转到123行:
123gg
或:123
.
- 跳转到文件头
使用ctrl+z
可将程序切换到后台。用fg
可将后台程序切换到前台。
可以看到此时的文件以及有十几万个字节了
可以看出这时候不再是一次性把文件读取完了,而是读取了482
行。
170051/100003
行,每行17
个字节。
这时我们的size
大于了缓冲区的大小8192
。因此我们的size
到了8192
和16384
之间。
重点:系统数据是按着整个buffer,整个buffer
来读的。此时系统会读取差不多两个buffer
的数据。也就是963*17 =16371
。
待探究
iter: 使用迭代器读取文件
迭代器并不是把我们的文件全部存入了内存中。而是我们每使用一次next
方法就会自动读取下一行。所以能在不消耗大量内存的情况下进行读取整个文件。
文件写入与写缓存
write()
1 | write(str) |
将字符串写入文件
writelines()
1 | writelines(sequence_of_strings) : 写多行到文件 |
sequence_of_strings
参数是一个可迭代对象
:
- 可以是字符串
- 可以是字符串所组成的元组。
- 可以是一个字符串所组成的迭代器。
- 也可是一个字符串组成的列表
实际操作
1 | In [37]: cat test.txt |
写入一个元组会报错 :提示必须是由字符串组成的序列。
1 | In [41]: f.writelines(('1','2','3')) |
可以看到我们都可以正常的写入由字符串组成的列表。
1 | In [46]: f = open("mtianyan.txt",'w') |
文件内容为空,因为我们没有使用f.close()
将文件关闭。
Linux系统有一种写缓存机制。如果我们不主动调用f.close()
或 flush
他是不会写到磁盘文件的。
写文件的过程中Python解释器进行系统调用。Linux系统内核将文件写入系统文件缓冲区。
当我们调用f.close()
时,系统会更新文件到硬盘。
Python写磁盘的缓存机制
- 主动调用
closed()
或flush
方法。写缓存同步到磁盘 - 写入数据量大于或等于写缓存,写缓存同步到磁盘。(此时系统写缓存又清空,然后就又继续缓存直到
close()
)
实际操作
1 | In [62]: f = open("mtianyan.txt",'w') |
进行flush()
操作时内容更新。
说明我的Linux的缓冲区就是这么大147456
当我们执行close
文件会变大。因为全部写进去了。
文件关闭
- 将写缓存同步到磁盘;
- linux系统中每个进程打开的文件个数是有限的;
- 如果打开文件数到了系统限制,在打开文件就会失败;
1 | mtianyan@mtianyan-deep:~/Desktop/PythonFile$ ps |
看到ipython进程:
1 | mtianyan@mtianyan-deep:~/Desktop/PythonFile$ cat /proc/5918/limits |
file.fileno()
:文件描述符;每打开一个就会加1,直到1024失败1
2
3n [3]: for i in range(1027):
...: f = open("mtianyan.txt",'r')
...: print ("%d:%d" %(i,f.fileno()))
并没有起到效果。fileno
在10
和12
不断来回
实现代码:
1 |
|
运行结果:
1 | 1010:1022 |
因此我们需要养成良好编码习惯记得关闭文件。
文件指针。
- 写入文件后,必须打开才能读取写入的内容
- 读取文件后,无法重新再次读取读取过的内容
比如:写完文件必须关闭才能读到我们写入的内容。
文件指针用于定位我们当前文件所执行到的位置:
- 使用
open()
打开时文件指针就在起始位置。 read(3)
文件指针就会往后挪3
个位置。指向第四个位置
。write('mtianyan')
就会从当前文件指针4
开始写。文件指针就会移动8个字节
。
我们之前的问题都是因为我们无法使文件指针归于起始位置的,
下面我们学习自由操作文件指针:
1 | seek(offset[,whence]):移动文件指针 |
1 | In [1]: f = open('mtianyan.txt','r+') |
f.tell()
(函数)返回当前文件的偏移返回的是一个整数,也许是一个长整数
1 | In [4]: f.read(3) |
可以看出我们可以使用f.seek(0, os.SEEK_SET)
来进行指针归零。
1 | In [8]: f.seek(0,os.SEEK_END) |
当然我们也可以把文件指针指到末尾去。文件指针已经在末尾了,向后继续读取会为空。
1 | In [12]: f.seek(-5,os.SEEK_END) |
使用f.seek(-5,os.SEEK_END)
可以将文件指针倒着移回去。
1 | In [14]: f.tell() |
读取5
个之后,指针又跑到了3139
:使用f.seek(-5,os.SEEK_CUR)
又可以从当前位置往前移。
当文件偏移大于文件长度会出现的问题:
1 | In [17]: f.seek(0,os.SEEK_END) |
会报错:告诉我们这是一个无效的参数。类似于索引越界等。
文件属性及OS模块使用
讲解文件属性、标准文件、文件命令行参数、文件编码格式、使用os模块中方法对文件进行操作、使用os模块中的方法对目录进行操作
文件属性编码格式
Python文件属性
file.fileno()
:文件描述符;每打开一个就会加1,直到1024失败file.mode:
文件打开权限file.encoding:
文件编码格式file.closed:
文件是否关闭
1 | In [20]: f.fileno() |
没有返回值:为ASCII
码文件。应该与系统相关。
Python标准文件
- 文件标准输入:
sys.stdin
; - 文件标准输出:
sys.stdout
; - 文件标准错误:
sys.stderr
;
1 | In [26]: import sys |
系统的sys.stdin
的read()
是指从控制台读入数据。
1 | In [32]: sys.stdin.fileno() |
系统的sys.stdin
的fileno
为0。也就是我们启动一个进程,他首先会打开标准输入:从控制台读数据。
a = raw_input()
其实内部是调用sys.stdin
来读取数据的。
1 | In [37]: sys.stdout.mode |
sys.stdout
只可以写,不可以读。写入相当于写入到控制台,会直接显示。
print
实际内部调用的是stdout
1 | In [39]: sys.stdout.fileno() |
sys.stdout
是系统在启动程序时第二个打开的。
也就是系统会先为我们打开输入,再打开输出。
1 | In [40]: sys.stderr.mode |
sys.stderr
是系统在启动程序时第二个打开的。
先开输入,再开输出。第三err输出。
Python文件命令行参数
sys
模块提供了sys.argv
,通过该属性可以得到命令行参数
很多程序都是这么做的:比如加上-v
,根据不同的参数完成不同的功能。
sys.argv
是一个字符串组成的列表
1 | import sys |
运行结果:
1 | 1 |
直接运行,我们没有提供参数,打印出了当前文件的绝对路径文件名。
Python文件编码方式。
使用普通方式打开文件:写入u天涯明月笙
。
1 | In [3]: f.write(u'天涯明月笙') |
会报错:UnicodeEncodeError
因为我们的文件是ascii
格式的。不能将Unicode
字符串写入。
实现代码:
1 | In [1]: a = unicode.encode(u'天涯','utf-8') |
运行结果:
1 | In [7]: cat mtianyan.txt |
我们可以用codecs
模块提供方法创建制定编码格式文件.
1 | import codecs |
open(fname,mode,encoding,errors,buffering):
使用指定编码格式打开文件
linux文件系统
所有设备都可以看为文件:
- 包括磁盘(ext2,ext4)文件,NFS文件系统,各种外设
虚拟文件系统
为文件提供文件节点
每一个外设在内核中都有一个对应的驱动程序。通过系统调用对文件节点进行访问。把所有外设作为文件处理。
在操作系统之上的Python解释器,Python程序跑在解释器中。
使用open()
会访问文件节点
。设备节点对应虚拟文件系统的方法,这个文件系统与驱动绑定。
驱动会操作硬件设备。
os模块对文件和目录进行操作
使用os模块来打开文件:
os.open(filename, flag [,mode])
打开文件
- os.O_CREAT:创建文件
- os.O_RDONLY:只读方式打开
- os.O_WRONLY:只写方式打开
- os.O_RDWR:读写方式打开
os.read(fd, buffersize)
:读取文件,返回值为读取的内容os.write(fd, string)
:写入文件 ,返回值是写入数据的大小os.lseek(fd, pos, how)
: 文件指针操作os.close(fd)
:关闭文件
umask
获取系统的默认权限。我的是0022
1 | In [14]:fd = os.open('mtianyan.txt',os.O_CREAT | os.O_RDWR) |
使用os是为了跨平台。
os方法
os方法 | 说明 |
---|---|
os.access(path, mode) | 判断该文件权限:F_OK存在,权限:R_OK ,W_OK, X_OK |
os.listdir(path) | 返回当path路径下所有文件名组成的列表 |
os.remove(path) | 删除文件 |
os.rename(old, new) | 修改文件或者目录名 |
os.mkdir(path[, mode]) | 创建目录 |
os.makedirs(path[, mode]) | 创建多级目录 |
os.removedirs(path) | 删除多级目录 |
os.rmdir(path) | 删除目录(目录必须空目录) |
1 | os.access('mtianyan,txt',os.R_OK) |
os.path方法
os.path方法 | 说明 |
---|---|
os.path.exists(path) | 当前路径是否存在,也可以判断是否有该文件 |
os.path.isdir(s) | 是否是一个目录 |
os.path.isfile(path) | 是否是一个文件 |
os.path.getsize(filename) | 返回文件大小,返回目录文件大小 |
os.path.dirname(p) | 返回路径的目录 |
os.path.basename(p) | 返回路径的文件名 |
1 | os.path.exists('./mtianyan.txt') |
文件练习
使用Python来管理ini
文件:实现查询
,添加
,删除
,保存
。
- 掌握文件的基本操作
- 认识
ini
文件 - 了解
ConfigPaser
ini配置文件格式:
1 | 节: [session] |
定位带port
这个节,然后找到。
ConfigParser
mtianyan.txt内容:
1 | [userinfo] |
两个概念:sections(大的分类)
和option小的选项
1 | import ConfigParser |
遍历结果如下
1 | userinfo |
1 | cfg.set('userinfo', 'pwd', '1234567') #修改键值 |
文件操作练习
1 | import os |
运行结果:
1 | **********************> |