文件和输入输出 - 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'