lsdwyl 发表于 2018-8-14 13:13:14

Python学习--13 文件I/O

  Python内置了读写文件的函数,用法和C是兼容的。
  读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。
读取文件内容
# coding: utf-8  

  
f = open('test.txt', 'r')
  
print(f.read())
  
f.close()
  输出:
Hello world!  
Python
  标示符'r'表示读。
  如果打开的文件不存在,会直接报错:
Traceback (most recent call last):  
File "/Projects/python/code/file.py", line 3, in <module>
  
    f = open('test.txt1', 'r')
  
IOError: No such file or directory: 'test.txt1'
  报错后,后面的f.close()不会调用。一般我们会使用try ... finally来操作文件:
try:  
    f = open('test.txt', 'r')
  
    print(f.read())
  
finally:
  
    if f:
  
      f.close()
  但是每次都这么写还是太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:
with open('test.txt', 'r') as f:  
    print(f.read())
  这和前面的try ... finally是一样的,但是代码更佳简洁,并且不必调用f.close()方法。
  如果文件很大,使用read()方法一下子读到内存,内存会占满。保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。
  另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list:
with open('test.txt', 'r') as f:  
    for line in f.readlines():
  
      print(line)
打开二进制文件
  要读取二进制文件(例如图片、音频、视频)内容,使用rb模式打开:
>>> f = open('test.jpg', 'rb')  
>>> f.read()
  
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节
读取非utf-8编码的文本
  如果要读取非utf-8编码的文本,需要给open()传入编码参数encoding,默认是utf-8:
>>> f = open('gbk.txt', 'r', encoding = 'gbk')  
>>> f.read()
  
'测试GBK'
  如果不传入,读取的内容是乱码的。
  open()还支持第4个参数errors,用于当读取的内容编码不规范(会返回UnicodeDecodeError错误),示例:
>>> f = open('gbk.txt', 'r', encoding = 'gbk', errors='ignore')  这样将忽略错误。
写入内容到文件
with open('test.txt', 'w') as f:  
    f.write('test\n')
  要写入特定编码的文本文件,请给open()函数传入encoding参数,将字符串自动转换成指定编码。
读取大文件方法
  方法一:将文件切分成小段,每次处理完小段,释放内存
def read_in_block(file_path):  
  BLOCK_SIZE=1024
  
  with open(file_path,"r") as f:
  
    while True:
  
      block =f.read(BLOCK_SIZE) #每次读取固定长度到内存缓冲区
  
      if block:
  
        yield block
  
      else:
  
        return #如果读取到文件末尾,则退出
  

  
for block in read_in_block(file_path):
  
  print block
  这个方法,速度很快,但有个问题,若满足了1024时,会将正好在1024位置的数据切开。
  方法二:利用open()方法生成的迭代对象:
with open(file_path) as f:  
    for line in f:
  
      print line
  这种用法是把文件对象f当作迭代对象,系统将自动处理IO缓存和内存管理。
  耗时较第1种方法慢一点。 但每个Line, type都是str, 都是自己需要的一行数据(一行是一个id)。
文件打开模式
模式描述r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。r+打开一个文件用于读写。文件指针将会放在文件的开头。rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。w打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。wb以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。w+打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。wb+以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。file-like Object
  像open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行。
  StringIO就是在内存中创建的file-like Object,常用作临时缓冲。
StringIO
  StringIO就是在内存中读写str。
  读取:
# coding : utf-8  

  
from io import StringIO
  
with StringIO('hello\nworld\n') as f:
  
    while True:
  
      s = f.readline()
  
      if s == '':
  
            break
  
      print(s.strip())
  输出:
hello  
world
  写入:
from io import StringIO  

  
with StringIO() as f:
  
    f.write('hello\nworld\n')
  
    print(f.getvalue())
  输出:
hello  
world
  getvalue()方法用于获得写入后的str。
BytesIO
  BytesIO就是在内存中读写二进制数据。
  写入:
# coding:utf-8  
from io import BytesIO
  

  
with BytesIO() as f:
  
    f.write('测试Bytes'.encode('utf-8'))
  
    print(f.getvalue())
  输出:
b'\xe6\xb5\x8b\xe8\xaf\x95'  注意这里写入的是经过UTF-8编码的bytes。
  读取:
# coding:utf-8  
from io import BytesIO
  

  
with BytesIO(b'\xe6\xb5\x8b\xe8\xaf\x95') as f:
  
    print(f.read())
  输出:
b'\xe6\xb5\x8b\xe8\xaf\x95'  StringIO和BytesIO是在内存中操作str和bytes的方法,使得和读写文件具有一致的接口。
操作文件和目录
  Python内置的os模块可以直接调用操作系统提供的接口函数来操作文件和目录。
查看系统信息
>>> import os  
>>> os.name
  
'nt'
  
>>> os.environ
  
environ({'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.wlua;.lexe;.PY', ...})
  要获取某个环境变量的值,可以调用os.environ.get('key')。
  unix操作系统提供os.uname()来获取详细的系统信息。
操作文件和目录
>>> import os  

  
# 查看当前目录的绝对路径:
  
>>> os.path.abspath('.')
  
'/Projects/python/code'
  

  
# 把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符:
  
>>> os.path.join('/Projects', 'python')
  
'/Projects/python'
  

  
# 把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:
  
>>> os.path.split('/Projects/python/code/os.py')
  
('/Projects/python/code', 'os.py')
  
>>> os.path.split('/Projects/python/code/')
  
('/Projects/python/code', '')
  
>>> os.path.split('/Projects/python/code')
  
('/Projects/python', 'code')
  

  
# 获取文件扩展名:
  
>>> os.path.splitext('/Projects/python/code/os.py')
  
('/Projects/python/code/os', '.py')
  

  
# 然后创建一个目录:
  
>>> os.mkdir('/Projects/python/code/testdir')
  

  
# 删掉一个目录:
  
>>> os.rmdir('/Projects/python/code/testdir')
  

  
# 对文件重命名:
  
>>> os.rename('test.txt', 'test.py')
  

  
# 删掉文件:
  
>>> os.remove('test.py')
复制文件
  os模块中并没有复制文件的方法。原因是复制文件并非由操作系统提供的系统调用。
  幸运的是shutil模块提供了copyfile()的函数,我们还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充。
# coding : utf-8  
import shutil
  

  
shutil.copyfile('os.py', 'os2.py')
列出目录内容
# coding : utf-8  
import os
  

  
dirs = os.listdir('.')
  
L = []
  
for d in dirs:
  
    if os.path.isdir(d):
  
      L.append(d)
  
print(L)
  输出:
['.idea', 'class', 'module']  当然,利用Python的列表生成式,可以很简单:
L =   
print(L)
  要列出所有的.py文件:
L = == '.py']  
print(L)
  输出:
['ostest.py', 'ostest2.py']
页: [1]
查看完整版本: Python学习--13 文件I/O