1、打开与关闭

1.1、open() close()
我们使用 open() 函数打开文件。这个函数将返回一个文件对象,我们对文件的读写都将使用这个对象。
open() 函数需要三个参数,第一个参数是文件路径或文件名,第二个是文件的打开模式,第三个是编码格式。模式通常是下面这样的:
"r",以只读模式打开,按字符读,也就是rt模式
"w",以写入模式打开,如果文件存在将会清空所有内容,然后写入
"a",以追加模式打开,写入到文件中的任何数据将自动添加到末尾
"b",以二进制的方式打开
r+:读文件并在文件最后进行追加内容
w+:文件有可读可写权限
rb:以二进制格式进行读,可用于在网络中传输。例如从gbk的windows系统中传递utf-8的linux系统就不需要编码了,直接解码就可以,效率上和r没啥区别,按字节读
wb:以二进制格式进行写,并且需要指定编码格式
如果用二进制方法读写,就不需要指定编码格式了
默认的模式为只读模式,也就是说如果你不提供任何模式,open()函数将会以只读模式打开文件。

f = open('1.txt', 'wb')
f这个变量称为文件句柄,一般命名为f,f1,fh,file_handle等。

坑:
当文件路径是'C:\Users\i\Desktop\1.txt'时会报错
原因:文件路径中含有\n、\U、\t时会认为是一个转义符
解决方法:1、推荐路径前加r,写成r'C:\Users\i\Desktop\1.txt'
             2、再加一个\,写成'C:\\Users\i\Desktop\1.txt'
                  3、\换成/


f.tell() 显示光标目前所在的位置,按字节计算,不是字符
f.seek(20)按字节查找,光标从第20个字节开始,其中1个汉字占3个字节
f.truncate(100)截取从文档最开始到第100个字符串,且只能从最头开始截取不能从中间截取,且只能以a或r+模式打开文件
f.flush()强制刷新硬盘,例如在f.write('1')时如果没有f.close()则不会立刻写入硬盘,这时可以使用flush()方法强制写入硬盘,一般用于日志实时显示时用。

f.seek(参数1, 参数2): 参数1表示移动几个字节(注意不是字符),参数2表示参照物(0表示文件开头,1表示当前光标位置,2表示文件结尾)


当程序执行结束后,我们需要关闭文件,如果不关闭会持续占用一些内存和操作系统资源,不关闭的文件也有可能造成数据丢失。

我们使用方法 close() 完成这个操作,重复关闭不会有任何影响:
file.close()

1.2 with语句
在实际情况中,我们应该尝试使用 with 语句处理文件对象,它会在文件用完后会自动关闭,就算发生异常也没关系。它是 try-finally 块的简写:

1 with open('/etc/protocols') as file:
2     count = 0
3     for line in file:
4         count += 1
5     print(count)

结果为:158
这个程序中我们将打印文件的行数,可以看到代码块中并没有使用 close,但当代码执行到 with 代码块之外时,文件会被自动关闭。

2、读取文件内容(read()、read(n)、readline()、readlines()、for循环)

此处我们创建一个文件test.txt,这个文件的内容包括两行:
Hello
I love Python

2.1、read()
使用read()可以一次性读取整个文件的内容到字符串:

1 f1 = open('1.txt',encoding='utf-8', mode='r') #这里1.txt和python程序在同一个路径下,所以只写了相对路径
2 content = f1.read()
3 print(content)
4 f1.close()

结果为:
Hello
I love Python

当然也可以使用 with,避免忘记了 close:

1 filename = '/home/test.txt'
2 with open(filename) as file:
3     file.read()

 

2.2、read(size)
read(size)有一个可选的参数size,用于指定字符长度,不是字节长度。如果没有指定size或者指定为负数,就会读取并返回整个文件。当文件大小为当前机器内存两倍时,就会产生问题。反之,会尽可能按比较大的size读取和返回数据。

1 f1 = open('1.txt',encoding='utf-8', mode='r')
2 content = f1.read(10)
3 print(content)
4 f1.close()

结果为:
Hello
I l

项目开发中,我们需要谨慎使用read()读取整个文件,因为有可能你的系统内存并不足够存储整个文件的内容。当read()执行后,再次执行将不会有任何内容的输出。

2.3、readline()
在处理文本文件的时候,我们通常会采用逐行处理,readline()就是用来每次读取文件的一行

1 filename = '1.txt'
2 f1 = open(filename,encoding='utf-8', mode='r')
3 content = f1.readline()
4 print(content)
5 content = f1.readline()
6 print(content)
7 f1.close()

结果为:
Hello

I love Python

2.4、readlines()
readlines()可以读取所有行,但不同于read(),这个函数的返回的是一个列表,列表中每个元素都是对应文本文件中一行内容的字符串:

1 filename = '1.txt'
2 f1 = open(filename,encoding='utf-8')
3 content = f1.readlines()
4 print(content)
5 f1.close()

['\ufeffHello\n', 'I love Python']

-------------------------------------------------------
延伸
1、发现读txt文件时最前面多了一个ufeff,当编码格式改成utf-8-sig时就正常
f1 = open(filename,encoding='utf-8-sig')

utf-8与utf-8-sig两种编码格式的区别:
As UTF-8 is an 8-bit encoding no BOM is required and anyU+FEFF character in the decoded Unicode string (even if it’s the firstcharacter) is treated as a ZERO WIDTH NO-BREAK SPACE.
UTF-8以字节为编码单元,它的字节顺序在所有系统中都是一样的,没有字节序的问题,也因此它实际上并不需要BOM(“ByteOrder Mark”)。但是UTF-8 with BOM即utf-8-sig需要提供BOM。

2、打开文件时with open(filename, mode='r', encodint='utf-8) as f1:
如果打开文件的方式写在filename后可以省略mode=,直接写'r'或'w',如果写在编码格式后面,就不能简写了,必须写成mode='r'

--------------------------------------------------------
2.5、for循环遍历文件句柄
你可以for循环遍历文件句柄来读取文件中的每一行

1 filename = '1.txt'
2 f1 = open(filename,encoding='utf-8')
3 content = f1.readlines()
4 for i in content:
5     print(i, end='')
6   或print(i.strip())
7 f1.close()

结果为:
Hello
I love Python

read() readline() readlines()的区别
read()是以字符串形式显示所有内容
readline()是以字符串形式每次显示一行内容,运行多次可逐行显示
readlines()是以列表的形式显示所有内容


对于大文件推荐用for循环读文件,例子:
写一个程序,这个程序接受用户输入的字符串作为将要读取的文件的文件名,并且在屏幕上打印文件行数和文件内容:

1 filename = input("Enter the file name: ")
2 with open(filename) as file:
3     count = 0
4     for line in file:
5         count += 1
6         print(line)
7     print('Lines:', count)

运行程序:
Enter the file name: /home/test.txt
Hello World
I love Python
Lines: 2

3、写入文件

3.1、mode='w'写入模式
最常用的写入文件的方法是 write(),通过write()方法打开一个文件然后我们随便写入一些文本。

1 filename = '1.txt'
2 with open(filename, encoding='utf-8',mode='w') as file:
3     file.write('testline1')
4     file.write('testline2')

这个程序中,我们将文件以'w'模式打开,然后写入两段内容。
['testline1testline2']

这时候发现文件中原来的内容已经被完全覆盖了,并且写入的内容占了一行(因为没有写入换行符的原因)。
可见w这种模式是将文件先清空,再写入
如果文件不存在,会先创建空文件,再写入

3.2、mode='a'追加模式
如果我们想向文件中增加内容如何操作呢?可以使用 'a' 追加模式打开文件:

1 filename = '/home/shiyanlou/test.txt'
2 with open(filename, mode='a') as file:
3     file.write('testline3')
4     file.write('testline4')

再次读取,可以看到新增加的字符串附加到了原来的内容后面:
['testline1testline2testline3testline4']

1 with open(filename,mode='a') as file:
2      file.write(str+'\n')

在写入参数str后加“\n”则会在每次完成写入后,自动换行到下一行,下次写入时便会在下一行写入

4、例子

例子1:更改文件中的内容,将haha改为Python

 1 import os
 2 file = 'G:/python/1.txt'
 3 file_new = 'G:/python/1_new.txt'
 4 
 5 with open(file,mode='r',encoding='utf-8') as f:
 6     with open(file_new,mode='w',encoding='utf-8') as f_new:
 7         for line in f:
 8             if 'haha' in line:
 9                 line = line.replace('haha','Python')
10             f_new.write(line)
11         
12 os.remove('G:/python/1.txt')
13 os.rename('G:/python/1_new.txt','G:/python/1.txt')

同时打开两个文件可以写成

1 with open(file,mode='r',encoding='utf-8') as f,open(file_new,mode='w',encoding='utf-8') as f_new:

或写成

1 with open(file,mode='r',encoding='utf-8') as f,\
2     open(file_new,mode='w',encoding='utf-8') as f_new:

 

如果想要拷贝一个图片或音视频文件,就需要用二进制方法打开,用rb和wb

1 with open('1.jpg', 'rb') as file_1:
2     with open('2.jpg', 'wb') as file_2:
3         for i in file_1:
4             file_2.write(i)

 

例子2 :利用命令行参数进行操作

 1 import sys,os
 2 file = sys.argv[1]
 3 old_str = sys.argv[2]
 4 new_str = sys.argv[3]
 5 new_file = 'g:/python/1_new.txt'
 6 with open(file,mode='r',encoding='utf-8') as f,open(new_file,mode='w',encoding='utf-8') as f_new:
 7     for line in f:
 8         if old_str in line:
 9             line = line.replace(old_str,new_str)
10         f_new.write(line)11 
12 os.remove(file)
13 os.rename(new_file,file)

在命令行里输入:
python test.py g:/python/1.txt Python haha
将Python替换成haha

获取sys.args的第2个参数和第3个参数也可以写成下面这样:

_, old_str, new_str = sys.argv

 例子3:实现tail -f的效果

通过代码实现tail -f access.log不断读取文件更新内容的效果

1 import time
2 with open('access.log', 'rb') as f:
3     f.seek(0,2)    #将光标移动到文件末尾
4     while True:
5         line = f.readline()
6         if line:
7             print(line.decode(), end='')
8         else:
9             time.sleep(0.05)

 必须用二进制b的模式打开,因为seek的第二个参数如果

  • 为0时(文件开头为参照点),可以用r或rb模式
  • 为1(当前光标位置为参照点)或2(文件末尾为参照点)时,用r模式打开会报错,必须用rb模式打开
  • r模式默认就是rt模式,也就是用文本模式打开

5、os.path 文件与文件夹操作

在这里简单介绍下 os.path 这个非常常用的标准库,这个库主要的用途是获取和处理文件及文件夹属性。
下面代码举例介绍几个常用的方法,更多的内容在使用到的时候查阅文档。

os.path.abspath(path) 返回文件的绝对路径
os.path.basename(path) 返回文件名
os.path.dirname(path) 返回文件路径
os.path.isfile(path) 判断路径是否为文件
os.path.isdir(path) 判断路径是否为目录
os.path.exists(path) 判断路径是否存在
os.path.join(path1[, path2[, ...]]) 把目录和文件名合成一个路径

实验代码内容,需要在 Python 交互环境中操作:
需要先导入os模块
>>> import os
>>> filename = '/home/1/test.txt'
>>> os.path.abspath(filename)
'/home/1/test.txt'x
>>>
>>> os.path.basename(filename)
'test.txt'
>>> os.path.dirname(filename)
'/home/1'
>>>
>>> os.path.isfile(filename)
True
>>>
>>> os.path.isdir(filename)
False
>>> os.path.exists(filename)
True
>>> os.path.join('/home/1', 'test.txt')
'/home/1/test.txt'
>>>

 

posted on 2018-10-29 09:47  longfei2021  阅读(214)  评论(0编辑  收藏  举报