# 文件处理的三个步骤:打开文件 读或者写 关闭文件
# 打开文件涉及了两方面:open功能让操作系统打开了文件,
# 另一方面open功能返回给应用程序一个文件句柄或者是文件对象
# 文件对象占用的是应用程序资源,打开的文件占用的是操作系统的资源
# 文件打开模式分为2大类:读写操作和读写内容模式
# 可读可写模式:+表示
# 遍历文件:for循环
# 1.控制文件指针移动
# ps:只有0模式可以在t下使用,其中1和2模式只能在b模式下使用
# 但是无论是t模式还是b模式下,移动的都是字节个数
# print(f.tell()) # 告诉你当前指针的位置,
# 他永远参照的计数方式是开头
with open('a.txt', mode='rt', encoding='utf-8') as f:
print(f.tell()) # 0
f.seek(9, 0)
f.seek(3, 0)
print(f.tell()) # 3
with open('a.txt', mode='rb', encoding='utf-8') as f:
print(f.tell()) # 0
f.seek(9, 1)
f.seek(3, 1)
print(f.tell()) # 12
with open('a.txt', mode='rb', encoding='utf-8') as f:
print(f.tell()) # 0
f.seek(0, 2)
print(f.tell()) # 18
# tail-f程序 access.log:日志,记录下来用以后看
# 它可以动态的看有没有人往access.log里面添加东西
# 小练习题:模拟记日志的程序
with open('access.log', mode='at', encoding='utf-8') as f:
f.write('2021-06-09 09:16:00 张三 200.103.110.22 ok\n')
# 这样一运行就会在access.log里面出现以上写的内容,运行一次出现一次
# 我们发现这个时候的时间是静止不变的达不到实时监控的目的
# 这个时候可以用模块的知识
# import time
# time.strftime('%Y-%m-%d %H:%M:%S') # 里面的%x是固定格式
# 斜杠可以不加或者换成其他的符号,看个人习惯。
import time
with open('access.log', mode='at', encoding='utf-8') as f:
f.write('%s 张三 200.103.110.22 ok' % time.strftime('%Y-%m-%d %H:%M:%S'))
# tail-f 实时监控程序追加进来内容的变化:(tail-of)运行的原理
# 有一个用户访问就写一条在access.log里面,不定时的用户访问写内容
# 所以access.log也是不定时的在运行。在写东西进access.log里面
# 需要有一个程序只要有新内容就打印出来到tail-f
# 说白了就是把access.log的东西读出来,读到tail里面,
# 而且是永远只读最后一行所以需要上来就把指针移动到末尾。
# (如果不把指针移动到末尾会造成什么后果?会使得tail记录的数据
# 具有重复性,相当于又把前面的全读下来了。)
# 然后tail-f读取access.log的内容。
# 所以tail-f程序此时需要做的是:先open()access.log这个文件
# 此时因为是用r读取的所以指针在文件的开头,而现在我们需要记录的是
# 用户在访问的时候,机器写下来到access.log传输给tail的实时数据
# 所以光标移动到末尾,读取实时行也相当于最后一行内容。
with open('access.log', mode='rb') as f:
f.seek(0, 2) # 指针的移动很关键
# line = f.readline() # 假设access.log还没有人访问,此时的
# tail-f很明显读取不到,也就是说他的返回值line没有,但是我要一直读
# 而且读到了就输出,读不到还是继续去读,循环的读来达到实时检测的目的
# 这个时候就需要用到循环读取。
while True:
line = f.readline()
if len(line) == 0:
continue
else:
print(line.encode('utf-8'), end='') # 每次读取的返回值
# 因为b模式下读取的是byetes类型,所以需要在进行相应的转换,也就是解码。
# 2.文件修改的两种方式
# 假如test.txt里面内容为(哈哈哈hello黑暗时代)
with open('test.txt', mode='r+t', encoding='utf-8') as f:
f.seek(9, 0)
f.write('hello') # 我们发现乱码了
# hello五个字节,而egon只有4个字节
# 首先我们应该要了解文件只能被覆盖不能被插入
# 5个字节覆盖4个字节多的一个字节就会覆盖下面的
# ‘黑’字,而黑是三个字节所以会出现乱码。
# 我们经常在电脑上操作的复制黏贴并不是我们所觉得的。
# 比如说把你好吗,修改成你好或者在你好的中间插入一些汉字
# ,却没有乱码。这是因为所以的文件修改的行为
# 其实都是模拟出来的,你是你看着像插入,其实他是文件的覆盖
# 更深层次的是新的覆盖旧的。但是内存可以修改
# 把硬盘的数据读到内存,再把内存改完的东西覆盖到硬盘
# 这是事实上所有的文本编辑器的大概原理。
# 文件修改的俩种方式都是把硬盘数据读到内存里面。
# 在内存改完了之后再覆盖到硬盘
# 具体又分为2种方式
# 第一种:
with open('test.txt', mode='rt', encoding='utf-8') as f:
date = f.read() # 赋值给一个变量date,字符串类型
date.replace('egon', 'EGON') # 字符串的替换
with open('test.txt', mode='wt', encoding='utf-8') as f:
f.write(date.replace('egon', 'EGON'))
# 首先分析:如果f.read()也就是原文件过大的话,会造成电脑很卡
# 其次就是千万不要用以下方法进行文件修改
with open('test.txt', mode='rt', encoding='utf-8') as f, \
open('test.txt', mode='wt', encoding='utf-8') as f:
# 这样会造成直接清空,永远也覆盖不了。
# 第二种:
import os
with open('test.txt', mode='rt', encoding='utf-8') as f1, \
open('b.txt.swp', mode='wt', encoding='utf-8') as f2:
for line in f1:
f2.write(line.replace('EGON', 'egon'))
# 这个时候我们需要做的是把原文件删掉,然后新文件改名成原文件的名字,
# 然后需要导入一个模块import os
os.remove('test.txt')
os.rename('b.txt.swp', 'test.txt')
# 总结:以上俩种情况,第二种不费内存,但是虽然不费硬盘,却需要硬盘
# 有一个最小值。假设原文件有10个G,如果第一种的话只需要10个G就行,
# 但是第二种却需要至少20个G才能进行文件的修改。
# 如果自己python写文件的话应该用第二种。
# 一般的文本编辑器都是用第一种,一次性把内容读到
# 内存,修改都是在内存里面修改。
# 3.函数
# 1.什么是函数?
# 函数就是盛放功能(一系列代码)的容器
# 定义函数就是造出来一个工具
# 事先准备工具的过程》函数的定义
# 遇到应用场景拿来就用》函数的调用
# 2.为何要用函数?
# 不用函数写出的代码问题是:
# 2.1程序的组织结构不清晰,可读性差,可维护性差
# 2.2程序的可扩展性差
# 3.如何用函数?
# 原则:先定义后调用
#
# 定义函数的语法
# def 函数名(参数1, 参数2, 参数3,.....):
# '''文档注释''' # 推荐写
# 代码1
# 代码2
# 代码3
# return 值
# 调用函数的语法:
# 函数名(值1,值2,值3)
# res = 函数名 # 拿到返回值
# print('*'*50)
# print('hello'.center(50,''))
# print('='*50)
# 如果想继续得到上面的print输出的值
# 我们可以利用函数的性质来完成
# def func():
# print('*' * 50)
# print('hello'.center(50, ' '))
# print('=' * 50)
# func()
# print(id(func()))
# print(func) # 得到的是函数的内存地址
# f = func # f为函数的内存地址
# f() # 函数的内存地址可以加括号调用
# x() # 变量的却不可以加括号
# print(x) # 得到的是变量值,理论上也是得到内存地址
# 这是因为变量名都做了处理
# x = 10
# 定义变量时,申请内存空间把10丢进去,然后把10的内存地址给X
# 定义函数时,申请内存空间把函数体代码放进去,然后将内存空间地址
# 给函数名
# func() = 函数体代码等
# 2.函数定义阶段发生的事情:只检测语法不执行代码
# 申请内存空间,把函数体代码放进去,然后把内存地址绑定给函数名
# 例1
# def func():
# print(1)
# print( # 语法错误
# print(2)
# 上面这种会直接报错,语法错误
# 例2
# def func():
# print(1)
# absfasf # 不会报错,因为没有语法错误
# 他没有先定义就引用了逻辑错误,应该先定义后引用。
# print(2)
# 上面这种不会报错,判断语法是否错误。
# 例3
# def foo():
# print('from foo')
# bar() # 也不会报错
# 例4
# def foo():
# print('from foo')
# bar()
# def bar():
# print('from foo')
#
# func()
# 函数调用阶段发生的事情:执行代码
# 例4
# def foo():
# print('from foo')
# bar()
# def bar():
# print('from foo')
# func() # 不会报错
# 函数的参数:
# def func(x, y):
# print(x + y)
# func(10, 20) # 30
# 如:
# x = 10
# y = 20
# if x > y:
# print(x)
# else:
# print(y)
# 假如在python写程序的时候经常用到下列代码
# 可以直接写成函数的形式,这样更加方便。
# def func(x, y):
# if x > y:
# print(x)
# else:
# print(y)
# func(20, 10) # 20
# inp_user = input('your name').strip()
# inp_pwd = input('your password').strip()
# if inp_user == 'egon' and inp_pwd == '123':
# print('ok')
# else:
# print('error')
# 这个可以把他弄成函数的形式:
def login(inp_user, inp_pwd):
inp_user = input('your name').strip()
inp_pwd = input('your password').strip()
if inp_user == 'egon' and inp_pwd == '123':
print('ok')
else:
print('error')
# 函数的返回值:
l = [111, 222, 333, 444, 5555]
# 如果列表操作三个元素打印Ok否则打印错误
def max():
size = len(l)
if size > 3:
print('ok')
else:
print('cuowu')