本文引用至: python 文件
在了解基本的Python的built-in trick 比如, Iterator, Generator, datatype 等等. 接着, 我们就应该继续深入,了解一下编程的两大块, 1. 文件, 2. 网络.
so, 这里我们先来了解一下关于python中的文件操作。
python基本的文件操作全在built-in object file中. 一些基本的CRUD 操作, 可以完全在这个原生的file中完成. 那应该怎样创建一个file object呢?
使用open 方法,你就可以 完美的创建了一个file object.基本 syntax:
open(file, mode='r', buffering=-1, encoding=None...)
file: 文件打开路径或者是file descriptor
mode: 文件打开的类型, 基本的有可读可写两种.代号分别为: r
, w
. 默认的就是 r
. 当然, 他还有其他的。 请看表:
mode | effect |
---|---|
r | reading 读文件 |
w | write 写文件 |
x | 打开并创建文件, 如果文件已经存在,那么这就没有什么x用了 |
a | append 表示用来写入文件, 并添加到指定文件尾部,相当于 >> 操作 |
b | binary 二进制mode,以后再懂即可 |
t | text 文档mode |
+ | 打开一个文件用来读写 |
上面介绍这么多,不过, 你只需要了解部分即可. 比如 r
, w
. 而且,上面的flag我们可以组合使用, 比如: r+
, w+
, a+
.
这里再介绍几个常用的组合命令.
mode | effect |
---|---|
r+ | 读写一个文件, 并且此时文件的指针指向文件开头,相当于从头添加文件 |
a+ | 读写一个文件, 和 r+ 类似,不过该继承了 a 的特质, 默认在尾部添加文件. 如果文件不存在则会报错 |
w+ | 读写一个文件,如果写入,则覆盖该文件, 如果文件不存在则创建 |
基本的就这两类, 当然你还可以搭配 b
模式, 进行二进制的操作,不过这有点difficult 我就不提了.
上面的参数实际上并未列举完全,但实际上,初期我们只需要前面4个参数即可, 甚至, 只需要第一个参数就over了, 更多的请参考: open
我们看一个简单的demo吧:
js = open('./demo.js');
这样我们就简简单单的打开一个js文件了.
在file object 上还存在4个基本属性 closed
, mode
, name
. 具体来看一下表示的意思吧:
property | effect |
---|---|
closed | Boolean 文件是否关闭 |
mode | r,w,b... 文件操作的类型 |
name | 文件的名字, 也就是文件打开路径 |
看一个demo:
js = open('./demo.js','r+'); print('''closed is: {0} mode is: {1} name is: {2}'''.format(js.closed,js.mode,js.name)) # 返回 closed is: False mode is: r+ name is: ./demo.js
当你打开一个文件之后, 你就可以执行两个操作, 读 or 写.
这里, 我们先进行文件的读操作.基本 syntax:
f.read(size)
这里的size这里设置的是你读写文件内容的多少. 如果按text mode(大部分情况下,你读的是文本文件,都是text mode), read(1)
就相当于只读一字节的文件, 比如一个字母, 一个标点等.
js = open('demo.js','r+'); print(js.read(1)) # 得到: "
如果你读的是 binary mode. 则会得到1B 的内容.而且,read 方法会记录你读取的文件位置, 如果你读取read(1) 接着读取read(2) 那么你现在就已经读取了3 字节的文件.
print(js.read(1)) # 得到: " print(js.read(2)) # 得到: us
如果你忽略了read的参数,或者你使用负数(like -1) 那么你将一下子把所有的内容读取到. 而这些内容都是放在内存当中的, 所以, 如果你的文件太大, 那么congradulations 你的电脑估计就会爆掉...
print(js.read()) # 读取所有的内容
当然,读取文件并不只有read这一个方法, 因为python不是事件触发型的语言(我指的是nodeJS), 所以,python 需要提供其他的额外的方法, 来弥补读取大小的限制. 这里就有readline.
readline的方法意思就是一行一行的读取你的文件. 这里的一行怎么定义呢?
就是 /n
, 这个很容易理解, 就是当你使用 Enter
时, 系统便会默认在你的段后加上一个 /n
的flag.
直接看demo吧:
print(js.readline()) # this is first line print(js.readline()) # this is second line
同样,他也会记录你的读取位置.官方还提供了另外一种读取文件行数的方法. 直接使用循环遍历. 即, for...in...
for line in text: print(line)
当然, 如果你想一次性获得所有的行数的话, 则可以使用readlines(), 他返回的是list, 里面是所有的行数.
print(text.readlines()) # ['this is first line/n', 'this is second line/n']
上面的read && readline 已经可以完成文件的读写. 不过,python提供了更灵活的文件读取 -- tell && seek
tell() 方法是用来返回, 当前文件读取的位置. 还及得read(size)吗? tell的返回值相当于你多次调用read时size的累加值.
print(text.read(2)) print(text.tell()) # 2
seek()则是用来改变当前的读取的位置.
print(text.read(1)) # t print(text.seek(0)) # 0 print(text.read(1)) # t
seek 的格式为:
seek(offset,reference)
offset:指的就是间隔值
reference: 表示参考值. reference 可以取3个数: 0,1,2。默认参数为0.
0: 相对于文件的开头部分
1: 相对于当前指向的位置
print(text.read(1)) # t print(text.seek(0,1)) # 0 # 相当于往后挪一位 print(text.read(1)) # t
2: 相对于文件的结尾部分, 但如果你使用 2
的参数的话, 第一个参数只能表示0. 所以, 这个参数作用不是特别大.
print(text.read(1)) # t print(text.seek(0,2)) # 39(结尾部分的序号)
介绍完,怎么读文件, 那么接下来就该如何写文件了,
在python中的如何写文件, 实际上和你一开始打开文件的方式是有关系的, 比如你是直接写入开头( r+
), overwrite( w+
), 或是 在尾部添加( a+
).
text = open('text.txt','a+'); print(text.write("this is the second line")) # 29
他会返回写入的其实位置
其他的,大家可以自己试验一下.
另外,python还提供了其他关于文件写入的操作-- writable,writelines(list)
该方法用来表示当前写入流是否可以继续写入, 比如你使用 r
mode 时, 则会返回 False
. 如果可以继续写入,则返回 True
.
text = open('text.txt','a+'); print(text.writable()) # True
和readlines是类似的, 该可以写入多段文本, 如果你想写入多行的话, 则段尾则需要使用的是 /n
. 接受的是list参数。
writelines(list)
input_file = ["first line/n","second line /n"]; print(text.writelines(input_file))
当你读完,写完之后, 你就可以把该文件给关闭掉了.
当你的打开了一个文件过后,读取相关的信息,如果你不需要该文件了,你就可以close it. 这时候, 你就可以使用close 方法,来显示关闭该文件. 该方法是直接 安放在 fileObject上的.基本 syntax为:
f.close()
直接针对于特定的fileObject 关闭文件.show u demo:
js = open('demo.js','r+'); print(js.close()) print(js.read(1)) // 直接回报错--tracePack, 因为已经关闭了
当然, 基于文件的操作,并不仅仅这有这一小部分. 处理基本的读写外, 文件的操作,应该还包括,文件权限的改变, 文件的类型等等.
但, 基本内置的file object上,已经介绍完了. 下面是OS Module 上面提供的内容.
我们来总结一下基本的fileObject:
文件的重命名和删除.
这就很easy了:
直接修改文件的名字, 这是os模块提供的方法. 基本格式为:
rename(current,changed)
text = open('text.txt','a+') os.rename('text.txt','change.txt')
用来直接删除文件.格式为:
remove(fileName)
用来直接删除文件. 需要注意的是fileName必须为完整文件名(需要带上后缀)
text = open('text.txt','a+') os.remove('change.txt')
另外,还有一个方法 unlink, 该方法和remove方法,并没有半点差别, 只是遵循了原来的Unix name. 其他的, 你懂得。。。
上面就是两个基本的文件操作方法,接下来我们来看看文件目录的操作方法.
首先,应该就是文件目录的创建.
基本格式为:
mkdir(fileName)
这个就很简单了. 直接看demo吧:
os.mkdir('new Directory')
但是,当文件已经存在时,他会返回 FileExistsError
的错误.(这就尴尬了)
当如果你是在进行交互程序时, 那么可能就会涉及到文件目录改变的操作--chdir()
基本格式为:
chdir(path)
相对于当前目录进行文件目录的变更.
chdir('~/Desktop')
另外, 你还可以获得当前的目录名:
该方法是返回绝对路径:
print(os.getcwd()) # /Users/jimmy_thr/Desktop
当我们创建一个空目录时, 想要更换他的名字时, 这里就有两种方法: 1. 删除重建. 2. 直接重命名. 2333 如果你没傻,应该都会选第二种. 这里,我顺便把,目录的删除一起介绍了.
基本格式为:
rmdir(path)
里面的path应该是绝对路径. but... 如果里面有文件,那么该次的删除是无效的. 那应该怎么做呢?
很简单嘛, recursively 即可. 不过, 这还是有点麻烦的. 因为, 你不知道你的目录下是否为空, 还是有nested directories. 当然, 这也是可以做到的, 最后使用递归即可. 不过,官方已经提供了一个很棒的方法来帮我们实现这个效果(实际上是,懒癌犯了)
这里需要使用的是 shutil
模块里的 rmtree
方法.
基本格式为:
rmtree(path, ignore_errors=False, onerror=None)
path: 文件的路径
ignore_errors: 如果设置为True, 则表示但移除失败时, 则会被忽略。 如果设置会False, 当发生错误时, 则会直接触发onerror的handler 函数. 当然, 一般而言都没啥大问题, 但如果你要做什么大系统的话, 则需要注意.
看一个demo吧:
shutil.rmtree('new Directory')
另外,os 还提供了一个removedirs(name)的方法, 但实际上,我们用的也并不多处理基本的这些操作外,os 还提供了创建软连接
上面大致简述了基本的文件操作, 通常情况, 我们使用文件, 不仅仅可以使用他的path, 还可以直接使用它的fd.
还记得开头所说的built-in method open 方法吗?该open 只是存粹的返回一个file Object. 并不是返回fd. fd是什么呢?
科普一下: fd(file descriptor) 他是用来描述文件的唯一性的. 你可以通过他来对文件进行访问. 反正,你只要记住, 他实际上就和你的文件路径是一样的道理
上面只是一个很简单的说明, 其他的内容, 可以自行google wiki. 里面的内容还是挺复杂的...so, cut out all this nonsense
该方法是我们获得fd的简单方法. 基本格式为:
os.open(file,flags[,mode])
file: 文件路径
flags: 这个相当于就是我们上文提到的 r
, w
, a
. 但这里使用一种更加语义化的表达. 我们可以参阅一个表:
flags | effect |
---|---|
os.O_RDONLY | 就是 read only. 你懂的 |
os.O_WRONLY | write only |
os.O_RDWR | read and write |
os.O_NONBLOCK | 非阻塞式打开 |
os.O_APPEND | append on each write |
os.O_CREAT | 如果文件不存在则自动创建,相当于 w+ |
os.O_TRUNC | 相当于清空文件了,将你文件的size 设为 0 |
os.O_EXCL | 创建文件,如果文件存在,则发生错误,相当于 x |
os.O_SHLOCK | 自动创建一个shared lock |
os.O_EXLOCK | 自动有一个唯一锁 |
上面的flag 你可以组合使用, 使用方式就是使用 |
进行或的操作.
like : os.RDONLY | os.SHLOCK
mode: 就是设置文件权限,通常为6位数--000000. 而我们设置文件权限只需要用来后面3位数. 分别代表own grp others. 取值可以为:r-4 w-2 x-1. 而在python中, 我们需要额外的两个前缀来帮忙 0o
表示使用的是8进制.比如:
0o600
: owner 可读可写.
当然, 他也有一些语义化的表达. S_ISUID 等等. 不过,本人比较青睐直接使用number 来表示(主要还是懒)
当你使用os.O_WRONLY的flag时, 这意味着你可以使用write方法根据fd 来写入内容. 基本格式为:
os.write(fd, str)
一个简单的demo:
new_fd = os.open('text.txt',os.O_RDWR) input_str = str.encode("this will be converted into bytes-like object") os.write(new_fd,input_str)
这里有个坑, 在python2.x的时候, os.write第二个参数可以为str, 但是在3.x中,该参数只能为bytes-like object, 所以, 需要使用到str.encode()方法.
基本的写入操作完成了, 就应该轮到使用read方法了. 该方法和 上文提到的原生read方法其实类似. 基本格式为:
os.read(fd, n)
n: 获得n bytes的大小.
new_fd = os.open('text.txt',os.O_RDWR) print(os.read(new_fd,4)) # b"this" print(os.read(new_fd,4)) # b" wil"
同样, 该方法也会记录你的postion.
当基本操作完成时, 则需要将该fd 关闭, 以免发生内存 leek.基本格式很简单:
os.close(fd)
new_fd = os.open('text.txt',os.O_RDWR) os.close(new_fd)
使用close方法过后, 那么该fd 就不能使用了.
简单的基本操作, 就介绍到这里。 当然, 文件的操作可能还会涉及到锁, 权限更改等其他问题, 更多信息,可以参考 OS module
最后, 我们来总结一下吧: