本文引用至: python 文件

在了解基本的Python的built-in trick 比如, Iterator, Generator, datatype 等等. 接着, 我们就应该继续深入,了解一下编程的两大块, 1. 文件, 2. 网络.
so, 这里我们先来了解一下关于python中的文件操作。
python基本的文件操作全在built-in object file中. 一些基本的CRUD 操作, 可以完全在这个原生的file中完成. 那应该怎样创建一个file object呢?

open()

使用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 写.

读取文件

read()

这里, 我们先进行文件的读操作.
基本 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()

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(结尾部分的序号)

介绍完,怎么读文件, 那么接下来就该如何写文件了,

write()

在python中的如何写文件, 实际上和你一开始打开文件的方式是有关系的, 比如你是直接写入开头(r+), overwrite(w+), 或是 在尾部添加(a+).

text = open('text.txt','a+');
print(text.write("this is the second line")) # 29

他会返回写入的其实位置
其他的,大家可以自己试验一下.
另外,python还提供了其他关于文件写入的操作-- writable,writelines(list)

writable

该方法用来表示当前写入流是否可以继续写入, 比如你使用r mode 时, 则会返回False. 如果可以继续写入,则返回True.

text = open('text.txt','a+');
print(text.writable()) # True

writelines()

和readlines是类似的, 该可以写入多段文本, 如果你想写入多行的话, 则段尾则需要使用的是\n. 接受的是list参数。

writelines(list)

input_file = ["first line\n","second line \n"];
print(text.writelines(input_file))

当你读完,写完之后, 你就可以把该文件给关闭掉了.

close()

当你的打开了一个文件过后,读取相关的信息,如果你不需要该文件了,你就可以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:
fileObject

文件的辅助操作

文件的重命名和删除.

这就很easy了:

rename

直接修改文件的名字, 这是os模块提供的方法. 基本格式为:

rename(current,changed)

text = open('text.txt','a+')
os.rename('text.txt','change.txt')

remove

用来直接删除文件.格式为:

remove(fileName)

用来直接删除文件. 需要注意的是fileName必须为完整文件名(需要带上后缀)

text = open('text.txt','a+')
os.remove('change.txt')

另外,还有一个方法 unlink, 该方法和remove方法,并没有半点差别, 只是遵循了原来的Unix name. 其他的, 你懂得。。。

上面就是两个基本的文件操作方法,接下来我们来看看文件目录的操作方法.

基本目录操作

首先,应该就是文件目录的创建.

mkdir()

基本格式为:

mkdir(fileName)

这个就很简单了. 直接看demo吧:

os.mkdir('new Directory')

但是,当文件已经存在时,他会返回FileExistsError的错误.(这就尴尬了)

当如果你是在进行交互程序时, 那么可能就会涉及到文件目录改变的操作--chdir()

chdir

基本格式为:

chdir(path)

相对于当前目录进行文件目录的变更.

chdir('~/Desktop')

另外, 你还可以获得当前的目录名:

getcwd()

该方法是返回绝对路径:

print(os.getcwd()) # /Users/jimmy_thr/Desktop

当我们创建一个空目录时, 想要更换他的名字时, 这里就有两种方法: 1. 删除重建. 2. 直接重命名. 2333 如果你没傻,应该都会选第二种. 这里,我顺便把,目录的删除一起介绍了.

rmdir()

基本格式为:

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.

围绕fd 的相关操作

还记得开头所说的built-in method open 方法吗?
该open 只是存粹的返回一个file Object. 并不是返回fd. fd是什么呢?

科普一下: fd(file descriptor) 他是用来描述文件的唯一性的. 你可以通过他来对文件进行访问. 反正,你只要记住, 他实际上就和你的文件路径是一样的道理

上面只是一个很简单的说明, 其他的内容, 可以自行google wiki. 里面的内容还是挺复杂的...
so, cut out all this nonsense

open

该方法是我们获得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 来表示(主要还是懒)

write

当你使用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方法了. 该方法和 上文提到的原生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.

close

当基本操作完成时, 则需要将该fd 关闭, 以免发生内存 leek.基本格式很简单:

os.close(fd)

new_fd = os.open('text.txt',os.O_RDWR)
os.close(new_fd)

使用close方法过后, 那么该fd 就不能使用了.

简单的基本操作, 就介绍到这里。 当然, 文件的操作可能还会涉及到锁, 权限更改等其他问题, 更多信息,可以参考 OS module

最后, 我们来总结一下吧:

python os module


villainhr
7.8k 声望2.2k 粉丝