文件读写

读写文件(文件是由字节组成的信息,在磁盘永久保存)是最常见的IO操作。文件分为文本文件和二进制文件。文本文件可以使用任何文本编辑器进行编辑,阅读起来比较容易,但对于程序来说却是困难的,需要相应的分析程序来解读,它通常比二进制的文件大,在网络传输方面是个严重问题。而二进制文件占据空间小,程序读起来比较容易,但人为阅读比较困难,在文本编辑器中打开会显示乱码。

文件对象

Python内置了读写文件的函数,用法和C是兼容的。读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘。而是通过“管道”来实现文件在磁盘和程序之间的传递,这个管道就是一个文件对象。所以,读写文件本质就是请求操作系统打开一个文件对象(通常称为文件描述符),然后通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。文件对象在建立连接时生成,由于信息在磁盘和程序之间移动,文件对象使用计算机主存来存储数据。

       有两种内建函数可以获取文件对象:open和file。他们的用法完全一样。下面以open()为例子讲解。获取一个文件对象(打开文件)的语法如下:

fileObj = open(filename,access_mode='r',buffering=-1)

其中filename要打开文件的路径(可以使用相对路径,相对于当前执行脚本)。access_mode用来标识文件打开的模式,默认为r(只读)。

常用的模式如下表所示:

文件模式                    解释

r                        以只读方式打开

w                        以写方式打开,文件不为空时清空文件;文件不存在时新建文件。

a                        追加模式,没有则创建

r+,w+,a+            以读写模式打开,a+:写在文件末尾,w+:写之前先清空文件内容,r+:写到文件任何位置

r、w、a为打开文件的基本模式,对应着只读、只写、追加模式;此外有b、t、+、U四个字符,可与以上的文件打开模式组合使用,分别表示二进制模式,文本模式,读写模式、通用换行符,根据实际情况组合使用。

其中b表示二进制模式访问,但是对于Linux或者unix系统来说这个模式没有任何意义,因为他们把所有文件都看作二进制文件,包括文本文件。第三个参数不经常用到,标识访问文件的缓冲方式,0代表不缓冲,1代表缓冲一行,-1代表使用系统默认缓冲方式。只要使用系统默认就好。

>>>fp=file("/root/filetest.txt",'w')

>>>dir(fp)

['__class__','__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__','__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__','__setattr__', '__str__', 'close', 'closed', 'encoding', 'fileno', 'flush','isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline','readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines','xreadlines']

>>> help(fp.write)

Help on built-in function write:

 

write(...)

   write(str) -> None.  Writestring str to file.

   

   Note that due to buffering, flush() or close() may be needed before

   the file on disk reflects the data written.

如果文件不存在,open()函数就会抛出一个IOError的错误,并且给出错误码和详细的信息告诉你文件不存在。文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的,由于文件读写时都有可能产生IOError,一旦出错,资源很可能得不到释放。如

>>>fp=file('/root/test.txty','r')

Traceback (most recent call last):

 File "", line 1, in

IOError: [Errno 2] No such file ordirectory: '/root/test.txty'

>>> fp

所以为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally机制调用close()方法正确关闭(销毁)文件对象,但是每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法。如

>>> withopen('/root/test.txty','r') as f:

...     f

...

Traceback (most recent call last):

 File "", line 1, in

IOError: [Errno 2] No such file ordirectory: '/root/test.txty'

>>> f

Traceback (most recent call last):

 File "", line 1, in

NameError: name 'f' is not defined

with语句给被使用到的文件创建了一个上下文环境,with控制块结束时,文件会自动关闭。

python中文件对象是一个迭代器(实现了next方法),这是因为Python的Iterator对象表示的是一个数据流。

>>> from collectionsimport Iterable

>>>

>>>

fp=open("/root/test.txt",'r')

>>>isinstance(fp,Iterable)

True

>>> 

>>>from collections import Iterator

>>>isinstance(fp,Iterator)

True

Python程序和文件之间建立连接后,即创造了所谓的“流”数据。流的一个重要组成部分是缓冲区,它位于主存中。流由操作系统管理,操作系统会确保当迭代需要使用下一行时,改行已经在内存中的缓冲区里,即使用流式传输的操作符每次只(从管道的前一部分)获取它所需要的数据来给出下一条结果。


读方法

python文件对象提供了三个“读”方法read()、readline()和readlines()。每种方法可以接受一个变量以限制每次读取的数据量。如对于一个文件

[root@localhost ~]# cat test.txt

test1 28 apple

test2 23 good

test3 34 bad

test4 26 apple

read() 每次读取整个文件中剩余的内容,它通常用于将读取的文件内容放到一个字符串变量中返回。默认无参数,即不限定返回字节数,如果文件大于可用内存,为了保险起见,可以反复调用read(size)方法,这样每次最多读取size个字节的内容。

>>> withopen('/root/test.txt','r') as fp:

...     retstr=fp.read(4)

...

>>> retstr

'test'

>>> 

readlines(),调用readlines()一次读取所有内容并按行返回一个list,各行内容作为其元素,该列表可以由Python 的for ... in ... 结构进行处理。

>>> withopen('/root/test.txt','r') as fp:

...     retlist=fp.readlines()

...

>>> retlist

['test1 28 apple\n', 'test2 23good\n', 'test3 34 bad\n', 'test4 26 apple\n']

>>> 

readline() 每次只读取一行,通常比readlines()慢得多。仅当没有足够内存可以一次读取整个文件时,才应该使用 readline()。

>>> withopen('/root/test.txt','r') as fp:

...     retstr=fp.readline()

...

>>> retstr

'test1 28 apple\n'

>>> 

因为文件对象是个迭代器,我们可以直接遍历文件对象获取每行,如

>>> fp=open('/root/test.txt','r')

>>> fp.readline()

'test1 28 apple\n'

>>> fp.readline()

'test2 23 good\n'

>>> fp.read()

'test3 34 bad\ntest4 26 apple\n'

>>> 

注意:这三种方法是把每行末尾的'\n'也读进来了,它并不会默认的把'\n'去掉,需要我们手动去掉。

如何读取大文件

如何操作大文件,比如10G一个文件,显然不能使用read()和readlines(),就算你的内存够大,这样一个文件都读取到内存里显然不是一个好办法,太浪费了内存了,另外从磁盘加载到内存页需要时间。是不是可以使用readline(),可以一行行读取,不过读的时候虽然是一行,可是不断的读取到内存最终还是会占用很大内存。

有两种方法可以达到节省内存的目的,要么每次控制读入的量,要么每次从文件对象中按行读入一条,内存占用比较稳定。

第一种方法是使用readlines(sizehint) 函数,通过指定读取的大小,大多数情况下,返回的数据的字节数会稍微比sizehint 指定的值大一点(除最后一次调用readlines(sizehint) 函数的时候)。通常情况下,Python会自动将用户指定的sizehint 的值调整成内部缓存大小的整数倍。

第二种方法是利用文件对象是迭代器的特性,每次读取一行到内存,处理后,然后再读取一行,也就是内存只保留一行。

>>>with open(FILE_PATH,encoding="utf-8", mode="r") asFILE_HANDLER:

# 这里并没有调用文件对象的read方法,此时这里这个文件对象是一个迭代器

 for line in FILE_HANDLER:

                  print(line)

Iterator对象可以被next()函数调用,并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据(只能前进,不能后退),所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

>>>fp=open('/root/test.txt','r')

>>>next(fp)

'test128 apple\n'

>>>next(fp)

'test223 good\n'

>>> 

>>> 

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。迭代器就是以时间换取空间,节省了空间,但是取值时间较长。

写文件

python文件对象提供了两个写方法:write() 和writelines()。

其中,write()方法和read()、readline()方法对应,是将字符串写入到文件中。writelines()方法和readlines()方法对应,也是针对列表的操作。它接收一个字符串列表作为参数,将他们写入到文件中,

写入文件时,换行符不会自动的加入,因此,需要显式的加入换行符。如

>>>with open('/root/test.txt','w') as f:

...     f.write('hello world'+'\n')

...     f.write('my world')

...

>>>f

       查看写入文件

[root@localhost~]# cat test.txt

helloworld

myworld[root@localhost ~]#

我们可以反复调用write()来写入文件,可见为了换行,必需显式的加入换行符。

当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。如

>>>fw=open('/root/test.txt','w')         #新创建一个文件对象

>>>fw.write('hello world'+'\n')

>>> 

>>>fr=open('/root/test.txt','r')         #读文件对象

>>>fr.readline()

''

>>>fw.close()

>>>fr.readline()

'helloworld\n'

>>> 

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容