# Python文件操作 在 Python 中,文件操作是非常常见的任务。Python 提供了内置的函数来处理文件的读写操作。 ## 文件的类型 1. **文本文件**:包含可读的字符(如 `.txt`、`.csv`)。一般使用 UTF-8 编码,可以使用文本编辑器查看; 2. **二进制文件**:包含非文本数据(如图像、音频、视频文件,后缀如 `.jpg`、`.png`、`.mp3`)。以原始字节格式存储。需要使用专用软件查看; ## 文件操作的过程 1. 打开文件; 2. 读写文件; - 读文件:将文件内容读入内存; - 写文件:将内存内容写入文件; 3. 关闭文件; # 操作方法 ## 打开文件 使用 `open()` 函数打开文件 `open` 函数负责打开文件,并且返回文件对象 1. 第一个参数是文件名(文件名区分大小写),第二个参数是打开方式; 2. 如果文件存在返回文件操作对象; 3. 如果文件不存在抛出异常 ```python f = open("文件名", "访问方式") ``` ### 文件路径 #### **绝对路径:** 从根路径开始描述文件的位置,例如:`F:\技术文件\课件-笔记\课件修订\Python\01.Python基础语法` 具有唯一性,不会出错,不管写在哪里都可以准确的找到文件的位置 #### **相对路径:** 相对当前位置进行文件定位,容易出错,需要对路径比较熟悉 ### 以不同模式打开 | 访问方式 | 说明 | | -------- | ------------------------------------------------------------ | | r | 以**只读**方式打开文件。文件的指针将会放在文件的开头,这是**默认模式**。如果文件不存在,抛出异常 | | w | 以**只写**方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 | | a | 以**追加**方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 | | r+ | 以**读写**方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常 | | w+ | 以**读写**方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 | | a+ | 以**读写**方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 | 以bytes类型操作的读写,写读,写读模式 | r+b | 读写【可读,可写】 | | :--- | :----------------- | | w+b | 写读【可写,可读】 | | a+b | 写读【可写,可读】 | 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式) 注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码 ### 文件编码 f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。 ```python f=open('example.txt','r',encoding='utf-8') ``` ## 读取文件 - **`read(size)`**:读取指定大小的内容,如果没有指定,读取全部内容。 - **`readline()`**:读取一行。 - **`readlines()`**:读取所有行并返回一个列表。 示例: ```python file = open('example.txt', 'r') content = file.read() # 读取全部内容 line = file.readline() # 读取一行 lines = file.readlines() # 读取所有行 print(content) print('-----------') print(line) print('-----------') print(lines) # 思考? # 为什么后面两个print读取不到东西呢? ``` ### 文件指针 seek 有时候我们想要改变文件指针(光标)的位置,就需要用到seek方法来操作指针 **语法:** ```python file.seek(offset, whence) ``` - **`offset`**:要移动的字节数。 - `whence` (可选):指定偏移量的基准位置。可以取以下值: - `0`:从文件开头开始计算(默认值)。 - `1`:从当前位置开始计算。 - `2`:从文件末尾开始计算 **示例:** ```python file = open('example.txt', 'r') content = file.read() # 读取全部内容 file.seek(0) # 把光标移到到文件的开头 line = file.readline() # 读取一行 file.seek(0) # 再次把光标移动到文件的开头 lines = file.readlines() # 读取所有行 print(content) print('-----------') print(line) print('-----------') print(lines) ``` ### 按行读取文件内容 - read方法默认会把文件的所有内容一次性读取到内存 - readline方法可以一次读取一行内容 ```python # 方式一、通过循环按行读取文件所有内容 file1 = open("example.txt") i = 1 while True: text1 = file1.readline().strip() if text1: print("这是第%s行内容" % i) i += 1 print(text1) else: break file1.close() file2 = open("example.txt") # 通过for遍历按行读取文件所有内容 for i in file2.readlines(): print(i.strip()) file2.close() ``` ## 写入内容 可以对文件对象调用write方法实现写入内容 **语法:** ```python file.write() ``` **示例:日记记录** ```python # 日记程序 # 以追加模式打开日记文件 file = open('diary.txt', 'a',encoding='utf-8') # 获取用户输入的日记内容 content = input("请输入今天的日记:") # 将日记内容写入文件 file.write(content + "\n") print("日记已保存!") # 关闭文件 file.close() ``` ## 关闭文件 **语法:** ```python file.close() ``` 使用 `close()` 方法关闭文件,释放系统资源,防止文件被一直占用 ## with结构 使用 `with` 语句可以自动管理文件的打开和关闭,避免忘记关闭文件的情况。 ```python with open('example.txt', 'r') as file: # 获取file文件对象 content = file.read() ``` **案例:简单的备份程序** 将一个文本文件的内容复制到另一个文件,用于简单的备份。 ```python # 简单备份小程序 source = 'a.txt' destination = 'b.txt' with open(source, 'r',encoding='utf-8') as src: content = src.read() with open(destination, 'w',encoding='utf-8') as dest: dest.write(content) print(f"备份成功!'{source}' 的内容已复制到 '{destination}'") ``` ## 其他文件操作 除了上述讲到的常用操作之外,还有很多其他的操作。这里我们列出在这,就不一一带着大家去看了。用到的时候可以回头来查一下就行 ```python class CustomFile: def __init__(self, *args, **kwargs): """初始化文件对象.""" pass @staticmethod def __new__(*args, **kwargs): """创建并返回一个新的对象.""" pass def close(self, *args, **kwargs): """关闭文件.""" pass def fileno(self, *args, **kwargs): """返回文件描述符.""" pass def flush(self, *args, **kwargs): """刷新文件内部缓冲区.""" pass def isatty(self, *args, **kwargs): """判断文件是否是一个终端设备.""" pass def read(self, *args, **kwargs): """读取指定字节的数据.""" pass def readable(self, *args, **kwargs): """检查文件是否可读.""" pass def readline(self, *args, **kwargs): """仅读取一行数据.""" pass def seek(self, *args, **kwargs): """移动文件指针到指定位置.""" pass def seekable(self, *args, **kwargs): """检查指针是否可操作.""" pass def tell(self, *args, **kwargs): """获取当前指针位置.""" pass def truncate(self, *args, **kwargs): """截断文件,仅保留指定之前的数据.""" pass def writable(self, *args, **kwargs): """检查文件是否可写.""" pass def write(self, *args, **kwargs): """写入内容到文件.""" pass def __next__(self, *args, **kwargs): """实现迭代器的 next() 方法.""" pass def __repr__(self, *args, **kwargs): """返回文件对象的字符串表示.""" pass def __getstate__(self, *args, **kwargs): """自定义对象的序列化状态.""" pass ``` ### 解释 1. **`__init__`**: 初始化文件对象的方法。通常在这里设置文件的基本属性。 2. **`__new__`**: 静态方法,用于创建新的对象实例。 3. **`close`**: 关闭文件,释放系统资源。 4. **`fileno`**: 返回文件描述符,通常用于与底层操作系统交互。 5. **`flush`**: 刷新文件的内部缓冲区,将未写入的数据写入文件。 6. **`isatty`**: 判断文件是否是一个终端设备(tty),用于检查文件是否连接到一个用户界面。 7. **`read`**: 读取指定字节的数据,可以用来读取文件内容。 8. **`readable`**: 检查文件对象是否可读。 9. **`readline`**: 读取文件中的一行数据,常用于逐行读取文件内容。 10. **`seek`**: 移动文件指针到指定位置,允许在文件中随机访问。 11. **`seekable`**: 检查文件指针是否可操作,确定文件是否支持随机访问。 12. **`tell`**: 返回当前文件指针的位置。 13. **`truncate`**: 截断文件,只保留指定位置之前的数据。 14. **`writable`**: 检查文件对象是否可写。 15. **`write`**: 向文件写入内容。 16. **`__next__`**: 实现迭代器的 `next()` 方法,用于支持迭代访问文件的内容。 17. **`__repr__`**: 返回文件对象的字符串表示,通常用于调试。 18. **`__getstate__`**: 自定义对象的序列化状态,用于存储和恢复对象的状态。 # 案例练习 ## 案例一 文件修改 文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式: 方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器) ```python import os with open('a.txt') as read_f,open('a.txt.new','w') as write_f: data = read_f.read() data = data.replace('Hello','nihao') write_f.write(data) os.remove('a.txt') os.rename('a.txt.new','a.txt') ``` 方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件 ```python import os with open('a.txt') as read_f,open('a.txt.new','w') as write_f: for line in read_f: line = line.replace('nihao','Hello') write_f.write(line) os.remove('a.txt') os.rename('a.txt.new','a.txt') ``` ## 案例二 商品信息管理与总价计算 #### 背景 在日常的商业管理中,商品的管理和销售记录是非常重要的。我们需要一种方式来处理商品信息,包括商品名称、价格和数量。通过这些信息,我们可以计算出总价,帮助商家了解销售情况。 #### 目标 本案例旨在通过 Python 读取存储在文本文件中的商品信息,并将其转换为易于操作的数据结构。具体目标包括: 1. 从文件 `a.txt` 中读取每一行的商品信息。 2. 将读取的信息构建为包含字典的列表,每个字典表示一个商品,包含名称、价格和数量。 3. 计算所有商品的总价,并输出结果。 #### 文件内容示例 `a.txt` 文件的内容如下: ``` apple 10 3 tesla 100000 1 mac 3000 2 lenovo 30000 3 chicken 10 3 ``` 每行代表一个商品,格式为:`商品名称 价格 数量`。 #### 代码示例 ```python # 初始化商品列表 products = [] # 读取文件并构建商品列表 with open('a.txt', 'r', encoding='utf-8') as file: for line in file: # 去除行首尾空白并分割 parts = line.strip().split() if len(parts) == 3: # 确保有三个部分 product = { 'name': parts[0], 'price': int(parts[1]), # 转换为整数 'amount': int(parts[2]) # 转换为整数 } products.append(product) # 输出商品列表 print("商品列表", products) total_price = 0 # 计算总价 for i in products: total_price += i["price"] * i["amount"] # 输出总价 print("总价:", total_price) # Output: [{'name': 'apple', 'price': 10, 'amount': 3}, {'name': 'tesla', 'price': 100000, 'amount': 1}, {'name': 'mac', 'price': 3000, 'amount': 2}, {'name': 'lenovo', 'price': 30000, 'amount': 3}, {'name': 'chicken', 'price': 10, 'amount': 3}] 总价: 196060 ``` ## 案例三 基于文件的账户验证 将用户信息存放在文件**user.txt**中,并且格式如下 ``` 张三|123456 ``` **代码示例:** ```python db = {} with open("user.txt","r", encoding="utf-8") as f: data = f.readlines() print(data) for i in data: ret = i.strip().split("|") # ret = ["张三", "123"] print(ret) db[ret[0]] = ret[1] # db["张三"] = "123" print(db) while True: username = input("请输入用户名:") if username in db: password = input("请输入密码:") if password ==db[username]: print("登录成功") else: print("密码错误登录失败") else: print("用户名不存在") ```