X Tutup
>Be on your guard! If another disciple sins, you must rebuke the offender, and if the same person sins against you seven times a day, adn turns back to you seven times and says, 'I repent,' you must forgive. (LUKE17:3-4) #文件(1) 文件,是computer姑娘中非常重要的东西。如在Linux操作系统中,所有的东西都被保存到文件中。 在Python里,它也很重要。只不过,Python 2和Python 3对它的态度有点不同。 在Python 2中,文件也是一种内建类型对象,其地位等同于前面已经学习过的列表、整数、字符串等类型。 在交互模式下,我们可以用`dir()`这种已经熟练的方法查看相关属性和方法。 >>> dir(file) ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines'] 然而,这一切在Python 3中都变了。在Python 3中,再没有`file`这个内建类型了。如果读者使用的是Python 3,执行`dir(file)`,会报错,并且显示`NameError: name 'file' is not defined`。 但,这并不妨碍我们对文件的研究。 暂且观察Python 2的`dir(file)`结果,里面有`__iter__`这个东西。曾经在讲述列表的时候,是不是也出现这个东西了呢?是的。它意味着这种类型的对象是可迭代的(iterable)。在下面的讲解中,你就会看到了,能够用for来读取其中的内容。 ##读文件 在某个文件夹下面建立了一个文件,名曰:130.txt,并且在里面输入了如下内容: learn python http://qiwsir.github.io qiwsir@gmail.com 此文件一共三行。 下图显示了这个文件的存储位置: ![](./1images/12601.png) 在上面截图中,我在当前位置输入了`python`,进入到交互模式。在这个交互模式下,这样操作: >>> f = open("130.txt") #打开已经存在的文件 >>> for line in f: ... print line #Python 3: print(line) ... learn python http://qiwsir.github.io qiwsir@gmail.com 提醒初学者注意,在那个目录里输入了启动Python交互模式的命令,那么,如果按照上面的方法`open("130.txt")`打开文件,就意味着这个文件130.txt是在当前文件夹内的。如果要打开其它文件夹内的文件,请用相对路径或者绝对路径来表示,从而让Python能够找到那个文件。 将打开的文件,赋值给变量`f`,这样也就是变量`f`跟对象文件130.txt用线连起来了(对象引用),本质上跟前面所讲述的其它对象进行赋值是一样的。 接下来,用`for`来读取文件中的内容,就如同读取一个前面已经学过的序列对象一样,把读到的文件中的每行,赋值给变量`line`。也可以理解为,用`for`循环一行一行地读取文件内容。每次扫描一行,遇到行结束符号`\n`表示本行结束,然后是下一行。 从打印的结果看出,每一行跟前面看到的文件内容中的每一行是一样的。只是行与行之间多了一空行,前面显示文章内容的时候,没有这个空行。或许这无关紧要,但是,还要深究一下,才能豁然。 在原文中,每行结束有本行结束符号`\n`,表示换行。`print line`或者`print(line)`默认情况下,打印完`line`的对象之后会增加一个`\n`。这样看来,在每行末尾就有两个`\n`,即:`\n\n`,于是在打印中就出现了一个空行。 >>> f = open('130.txt') >>> for line in f: ... print line, #Python 3: print(line, end='') ... learn python http://qiwsir.github.io qiwsir@gmail.com 如果读者完成了上述操作,紧接着做下面的操作: >>> for line2 in f: #在前面通过for循环读取了文件内容之后,再次读取, ... print line2 #然后打印,结果就什么也显示,这是什么问题? ... >>> 这不是什么错误,是因为前一次已经读取了文件内容,并且到了文件的末尾了。再重复操作,就是从末尾开始继续读了。当然显示不了什么东西,但是Python并不认为这是错误。后面会对此进行讲解。 在这里,如果要再次读取,那就从新`f = open('130.txt')`。有点麻烦!怎奈知识尚不充足。 使用Python 3的读者,这里要注意了,如果你已经执行了`f = open('130.txt')`,就是已经建立了一个文件对象,这时候可以使用`dir()`来查看这个对象的方法和属性了。 >>> f = open("130.txt") >>> dir(f) ['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read', 'readable', 'readline', 'readlines', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'writelines'] 不管两个版本的显示结果有哪些不同,它们相同的是都有`__iter__`属性,意味着在两个版本中,文件对象都是可迭代的。 特别提醒,因为我所演示的交互模式是在该文件所在目录启动的,所以,就相当于这个实验室和文件130.txt是同一个目录,这时候我们打开文件130.txt,就认为是在本目录中打开,如果文件不是在本目录中,需要写清楚路径。 比如:在上一级目录中(`~/Documents/ITArticles/BasicPython`),假如我进入到那个目录中,运行交互模式,然后试图打开130.txt文件。 ![](./1images/12602.png) >>> f = open("130.txt") Traceback (most recent call last): File "", line 1, in IOError: [Errno 2] No such file or directory: '130.txt' >>> f = open("./codes/130.txt") #必须得写上路径了(注意,windows的路径分隔符与此不同。) >>> for line in f: ... print line ... learn python http://qiwsir.github.io qiwsir@gmail.com 读文件,只是针对文件的操作之一,还有创建文件。 ##创建文件 上面的实验中,打开的是一个已经存在的文件。如何创建文件呢? >>> nf = open("131.txt", "w") >>> nf.write("This is a file") >>> nf.close() 就这样创建了一个文件?并写入了文件内容呢?看看再说: ![](./1images/12603.png) 真的就这样创建了新文件,并且里面有那句话呢。 创建文件,我们同样是用`open()`这个函数,但是多了个`"w"`,这是在告诉Python用什么样的模式打开文件。也就是说,用`open()`操作文件,可以有不同的模式。看下表: | 模式 | 描述 | |------|------| | r | 以读方式打开文件,可读取文件信息。| | w | 以写方式打开文件,可向文件写入信息。如文件存在,则清空该文件,再写入新内容 | | a | 以追加模式打开文件(即一打开文件,文件指针自动移到文件末尾),如果文件不存在则创建 | | r+ | 以读写方式打开文件,可对文件进行读和写操作。 | | w+ | 消除文件内容,然后以读写方式打开文件。 | | a+ | 以读写方式打开文件,并把文件指针移到文件尾。 | | b | 以二进制模式打开文件,而不是以文本模式。该模式只对Windows或Dos有效,类Unix的文件是用二进制模式进行操作的。 | 从表中不难看出,不同模式下打开文件,可以进行相关的读写。那么,如果什么模式都不写,像前面那样呢?那样就是默认为r模式,只读的方式打开文件。 >>> f = open("130.txt") >>> f >>> f = open("130.txt","r") >>> f Python 3中显示的结果信息更丰富、明确。 >>> f <_io.TextIOWrapper name='130.txt' mode='r' encoding='cp936'> 可以用这种方式查看当前打开的文件是采用什么模式的,上面显示,两种模式是一样的效果,如果不写那个`"r"`,就默认为是只读模式了。下面逐个对各种模式进行解释 **"w":以写方式打开文件,可向文件写入信息。如文件存在,则清空该文件,再写入新内容** 131.txt这个文件是存在的,前面建立的,并且在里面写了一句话:This is a file >>> fp = open("131.txt") >>> for line in fp: #原来这个文件里面的内容 ... print line #Python 3: print(line) ... This is a file >>> fp = open("131.txt","w") #这时候再看看这个文件,里面还有什么呢?是不是空了呢? >>> fp.write("My name is qiwsir.\nMy website is qiwsir.github.io") #再查看内容 >>> fp.close() 查看文件内容: $ cat 131.txt #cat是linux下显示文件内容的命令,这里就是要显示131.txt内容 My name is qiwsir. My website is qiwsir.github.io **"a":以追加模式打开文件(即一打开文件,文件指针自动移到文件末尾),如果文件不存在则创建** >>> fp = open("131.txt","a") >>> fp.write("\nAha,I like program\n") #向文件中追加 >>> fp.close() #这是关闭文件,一定要养成一个习惯,写完内容之后就关闭 查看文件内容: $ cat 131.txt My name is qiwsir. My website is qiwsir.github.io Aha,I like program 其它项目就不一一讲述了。看官可以自己实验。 ##使用with 在对文件进行写入操作之后,一定要牢记一个事情:`file.close()`,这个操作千万不要忘记,忘记了怎么办,那就补上吧,也没有什么天塌地陷的后果。 有另外一种方法,能够不用这么让人揪心,实现安全地关闭文件。 >>> with open("130.txt","a") as f: ... f.write("\nThis is about 'with...as...'") ... >>> with open("130.txt","r") as f: ... print f.read() ... learn python http://qiwsir.github.io qiwsir@gmail.com hello This is about 'with...as...' >>> 这里就不用close()了。而且这种方法更有Python味道,或者说是更符合Pythonic的一个要求。 ------ [总目录](./index.md)   |   [上节:语句(5)](./125.md)   |   [下节:文件(2)](./127.md) 如果你认为有必要打赏我,请通过支付宝:**qiwsir@126.com**,不胜感激。
X Tutup