一.文件操作方式
1.打开操作

open(file,mode='r',buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)

打开一个文件,返回一个文件对象(流对象)和文件描述符。打开文件失败,则返回异常
2.文件处理基本流程:
<1>打开test文件,得到文件句柄并赋值给一个变量
<2>通过句柄对文件进行操作
<3>关闭文件

f = open("test")  #file对象     #open函数会检索当前系统的编码,如果在win需要转成encoding='utf-8'
#windows<_io.TextIOWrapper name='test' mode='r' encoding='cp936'>
#linux<_io.TextIOWrapper name='test' mode='r' encoding='UTF-8'>
print(f.read())   #读取文件
f.close()         #关闭文件
####打开操作详解:
test文件内容在硬盘上,需要把文件加载到内存当中看。
第一步:open('test')在操作系统要了一个渔网,文件假如在硬盘上的一堆鱼,要想要鱼,就拿着渔网f到硬盘上去舀鱼,舀鱼相当于看内容
第二步:通过渔网f到硬盘上去捞鱼read(),整个过程通过操作系统提供的渔网去完成,这个渔网就是文件句柄f,f是open()函数提供的,open()函数是一个应用程序,函数都要完成一个特定的目的,这里完成特定的目的就是打开文件,open()它自己打不开,就得需要跟操作系统要,这个open()实际是在调操作系统,由操作系统最终给你返回一个f,有了这个f,就可以操作硬盘上的内容第三步:f.close()把渔网回收还给操作系统

关闭
1.close:flush并关闭文件对象。
2.文件已经关闭,再次关闭没有任何效果
读取
1.read(size=-1)
size表示读取的多少个字符或字节;负数或者None表示读取的EOF
2.行读取
①readline(size=-1):一行行读取文件的内容。size设置一次能读取行内几个字符或字节(节省内存)
举例1:
<1>xixi.txt文档:
111111111111111111111111111
222222222222222222222222222
<2>代码:

f=open('xixi.txt','r',encoding='utf-8')
print('第1行',f.readline(),end='')   #end=''去掉空行
print('第2行',f.readline())
f.close()
#输出:
第1行 1111111111111111111111111111
第2行 2222222222222222222222222222

举例2:用for方式(内部调用readline)读取文件(linux)
<1>xixi.txt文档:
111111111111111111111111111
222222222222222222222222222
<2>代码:

#!/bin/env python
from __future__ import print_function  #解决python2.7使用end = ''报错
#_*_coding:utf-8_*_
f = open('xixi.txt','r')
for i in f:
    print(i,end = '')
#输出:
111111111111111111111111111
222222222222222222222222222

②readlines(hint=-1):读取所有行的列表。指定hint则返回指定的行数
<1>xixi.txt文档:
111111111111111111111111111
222222222222222222222222222
<2>代码:

f=open('xixi.txt','r',encoding='utf-8')
data=f.readlines()
print(data)
f.close()
##输出:
['1111111111111111111111111111\n', '2222222222222222222222222222\n']


1.write(s):把字符串s写入到文件中并返回字符的个数
举例:写文件

f=open('xixi.txt','w',encoding='utf-8')
f.write('11111111\n')
f.write('222222222\n')
f.write('333\n4444\n555\n')
f.close()
##xixi.txt写入的文件结果:
11111111
222222222
333
4444
555

二.参数
1.file:打开或者要创建的文件名。如果不指定路径,默认是当前路径
2.模式mode:
文件操作中,最常用的操作就是读和写
文件访问的模式有两种:文件模式和二进制模式。不同模式下,操作函数不尽相同,表现的结果也不一样
(1)r:缺省的,表示只读打开
只读打开文件,如果使用write方法,会抛异常
如果文件不存在,抛出FileNotFoundError异常
(2)w:只写打开
表示只写方式打开,如果读取则抛出异常
如果文件不存在,则直接创建文件
如果文件存在,则清空文件内容
(3)x:只写创建并写入一个新文件
文件不存在,创建文件,并只写方式打开
文件存在,抛出FileExistsError异常
(4)a:只写入打开,如果文件存在,则追加
文件存在,只写打开,追加内容
文件不存在,则创建后,只写打开,追加内容
举例:7777这几个字追加到xixi.txt文档的最后一行
<1>原文件xixi.txt:
111111111111111111111111111
222222222222222222222222222
<2>代码:

f=open('xixi.txt','a',encoding='utf-8')
f.write('7777')
f.close()
#追加xixi.txt文档后:
111111111111111111111111111
222222222222222222222222222
7777

(5)b:二进制模式
字节流,将文件就按照字节理解,与字符编码无关。二进制模式操作时,字节操作使用bytes类型
(6)t:缺省的,文件模式
字符流,将文件的字节按照某种字符编码理解,按照字符操作.open的默认mode就是rt
(7)+:读写打开一个文件。给原来只读,只写方式打开提供缺失的读或者写能力
为r,w,a,x提供缺失的读写功能,但是,获取文件对象依旧按照r,w,a,x,自己的特征
+不能单独使用,可以认为它是为前面的模式字符做增强功能的
举例:把原文件里的wangxixi删除掉
<1>xixi.txt原文件:
王西西
wangxixi
<2>代码:

src_f=open('xixi.txt','r',encoding='utf-8')   #读的方式打开xixi.txt原文件
data=src_f.readlines()                        #把读取的结果存在data里
src_f.close()                                 #关闭原文件

dst_f=open('xixi.txt','w',encoding='utf-8')   #写的方式打开xixi.txt原文件
dst_f.write(data[0])                          #把读取的data里的内容的里的王西西写进去
dst_f.close()
##xixi.txt文件修改后:
王西西

3.其它参数
(1)encoding编码,仅文本模式使用
None表示使用缺省编码,以来操作系统
(2)errors:什么样的编码错误将被捕获
None和strict表示有编码错误将抛出ValueError异常,ignore表示忽略
(3)newline:文本模式中,换行的转换。可以为None,",'\r','\n','\r\n'
①读时,None表示'\r','\n','\r\n'都会被转换为'\n';"表示不会自动转换通用换行符;其它合法字符表示换行符就是指定字符,就会按照指定字符分行
②写时,None表示'\n'都会被替换为系统却省行分隔符os.linesep;'\n'或"表示'\n'不替换;其它合法字符表示'\n'会被替换为指定的字符
举例:
<1>原文:xixi.txt
西西
xixiaaa
<2>代码:

f=open('xixi.txt','r',encoding='utf-8',newline='')
print(f.readlines())
##打印:
['西西\r\n', 'xixiaaa']

(4)closefd:关闭文件描述符,True表示关闭它,False会在文件关闭后保持这个描述符。
fileobj.fileno()查看
5.常用修改文件操作
举例1:把xixi.txt文件里的所有字母b改成0
<1>文件xixi.txt
abcdefg
gfedcba
cba
<2>代码:

#!/bin/env python
#_*_coding:utf-8_*_
with open('xixi.txt','r') as fr,open('xixi.txt.bak','w') as fw:
    for i in fr:
        if 'b' in i:
            i = i.replace('b','0')
        fw.write(i)

<3>改变后的xixi.txt.bak
a0cdefg
gfedc0a
c0a
举例2:把xixi.txt文件里的所有字母b和字母e都改成0
<1>修改前文件xixi.txt
abcdefg
gfedcba
cba
<2>代码:

#!/bin/env python
#_*_coding:utf-8_*_
with open('xixi.txt','r') as fr,open('xixi.txt.bak','w') as fw:
    for i in fr:
        if 'b' in i:
            i = i.replace('b','0')
        if 'e' in i:
            i = i.replace('e','0')
        fw.write(i)

<3>修改后xixi.txt.bak
a0cd0fg
gf0dc0a
c0a
三.文件指针
1.文件指针,指向当前字节位置
mode=r,指针起始在0
mode=a,指针起始在EOF
2.文件指针方法:
①tell()显示指针当前位置
②seek(offset[,whence])移动文件指针位置。offest偏移多少字节,whence从哪里开始
(1)文本模式下
whence 0 缺省值,表示从头开始,offest只能正整数
whence 1 表示从当前位置,offest只接受0
whence 2 表示从EOF开始,offest只接受0
举例:
<1>test文件内容:
西abcxi
<2>文本模式代码

f = open('test','r+',encoding='utf-8' )
print(f.tell())     #光标起始位置:0
print(f.read())     #读取文件所有内容:西abcxi
print(f.tell())     #再次查看光标结束位置:8

f.seek(0)           #把光标设定在起始位置
print(f.read())     #读取文件所有内容:西abcxi

f.seek(3,0)         #把光标移动到位置3
print(f.read())     #读取内容:abcxi

f.seek(0,2)         #把光标移到结尾
print(f.tell())     #光标位置:8

f.close()

(2)二进制模式下
①whence 0 缺省值,表示从头开始,offest只能正整数
②whence 1 表示从当前位置,offest可正可负
③whence 2 表示从EOF开始,offest可正可负
举例1:rb模式
<1>test文件内容:
西abcxi
<2>二进制模式代码

f=open('test','rb')
print(f.tell())       #起始光标位置:0
print(f.read())       #读取所有内容:b'\xe8\xa5\xbfabcxi'
print(f.tell())       #当前光标位置:8

f.seek(0)             #把光标设定在起始位置
f.seek(2,1)           #从当前指针开始,向后2
print(f.read())       #读取当前内容:b'\xbfabcxi'

print(f.tell())       #当前光标位置:8
f.seek(-2,1)          #从当前指针开始,向前2
print(f.read())       #读取当前内容:b'xi'

f.seek(2,2)           #从结尾开始,向后2
print(f.tell())       #当前光标位置:10

f.seek(-2,2)          #从结尾开始,向前2
print(f.tell())       #当前光标位置:6
print(f.read())       #读取当前内容:b'xi'

f.close()

总结:二进制模式支持任意起点的偏移,从头,从尾,从中间位置开始。向后seek可以超界,但是向前seek的时候,不能超界,否则抛异常
举例2:wb模式

f=open('xixi.txt','wb')                     #b的方式不能指定编码
f.write(bytes('1111\n',encoding='utf-8'))
f.write('西西'.encode('utf-8'))

###xixi.txt写入结果:
1111
西西

举例3:ab模式

f=open('xixi.txt','ab')                    #b的方式不能指定编码
f.write('你好'.encode('utf-8'))

###写入结果:
1111
西西你好

四.判断
1.seekable()判断是否可seek
2.readable()判断是否可读
举例:判断xixi.txt这个文件是否可读

f=open('xixi.txt','r',encoding='utf-8')
print(f.readable())
f.close()
#输出:
True

3.writable()判断是否可写
4.closed判断是否已经关闭
五.上下文管理
一种特殊的语法,交给解释器去释放文件对象

with open('test') as f:
    print(f.read())       #文件只读,写入失败
    print(f.closed)       #查看是否关闭:False

上下文管理总结:
使用with ...as 关键字
上下文管理的语句块并不会开启新的作用域
with语句块执行完的时候,会自动关闭文件对象
举例:文件句柄open用as f赋值直接对文件进行操作

with open('xixi.txt','w') as f:
     f.write('1111\n')
#写入文件内容:
1111

六.StringIO和BytesIO
StringIO
(1)io模块中的类
from io import StringIO
(2)内存中,开辟的一个文本模式的buffer,可以想文件对象一样操作它
(3)当close方法被调用的时候,这个buffer会被释放
StringIO操作:
(1)getvalue()获取全部内容。跟文件指针没有关系

from io import StringIO
#内存中构建
sio = StringIO()             #像文件对象一样操作
print(sio.readable(),sio.writable(),sio.seekable())

sio.write('xi\npython')    #写入xi,\n,python
sio.seek(0)                  #指针到第一位

print(sio.readline())        #读一行
print(sio.getvalue())        #无视指针,输出全部内容

sio.close()
##输出结果:
True True True
xi

xi
python

(2)好处:一般来说,磁盘的操作比内存的造作要慢得多,内存足够的情况下,一般的优化思路是少落地,减少磁盘IO的过程,可以大大提高程序的运行效率
BytesIO
(1)from io import BytesIO
(2)内存中,开辟的一个二进制模式的buffer,可以像文件对象一样操作它
(3)当close方法被调用的时候,这个buffer会被释放
BytesIO操作:

from io import BytesIO
#内存中构建
bio = BytesIO()             #像文件对象一样操作
print(bio.readable(),bio.writable(),bio.seekable())

bio.write(b'xi\npython')    #写入b'xi,\n,python
bio.seek(0)                  #指针到第一位

print(bio.readline())        #读一行
print(bio.getvalue())        #无视指针,输出全部内容

bio.close()
##输出结果:
True True True
b'xi\n'
b'xi\npython'

七.file-like对象
1.类文件对象,可以像文件对象一样操作
2.socket对象,输入输出对象(stdin,stdout)都是类文件对象

from sys import stdout
f = stdout
print(type(f))#用的什么东西:<class '_io.TextIOWrapper'>
f.write('xi')    #控制台打印:xi