Python File



Python File

搞懂Python对文件的基本操作

当前工作目录

每个运行在计算机上的程序,都有一个“当前工作目录。所有没有从根文件夹开始的文件名或路径,都假定在当前工作目录下。

注意,虽然文件夹是目录的更新的名称,但当前工作目录(或当前目录)是标准术语,没有当前工作文件夹这种说法。
在 Python 中,利用 os.getcwd() 函数可以取得当前工作路径的字符串,还可以利用 os.chdir() 改变它。例如,在交互式环境中输入以下代码:
 >>> import os
>>> os.getcwd()
'C:\\Users\\jack\\workspace'
>>> os.chdir('C:\\Windows\\System32')
>>> os.getcwd()
'C:\\Windows\\System32'

可以看到,原本当前工作路径为 'C:\\Users\\jack\\workspace',通过 os.chdir() 函数,将其改成了 'C:\\Windows\\System32'。

需要注意的是,如果使用 os.chdir() 修改的工作目录不存在,Python 解释器会报错,例如:
 >>> os.chdir('C:\\error')
Traceback (most recent call last):
File " ", line 1, in
os.chdir('C:\\error')
FileNotFoundError: [WinError 2] 系统找不到指定的文件。: 'C:\\error'

了解了当前工作目录的具体含义之后,接下来介绍绝对路径和相对路径各自的含义和用法。

绝对路径与相对路径

明确一个文件所在的路径,有 2 种表示方式,分别是:

绝对路径:总是从根文件夹开始,Window 系统中以盘符(C:、D:)作为根文件夹,而 OS X 或者 Linux 系统中以 / 作为根文件夹。

相对路径:指的是文件相对于当前工作目录所在的位置。例如,当前工作目录为 "C:\Windows\System32",若文件 text.txt 就位于这个 System32 文件夹下,则 demo.txt 的相对路径表示为 ".\demo.txt"(其中 .\ 就表示当前所在目录)。
在使用相对路径表示某文件所在的位置时,除了经常使用 .\ 表示当前所在目录之外,还会用到 ..\ 表示当前所在目录的父目录。
Python os.path 模块提供了一些函数,可以实现绝对路径和相对路径之间的转换,以及检查给定的路径是否为绝对路径,比如说:

调用 os.path.abspath(path) 将返回 path 参数的绝对路径的字符串,这是将相对路径转换为绝对路径的简便方法。

调用 os.path.isabs(path),如果参数是一个绝对路径,就返回 True,如果参数是一个相对路径,就返回 False。

调用 os.path.relpath(path, start) 将返回从 start 路径到 path 的相对路径的字符串。如果没有提供 start,就使用当前工作目录作为开始路径。

调用 os.path.dirname(path) 将返回一个字符串,它包含 path 参数中最后一个斜杠之前的所有内容;调用 os.path.basename(path) 将返回一个字符串,它包含 path 参数中最后一个斜杠之后的所有内容。

open() 方法

Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。
注意:使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。
open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。
open(file, mode='r')

完整的语法格式为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

参数说明:

file: 必需,文件路径(相对或者绝对路径)。
mode: 可选,文件打开模式。
buffering: 设置缓冲。
encoding: 一般使用utf8。
errors: 报错级别。
newline: 区分换行符。
closefd: 传入的file参数类型。
opener:

mode 参数有:

默认为文本模式,如果要以二进制模式打开,加上 b 。

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(Python 3 不支持)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

file 对象

file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数:
方法 描述
file.close() 关闭文件。关闭后文件不能再进行读写操作。
file.flush() 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
file.fileno() 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
file.isatty() 如果文件连接到一个终端设备返回 True,否则返回 False。
file.next() Python 3 中的 File 对象不支持 next() 方法。返回文件下一行。
file.read([size]) 从文件读取指定的字节数,如果未给定或为负则读取所有。
file.readline([size]) 读取整行,包括 "\n" 字符。
file.readlines([sizeint]) 读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。
file.seek(offset[, whence]) 移动文件读取指针到指定位置。
file.tell() 返回文件当前位置。
file.truncate([size]) 从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小。
file.write(str) 将字符串写入文件,返回的是写入的字符长度。
file.writelines(sequence) 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。

读写文本文件

文本读取

1.txt文本内容如下:
 Hello Lidihuo:
I am a student,I like python。

读取文本文件时,需要在使用
open函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为
'r'(如果不指定,默认值也是'r'),然后通过encoding参数指定编码(如果不指定,默认值是None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与encoding参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。下面的例子演示了如何读取一个纯文本文件。
 def openfile():
    f = open('1.txt', 'r', encoding='utf-8')
    print(f.read())
    f.close()

if __name__ == '__main__':
    openfile()

执行结果:
Hello Lidihuo:
I am a student,I like python。

请注意上面的代码,如果
open函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码有一定的健壮性和容错性,我们可以使用Python的异常机制对可能在运行时发生状况的代码进行适当的处理,如下所示。
 def openfile():
    try:
        f = open('1.txt', 'r', encoding='utf-8')
        print(f.read())
    except FileNotFoundError:
        print('无法打开指定的文件!')
    except LookupError:
        print('指定了未知的编码!')
    except UnicodeDecodeError:
        print('读取文件时解码错误!')
    finally:
        if f:
            f.close()

if __name__ == '__main__':
    openfile()

执行结果:
Hello Lidihuo:
I am a student,I like python。

在Python中,我们可以将那些在运行时可能会出现状况的代码放在try代码块中,在try代码块的后面可以跟上一个或多个except来捕获可能出现的异常状况。例如在上面读取文件的过程中,文件找不到会引发
FileNotFoundError,指定了未知的编码会引发LookupError,而如果读取文件时无法按指定方式解码会引发
UnicodeDecodeError,我们在try后面跟上了三个except分别处理这三种不同的异常状况。最后我们使用finally代码块来关闭打开的文件,释放掉程序中获取的外部资源,由于finally块的代码不论程序正常还是异常都会执行到(甚至是调用了sys模块的exit函数退出Python环境,finally块都会被执行,因为exit函数实质上是引发了SystemExit异常),因此我们通常把finally块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。如果不愿意在finally代码块中关闭文件对象释放资源,也可以使用上下文语法,通过with关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源,代码如下所示。
 def openfile():
    try:
        with open('1.txt', 'r', encoding='utf-8') as f:
            print(f.read())
    except FileNotFoundError:
        print('无法打开指定的文件!')
    except LookupError:
        print('指定了未知的编码!')
    except UnicodeDecodeError:
        print('读取文件时解码错误!')

if __name__ == '__main__':
    openfile()

执行结果:
Hello Lidihuo:
I am a student,I like python。

除了使用文件对象的read方法读取文件之外,还可以使用for-in循环逐行读取或者用readlines方法将文件按行读取到一个列表容器中,代码如下所示。
 import time
def openfile():
    with open('1.txt', 'r', encoding='utf-8') as f:
        print(f.read())
    with open('1.txt', mode='r') as f:
        for line in f:
            print(line, end='')
            time.sleep(0.5)
    print()
    with open('1.txt') as f:
        line = f.readlines()
    print(line)
if __name__ == '__main__':
    openfile()

执行结果:
['Hello Lidihuo:\n', 'I am a student,I like python。\n']

文本写入

要将文本信息写入文件文件也非常简单,在使用open函数时指定好文件名并将文件模式设置为'w'即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为'a'。如果要写入的文件不存在会自动创建文件而不是引发异常。下面的例子演示文件写入。
 def writefile():
    filename = ('1.txt')
    file = open(filename, 'w', encoding='utf-8')
    try:
        for number in range(1, 5):
            file.write(str(number) + '\n')
    except IOError as ex:
        print(ex)
        print('写文件时发生错误!')
    finally:
        file.close()
    print('操作完成!')
if __name__ == '__main__':
    writefile()

执行结果:
操作完成!

读写二进制文件

知道了如何读写文本文件要读写二进制文件也就很简单了,下面的代码实现了复制图片文件的功能。
 def openfile():
    try:
        with open('1.jpg', 'rb') as f1:
            data = f1.read()
            print(type(data))
        with open('2.jpg', 'wb') as f2:
            fs2.write(data)
    except FileNotFoundError as ex:
        print('指定的文件无法打开')
    except IOError as e:
        print('读写文件时出现错误')
    print('程序执行结束')

if __name__ == '__main__':
    openfile()

执行结果:
<class 'bytes'>
程序执行结束

写入CSV文件

python自带了csv模块提供用户对csv文件进行读写操作,要对csv文件进行写操作,首先要创建一个writer对象,参考help(csv.writer),情况如下
调用writer对象的前提是:需要传入一个文件对象,然后才能在这个文件对象的基础上调用csv的写入方法writerow(写入一行)writerrow(写入多行)。写入数据的代码如下:
 import csv
headers = ['class','name','sex','height','year']
rows = [
    [1,'xiaoming','male',168,23],
    [1,'xiaohong','female',162,22],
    [2,'xiaozhang','female',163,21],
    [2,'xiaoli','male',158,21]
]

with open('test.csv','w') as f:
    f_csv = csv.writer(f)
    f_csv.writerow(headers)
    f_csv.writerows(rows)

执行结果:
<class 'bytes'>
程序执行结束

这段代码我首先定义了写入csv文件的表头、每一列的内容,然后打开一个csv文件,将文件对象作为参数传给csv.writer(),最后将表头和每一行的内容写入到csv文件中。
注意:打开csv文件出现空行的情况,那么需要添加一个参数 newline=”(我使用windows出现了这种情况,使用linux mint没有出现)
with open('test.csv','w',newline='')as f:

读取CSV文件

 import csv
with open('test.csv') as f:
    f_csv = csv.reader(f)
    for row in f_csv:
    print(row)

执行结果:
['class', 'name', 'sex', 'height', 'year']
['1', 'xiaoming', 'male', '168', '23']
['1', 'xiaohong', 'female', '162', '22']
['2', 'xiaozhang', 'female', '163', '21']
['2', 'xiaoli', 'male', '158', '21']