文件和输入输出 - QLGQ/learning-python GitHub Wiki
文件对象
文件只是连续的字节序列,数据的传输经常会用到字节流,无论字节流是由单个字节还是大块数据组成。
文件内建函数(open()和file())
作为打开文件之门的“钥匙”,内建函数open()[以及file()]提供了初始化输入/输出(I/O)操作的通用接口。open()内建函数成功打开文件后会返回一个文件对象,否则引发一个错误。当操作失败,Python会产生一个IOError异常。内建函数open()的基本语法是:
file_object = open(file_name, access_mode='r', buffering=-1)
file_name是包含要打开的文件名字的字符串,它可以是相对路径或者绝对路径。可选变量access_mode也是一个字符串,代表文件打开的模式。通常,文件使用模式‘r’,‘w’,或是‘a’模式来打开,分别代表读取,写入和追加。还有个‘U’模式,代表通用换行符支持。
使用‘r’或‘U’模式打开的文件必须是已经存在的。使用‘w’模式打开的文件若存在则首先清空,然后(重新)创建。以‘a’模式打开的文件是为追加数据做准备的,所有写入的数据都将追加到文件的末尾,即使你seek到了其他的地方。如果文件不存在,将被自动创建,类似以‘w’模式打开文件。如果没有给定access_mode,它将自动采用默认值‘r’。
另外一个可选参数buffering用于指示访问文件所采用的缓冲方式。其中0表示不缓冲,1表示只缓冲一行数据,任何其他大于1的值代表使用给定值作为缓冲区大小。不提供该参数或者给定负值代表使用系统默认缓冲机制,即对任何类电报机(tty)设备使用行缓冲,其他设备使用正常缓冲。一般情况下使用系统默认方式即可。
文件对象的访问模式
文件模式 | 操作 |
---|---|
r | 以读方式打开 |
rU或U | 以读方式打开,同时提供通用换行符支持 |
w | 以写方式打开(必要时清空) |
a | 以追加模式打开(从EOF开始,必要时创建新文件) |
r+ | 以读写模式打开 |
w+ | 以读写模式打开 |
a+ | 以读写模式打开 |
rb | 以二进制读模式打开 |
wb | 以二进制写模式打开 |
ab | 以二进制追加模式打开 |
rb+ | 以二进制读写模式打开 |
wb+ | 以二进制读写模式打开 |
ab+ | 以二进制读写模式打开 |
‘+’代表可读可写,‘b’代表二进制模式访问。
关于‘b’有一点需要说明,对于所有POSIX兼容的Unix系统(包括Linux)来说,‘b’是可有可无的,因为它们把所有的文件当作二进制文件,包括文本文件。
open()和file()函数具有相同的功能,可以任意替换。您所看到任何使用open()的地方,都可以使用file()替换它。
通用换行符支持(UNS)
UNS(Universal NEWLINE Support,cifan通用换行符支持):当你使用'U'标志打开文件的时候,所有的行分隔符(或行结束符,无论它原来是什么)通过Python的输入方法返回时都会被替换为换行符NEWLINE(\n)。(‘rU’模式也支持‘rb’选项)。这个特性还支持包含不同类型行结束符的文件。文件对象的newlines属性会记录它曾“看到的”文件的行结束符。
如果文件刚被打开,程序还没有遇到行结束符,那么文件的newlines为None。在第一行被读取后,它被设置为第一行的结束符。如果遇到其他类型的行结束符,文件的newlines会成为一个包含每种格式的元组。注意UNS只用于读取文本文件。没有对应的处理文件输出的方法。
文件内建方法
open()成功执行并返回一个文件对象之后,所有对该文件的后续操作都将通过这个“句柄”进行。文件方法可以分为四类:输入、输出、文件内移动及杂项操作。
输入
- read()方法用来直接
读取字节到字符串中
,最多读取给定数目个字节。如果没有给定size参数(默认值为-1)或者size值为负,文件将被读取直至末尾。 - readline()方法读取打开文件的一行(读取下个行结束符之前的所有字节)。
然后整行,包括行结束符,作为字符串返回。
和read()相同,它也有一个可选的size参数,默认为-1,代表读至行结束符。如果提供了该参数,那么在超过size个字节后会返回不完整的行。 - readlines()方法并不像其他两个输入方法一样返回一个字符串。
它会读取所有(剩余的)行然后把它们作为一个字符串列表返回。
它的可选参数sizhint代表返回的最大字节大小。如果它大于0,那么返回的所有行应该大约有sizhint字节(可能稍微大于这个数字,因为需要凑齐缓冲区大小)。
输出
- write()内建方法的功能与read()和readline()相反。它把含有文本数据或二进制数据块的字符串写入到文件中去。
- 和readlines()一样,
writelines()方法是针对列表的操作,它接受一个字符串列表作为参数,将它们写入文件
。行结束符并不会被自动加入,所以如果需要的话,你必须在调用writelines()前给每行结尾加上行结束符。
注意这里并没有“writeline()”方法,因为它等价于使用以行结束符结尾的单行字符串调用write()方法。
保留行分隔符
当使用输入方法如read()或者readlines()从文件中读取行时,Python并不会删除行结束符,这个操作被留给了程序员。例如这样的代码在Python程序中很常见:
f = open('myfile', 'r')
data = [line.strip() for line in f.readlines()]
f.close()
类似地,输出方法write()或writelines()也不会自动加入行结束符。你应该在向文件写入数据前自己完成。
文件内移动
seek()方法可以在文件中移动文件指针到不同位置。offset字节代表相对于某个位置偏移量。位置的默认值为0,代表从文件开头算起(即绝对偏移量),1代表从当前位置算起,2代表从文件末尾算起。当人们打开文件进行读写操作的时候就会接触到seek()方法。text()方法是对seek()的补充,它告诉你当前文件指针在文件中的位置——从文件起始算起,单位为字节。
文件迭代
一行一行访问文件很简单:
for eachLine in f:
在这个循环里,eachLine代表文本文件的一行(包括末尾的行结束符),你可以使用它做任何想做的事情。 文件对象成为了它们自己的迭代器,这意味着用户不必调用read*()方法就可以在for循环中迭代文件的每一行
。
另外,我们也可以使用迭代器的next()方法,file.next()可以用来读取文件的下一行。和其他迭代器一样,Python也会在所有行迭代完成后引发StopIteration异常。
行分隔符和其他文件系统的差异
- **操作系统间的差异之一是它们所支持的行分隔符不同。**在POSIX(Unix系列或MacOS X)系统上,行分隔符是换行符NEWLINE(\n)字符。在旧的MacOS下是RETURN(\r),而DOS和Wind32系统下结合使用了两者(\r\n)。
- **另一个不同是路径分隔符。**POSIX使用“/”; DOS和Windows使用“\”;旧版本的MacOS使用“:”。它用来分隔文件路径名;标记当前目录和父目录。
文件对象的内建方法列表
文件对象方法 | 操作 |
---|---|
file.close() | 关闭文件 |
file.fileno() | 返回文件的描述符(file descriptor, FD, 整型值) |
file.flush() | 刷新文件的内部缓冲区 |
file.isatty() | 判断file是否是一个类tty设备 |
file.next() | 返回文件的下一行(类似于file.readline()),或在没有其他行时引发StopIteration异常 |
file.read(size=-1) | 从文件读取size个字节,当未给定size或给定负值的时候,读取剩余的 所有字节,然后作为字符串返回 |
file.readinto(buf, size) | 从文件读取size个字节到buf缓冲器(已不支持) |
file.readline(size=-1) | 从文件读取并返回一行(包括行结束符),或返回最大size个字符 |
file.readlines(size=0) | 读取文件的所有行并作为一个列表返回(包含所有的行结束符);如果给定sizhint且大于0,那么将返回总和大约为sizhint字节的行(大小由缓冲器容量的下一个值决定)(比如说缓冲器的大小只能为4K的倍数,如果sizhint为15K,则最后返回的可能是16K) |
file.xreadlines() | 用于迭代,可以替换readlines()的一个更高效的方法 |
file.seek(off, whence=0) | 在文件中移动文件指针,从whence(0代表文件起始,1代表当前位置,2代表文件末尾)偏移off字节 |
file.tell() | 返回当前在文件中的位置 |
file.truncate(size=file.tell()) | 截取文件到最大size字节,默认为当前文件位置 |
file.write(str) | 向文件写入字符串 |
file.writelines(seq) | 向文件写入字符串序列seq,seq应该是一个返回字符串的可迭代对象,在Python2.2前,它只是字符串的列表 |
文件内建属性
文件对象的属性
文件对象的属性 | 描述 |
---|---|
file.closed | 表示文件已经被关闭,否则为False |
file.encoding | 文件所使用的编码——当Unicode字符串被写入数据时,它们将自动使用file.encoding转换为字节字符串,若file.encoding为None时使用系统默认编码 |
file.mode | Access文件打开时使用的访问模式 |
file.name | 文件名 |
file.newlines | 未读取到行分隔符时为None,只有一种行分隔符时为一个字符串,当文件有多种类型的行结束符时,则为一个包含所有当前所遇到的行结束符的列表 |
file.softspace | 为0表示在输出一数据后,要加上一个空格符,1表示不加。这个属性一般程序员用不着,由程序内部使用 |
标准文件
一般说来,只要你的程序一执行,你就可以访问3个标准文件。它们分别是标准输入(一般是键盘)、标准输出(到显示器的缓冲输出)和标准错误i(到屏幕的非缓冲输出)(这里所说的“缓冲”和“非缓冲”是指open()函数的第3个参数)。
print语句会自动在要输出的字符串后加上换行符。
文件系统
os模块的文件/目录访问函数
函数 | 描述 |
---|---|
文件处理 | |
mkfifo()/mknod() | 创建命名管道/创建文件系统节点 |
remove()/unlink() | Delete file(删除文件) |
rename()/renames() | 重命名文件 |
stat() | 返回文件信息 |
symlink() | 创建符号链接 |
utime() | 更新时间戳 |
tmpfile() | 创建并打开('w+b')一个新的临时文件 |
walk() | 生成一个目录树下的所有文件名 |
目录/文件夹 | |
chdir()/fchdir() | 改变当前工作目录/通过一个文件描述符改变当前工作目录 |
chroot() | 改变当前进程的根目录 |
listdir() | 列出指定目录的文件 |
getcwd()/getcwdu() | 返回当前工作目录/功能相同,但返回一个Unicode对象 |
mkdir()/makedirs() | 创建目录/创建多层目录 |
rmdir()/removedirs() | 删除目录/删除多层目录 |
访问/权限 | |
access() | 检验权限模式 |
chmod() | 改变权限模式 |
chown()/lchown() | 改变owner和group ID/功能相同,但不会跟踪链接 |
umask() | 设置默认权限模式 |
文件描述符操作 | |
open() | 底层的操作系统open(对于文件,使用标准的内建open()函数 ) |
read()/write() | 根据文件描述符读取/写入数据 |
dup()/dup2() | 复制文件描述符号/功能相同, 但是是复制到另一个文件描述符 |
设备号 | |
makedev() | 从major和minor设备号创建一个原始设备号 |
major()/minor() | 从原始设备号获得major/minor设备号 |
os.path模块中的路径名访问函数
函数 | 描述 |
---|---|
分割 | |
basename() | 去掉目录路径,返回文件名 |
dirname() | 去掉文件名, 返回目录路径 |
join() | 将分离的各部分组合成一个路径名 |
split() | 返回(dirname(), basename())元组 |
splitdrive() | 返回(drivename, pathname)元组 |
splitext() | 返回(filename, extension)元组 |
信息 | |
getatime() | 返回最近访问时间 |
getctime() | 返回文件创建时间 |
getmtime() | 返回最近文件修改时间 |
getsize() | 返回文件大小(以字节为单位) |
查询 | |
exists() | 指定路径(文件或目录)是否存在 |
isabs() | 指定路径是否为绝对路径 |
isdir() | 指定路径是否存在且为一个目录 |
isfile() | 指定路径是否存在且为一个文件 |
islink() | 指定路径是否存在且为一个符号链接 |
ismount() | 指定路径是否存在且为一个挂载点 |
os和os.path模块实例
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import os
for tmpdir in ('/tmp', r'c: \temp'):
if os.path.isdir(tmpdir):
break
else:
print 'no temp directory available'
tmpdir = ''
if tmpdir:
os.chdir(tmpdir)
cwd = os.getcwd()
print '*** current temporary directory'
print cwd
print '*** creating example directory...'
os.mkdir('example2')
os.chdir('example2')
cwd = os.getcwd()
print '*** new working directory: '
print cwd
print '*** original directory listing: '
print os.listdir(cwd)
print '*** creating test file...'
fobj = open('test', 'w')
fobj.write('foo\n')
fobj. write('bar\n')
fobj. close()
print '*** updated directory listing: '
print "*** renaming 'test' to 'filetest.txt'"
os.rename('test', 'filetest.txt')
print '*** updated directory listing: '
print os.listdir(cwd)
path = os.path.join(cwd, os.listdir(cwd)[0])
print '*** full file pathname'
print path
print '*** (pathname, basename) =='
print os.path.split(path)
print '*** (filename, extension) =='
print os.path.splitext(os.path.basename(path))
print '*** displaying file contents: '
fobj = open(path)
for eachLine in fobj:
print eachLine,
fobj.close()
print '*** deleting test file'
os.remove(path)
print '*** updated directory listing: '
print os.listdir(cwd)
os.chdir(os.pardir)
print '*** deleting test directory'
os.rmdir('example2')
print '*** DONE'