python读写方式
python的读写,在实际应用中还是很广泛的,有必要系统性的学习一下,以便于处理问题时的抉择和对现象的合理解释。例如,python用logging写入日志文件默认的读写方式是“a”(在文件尾追加日志记录);将生成的字符串列表加入到文件中,一般会用到“a+”;打开文件进行读取显示会用到open(‘filename’,‘r’)......
r | 以只读模式打开文件 | 光标在文件开头 | 如果文件不存在,则出错 |
r+ | 以读写模式打开文件 | 光标在文件开头 | 如果文件不存在,则出错。读写都可以移动光标。写入时,如果光标不在文件末尾,则会覆盖源文件 |
w | 以只写模式打开文件 | 光标在文件开头 | 如果文件不存在,则创建文件,如果文件已存在,则从文件头开始覆盖文件。如果写入内容比源文件少,则会保留未覆盖的内容 |
w+ | 以读写模式打开文件 | 光标在文件开头 | 如果文件不存在,则会创建文件。文件已存在,从光标位置覆盖文件。读写都可以移动光标。 |
a | 以只写模式打开文件 | 光标在文件结尾,追加模式 | 文件不存在是,创建文件。文件存在时,打开时,光标在文件末尾,写入不覆盖源文件 |
a+ | 以读写模式打开文件 | 光标在文件结尾,追加模式 | 文件不存在是,创建文件。文件存在时,打开时,光标在文件末尾,写入不覆盖源文件。 |
b | 与前面六种结合使用,以二进制方式读或者写(e.g. open('filename','rb')) (为什么要用到b下文有详解) |
python常见读写操作指令
1. f.read([size]) # size可有可无
该方法从文件当前位置起读取size个字节,若无参数size,则表示读取至文件结束为止。注意,此处按字符来读入,一个汉字为一个字符。
2. f.readline( ) # size可有可无,都只读取一行
从字面意思可以看出,该方法每次读出一行内容,所以,读取时占用内存小,比较适合大文件,该方法返回一个字符串对象。
3. f.readlines( ) # size可有可无,都读取到文件尾
该方法读取整个文件所有行,保存在一个列表(list)变量中,每行作为一个元素,但读取大文件会比较占内存。
4. linecache模块
用于输出某个文件的第n行,用法如下:
line2 = linecache.getline(‘lines.txt',2) # print the 2nd line
print line2
5. f.write( )
将数据写入文件,用法为f.write('strings')
6. f.writelines()
将多行数据写入文件中,数据以列表的方式提供:
f.writelines(['11\n','22\n',...'66\n'])
7. f.tell( )
可以将文件指针的当前指向的位置读出(即光标位置)
8. f.seek()
将光标位置移至所需位置。用法: f.seek(offset,whence=0)
offset:开始偏移量,也就是代表需要移动偏移的字节数。
whence:给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起,默认为0。注意,此处偏移量是按字节计算,也就是一个汉字最少需要两个偏移量。如果偏移量正好讲一个汉字分开,则会报错。
whence常量:
os.SEEK_SET: 0 相对文件起始位置
os.SEEK_CUR: 1 相对文件的当前位置
os.SEEK_END: 2 相对文件的结束位置
>>> f.close()
>>> f=open('2.txt','w+')
>>> f.write('123')
>>> f.tell() #当前文件指针的位置
3
>>> import os #导入OS
>>> f.seek(-3,os.SEEK_CUR)#在文件指针当前的位置-3,就是移到开始位置,由此读出了刚刚写入在2.txt中的123的内容
>>> f.read()
'123'
9. f.truncate( [size]) # size可有可无
当不指定size的时候,表示从光标位置删除后面内容;当指定size之后,表示从文件头开始,保留size个字节的字符(同上,中文按两个字节计算)
10. f.flush( )
将内存内容立即写入硬盘
11. f.close() # 一定不要忘记!!!
关闭文件。接下来普及一下不关闭文件的后果:
close()是为了释放资源。 如果不close(),那就要等到垃圾回收时,自动释放资源。垃圾回收的时机是不确定的,也无法控制的。
如果程序是一个命令,很快就执行完了,那么可能影响不大(注意:并不是说就保证没问题)。
但如果程序是一个服务,或是需要很长时间才能执行完,或者很大并发执行,就可能导致资源被耗尽,也有可能导致死锁。
另外,缓存的信息可能会意外丢失,文件可能会损坏。因为我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险,同时这也个比较 pythonic 的方式:
with open('close.txt', 'w') as f:
f.write('remember it please!')
Q:为什么要用‘b’来进行读写呢?
A : 从两个方面讨论:
写文件时,对于字符串x='abc\ndef',我们可用len(x)得到它的长度为7,\n我们称之为换行符,实际上是0x0A。当我们用'w'即文本方式写的时候,在windows平台上会自动将'0x0A'变成两个字符'0x0D','0x0A',即文件长度实际上变成8。当用'r'文本方式读取时,又自动的转换成原来的换行符。 如果换成'wb'二进制方式来写的话,则会保持一个字符不变,读取的时候也是原样读取。 所以如果用文本方式写入,用二进制方式读取的话,就要考虑这多出的一个字节了。'0x0D'也称回车符。 Linux下不会变,因为linux只使用'0X0A'来表示换行。
读文件时,直到读到文档结束符(EOF)才算读取到文件最后,Python会认为字节\x1A(26)转换成的字符为文档结束符(EOF), 故使用'r'进行读取二进制文件时,可能会出现文档读取不全的现象。
例如:
二进制文件中存在如下从低位向高位排列的数据:7F 32 1A 2F 3D 2C 12 2E 76
如果使用'r'进行读取,则读到第三个字节,即认为文件结束。
如果使用'rb'按照二进制位进行读取的,不会将读取的字节转换成字符,从而避免了上面的错误。
方案:
二进制文件就用二进制方法读取'rb'
总结:
使用'r'的时候,如果碰到'0x1A',就视为文件结束,就是EOF,使用'rb'则不存在这个问题。也就是说,如果你用二进制写入再用文件读出的话,如果其中存在'0x1A',就只会读出文件的一部分,使用'rb'会一直读取文件末尾。