09-11-周四_16-52-32
This commit is contained in:
473
project04/01.Python文件操作.md
Normal file
473
project04/01.Python文件操作.md
Normal file
@@ -0,0 +1,473 @@
|
||||
# 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格式)
|
||||
|
||||
<font color=red>注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码</font>
|
||||
|
||||
### 文件编码
|
||||
|
||||
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("用户名不存在")
|
||||
```
|
||||
|
||||
|
||||
|
78
project04/[任务书]基于文件的用户管理.md
Normal file
78
project04/[任务书]基于文件的用户管理.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# 基于文件的用户管理
|
||||
|
||||
## 需求
|
||||
|
||||
### 数据库文件设计
|
||||
|
||||
- 创建db文件,并且保存用户名、密码、剩余登录次数、解封的时间,示例如下
|
||||
|
||||
```
|
||||
user01|123456|3|1733039528
|
||||
user02|123123|3|1733039528
|
||||
user03|121212|2|1733039528
|
||||
```
|
||||
|
||||
### 登录功能
|
||||
|
||||
- 用户输入正确的用户名和密码,就可以登录
|
||||
- 用户输入错误的用户名,提示用户名不存在
|
||||
- 用户名正确,但是密码错误,就提示密码错误,输入错误3次,就封号30秒
|
||||
- 用户名正确,只要是封号期间,不管密码是否正确,都提示已封号,还有xx秒解封
|
||||
- 用户名正确,如果已经解封,就正常登录
|
||||
|
||||
## 参考代码
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
# 数据库文件路径
|
||||
db_file = 'db'
|
||||
|
||||
# 读取数据库文件,返回用户信息字典
|
||||
users = {}
|
||||
with open(db_file, 'a+') as file:
|
||||
file.seek(0)
|
||||
for line in file:
|
||||
username, password, attempts, ban_time = line.strip().split('|')
|
||||
users[username] = {
|
||||
'password': password,
|
||||
'attempts': int(attempts),
|
||||
'ban_time': int(ban_time)
|
||||
}
|
||||
|
||||
# 主程序
|
||||
while True:
|
||||
username = input("请输入用户名:")
|
||||
if username not in users:
|
||||
print("用户名不存在。")
|
||||
continue
|
||||
|
||||
if users[username]['attempts'] <= 0 and users[username]['ban_time'] > int(time.time()):
|
||||
remaining_time = users[username]['ban_time'] - int(time.time())
|
||||
print(f"已封号,还有{remaining_time}秒解封。")
|
||||
continue
|
||||
|
||||
password = input("请输入密码:")
|
||||
if password == users[username]['password']:
|
||||
users[username]['attempts'] = 3 # 重置尝试次数
|
||||
print("登录成功。")
|
||||
else:
|
||||
users[username]['attempts'] -= 1
|
||||
if users[username]['attempts'] == 0:
|
||||
users[username]['ban_time'] = int(time.time()) + 30 # 封号30秒
|
||||
print("密码错误,账号已被封禁30秒。")
|
||||
else:
|
||||
print("密码错误,剩余尝试次数:", users[username]['attempts'])
|
||||
|
||||
# 将更新后的用户信息写回数据库文件
|
||||
with open(db_file, 'w') as file:
|
||||
for user, info in users.items():
|
||||
file.write(f"{user}|{info['password']}|{info['attempts']}|{info['ban_time']}\n")
|
||||
```
|
||||
|
||||
|
||||
|
||||
><span style="color: red; background: yellow; padding: 2px 5px; font-size: 22px;">作业4.1提交的内容</span>
|
||||
>
|
||||
>- 理解程序的运行逻辑
|
||||
>- 程序运行成功的截图,单独发送给组长
|
Reference in New Issue
Block a user