读文件
打开一个文件用 open()方法 (open() 返回一个文件对象, 它是可迭代的):
>>> f = open('test.txt', 'r')
r 表示是文本文件, rb 是二进制文件.(这个 mode 参数默认值就是 r)
如果文件不存在, open()函数就会抛出一个 IOError 的错误, 并且给出错误码和详细的信息告诉你文件不存在:
- >>> f=open('test.txt', 'r')
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
文件使用完毕后必须关闭, 因为文件对象会占用操作系统的资源, 并且操作系统同一时间能打开的文件数量也是有限的
>>> f.close()
由于文件读写时都有可能产生 IOError, 一旦出错, 后面的 f.close()就不会调用. 所以, 为了保证无论是否出错都能正确地关闭文件, 我们可以使用 try ... finally 来实现:
- try:
- f = open('/path/to/file', 'r')
- print(f.read())
- finally:
- if f:
- f.close()
但是每次都这么写实在太繁琐, 所以, Python 引入了 with 语句来自动帮我们调用 close()方法:
- with open('/path/to/file', 'r') as f:
- print(f.read())
python 文件对象提供了三个 "读" 方法: read(),readline() 和 readlines(). 每种方法可以接受一个变量以限制每次读取的数据量.
read() 每次读取整个文件, 它通常用于将文件内容放到一个字符串变量中. 如果文件大于可用内存, 为了保险起见, 可以反复调用 read(size)方法, 每次最多读取 size 个字节的内容.
readlines() 之间的差异是后者一次读取整个文件, 象 .read() 一样..readlines() 自动将文件内容分析成一个行的列表, 该列表可以由 Python 的 for ... in ... 结构进行处理.
readline() 每次只读取一行, 通常比 readlines() 慢得多. 仅当没有足够内存可以一次读取整个文件时, 才应该使用 readline().
注意: 这三种方法是把每行末尾的'\n'也读进来了, 它并不会默认的把'\n'去掉, 需要我们手动去掉.
- In[2]: with open('test1.txt', 'r') as f1:
- list1 = f1.readlines()
- In[3]: list1
- Out[3]: ['111\n', '222\n', '333\n', '444\n', '555\n', '666\n']
去掉'\n'
- In[4]: with open('test1.txt', 'r') as f1:
- list1 = f1.readlines()
- for i in range(0, len(list1)):
- list1[i] = list1[i].rstrip('\n')
- In[5]: list1
- Out[5]: ['111', '222', '333', '444', '555', '666']
对于 read()和 readline()也是把'\n'读入了, 但是 print 的时候可以正常显示(因为 print 里的'\n'被认为是换行的意思)
- In[7]: with open('test1.txt', 'r') as f1:
- list1 = f1.read()
- In[8]: list1
- Out[8]: '111\n222\n333\n444\n555\n666\n'
- In[9]: print(list1)
- 111
- 222
- 333
- 444
- 555
- 666
- In[10]: with open('test1.txt', 'r') as f1:
- list1 = f1.readline()
- In[11]: list1
- Out[11]: '111\n'
- In[12]: print(list1)
- 111
一个 python 面试题的例子:
有两个文件, 每个都有很多行 ip 地址, 求出两个文件中相同的 ip 地址:
- # coding:utf-8
- import bisect
- with open('test1.txt', 'r') as f1:
- list1 = f1.readlines()
- for i in range(0, len(list1)):
- list1[i] = list1[i].strip('\n')
- with open('test2.txt', 'r') as f2:
- list2 = f2.readlines()
- for i in range(0, len(list2)):
- list2[i] = list2[i].strip('\n')
- list2.sort()
- length_2 = len(list2)
- same_data = []
- for i in list1:
- pos = bisect.bisect_left(list2, i)
- if pos <len(list2) and list2[pos] == i:
- same_data.append(i)
- same_data = list(set(same_data))
- print(same_data)
要点就是:(1)用 with (2)处理行末的'\n' (3)使用二分查找提高算法效率.(4)使用 set 快速去重.
写文件
写文件和读文件是一样的, 唯一区别是调用 open()函数时, 传入标识符'w'或者'wb'表示写文本文件或写二进制文件:
- >>> f = open('test.txt', 'w') # 若是'wb'就表示写二进制文件
- >>> f.write('Hello, world!')
- >>> f.close()
注意:'w'这个模式是酱紫: 如果没有这个文件, 就创建一个; 如果有, 那么就会先把原文件的内容清空再写入新的东西. 所以若不想清空原来的内容而是直接在后面追加新的内容, 就用'a'这个模式.
我们可以反复调用 write()来写入文件, 但是务必要调用 f.close()来关闭文件. 当我们写文件时, 操作系统往往不会立刻把数据写入磁盘, 而是放到内存缓存起来, 空闲的时候再慢慢写入. 只有调用 close()方法时, 操作系统才保证把没有写入的数据全部写入磁盘. 忘记调用 close()的后果是数据可能只写了一部分到磁盘, 剩下的丢失了. 所以, 还是用 with 语句来得保险:
- with open('test.txt', 'w') as f:
- f.write('Hello, world!')
python 文件对象提供了两个 "写" 方法: write() 和 writelines().
write()方法和 read(),readline()方法对应, 是将字符串写入到文件中.
writelines()方法和 readlines()方法对应, 也是针对列表的操作. 它接收一个字符串列表作为参数, 将他们写入到文件中, 换行符不会自动的加入, 因此, 需要显式的加入换行符.
- f1 = open('test1.txt', 'w')
- f1.writelines(["1", "2", "3"])
- # 此时 test1.txt 的内容为: 123
- f1 = open('test1.txt', 'w')
- f1.writelines(["1\n", "2\n", "3\n"])
- # 此时 test1.txt 的内容为:
- # 1
- # 2
- # 3
关于 open()的 mode 参数:
'r': 读
'w': 写
'a': 追加
- 'r+' == r+w(可读可写, 文件若不存在就报错(IOError))
- 'w+' == w+r(可读可写, 文件若不存在就创建)
- 'a+' ==a+r(可追加可写, 文件若不存在就创建)
对应的, 如果是二进制文件, 就都加一个 b 就好啦:
- 'rb' 'wb' 'ab' 'rb+' 'wb+' 'ab+'
- file_obj.seek(offset,whence=0)
file_obj.seek(offset,whence=0)方法用来在文件中移动文件指针. offset 表示偏移多少. 可选参数 whence 表示从哪里开始偏移, 默认是 0 为文件开头, 1 为当前位置, 2 为文件尾部. 举例:
- f = open("test1.txt", "a+")
- print(f.read())
- f.write('1')
- f.seek(0, 0)# 把文件指针从末尾移到开头, 没有这句话下面的 read()就读不到正确的东西
- print(f.read())
- f.close()
注意: 这个文件指针的改变只是作用于'r', 对'w'和'a'不会起作用, 如果是'w', 那么 write()永远都是从开头写 (会覆盖后面对应位置的内容), 是'a'的话 write() 就永远都是从最后开始追加.
字符编码
要读取非 UTF-8 编码的文本文件, 需要给 open()函数传入 encoding 参数, 例如, 读取 GBK 编码的文件:
- >>> f = open('test.txt', 'r', encoding='gbk')
- >>> f.read()
- '测试'
遇到有些编码不规范的文件, 你可能会遇到 UnicodeDecodeError, 因为在文本文件中可能夹杂了一些非法编码的字符. 遇到这种情况, open()函数还接收一个 errors 参数, 表示如果遇到编码错误后如何处理. 最简单的方式是直接忽略:
>>> f = open('test.txt', 'r', encoding='gbk', errors='ignore')
来源: http://www.bubuko.com/infodetail-2673434.html