0 两个重要的函数
isinstance(obj,cls):检查obj是否是类 cls 的对象
class Foo(object):
pass
obj = Foo()
print(isinstance(obj, Foo))
issubclass(sub, super):检查sub是否是类super的子类
class Foo(object):
pass
class Bar(Foo):
pass
print(issubclass(Bar, Foo))
1 反射
反射就是以字符串的形式来操作变量
反射一共提供了4个方法: hasattr();getattr();setattr();delattr()
eval函数就是实现list、dict、tuple与str之间的转化
str函数把list,dict,tuple转为为字符串
这两个函数与反射无关
Eval存在安全问题,而反射不存在安全问题
# 反射对象的属性
class A:
def func(self):
print('in func')
a = A()
a.name = 'lux'
a.age= 63
ret = getattr(a, 'name')
print(ret)
b = input('>>>>')
print(getattr(a, b))
print(a.__dict__['name'])
注意:上述的三种方法都能实现功能, input输入的内容就是字符串类型,因为是反射对象中的属性,所以也可以通过字典来实现
# 反射对象的方法
class A:
def func(self):
print('in func')
a = A()
a.name = 'lux'
a.age = 63
ret = getattr(a, 'func')
ret()
# 反射类的属性(这里的属性包括一般属性和静态属性)
class A:
price = 20
def func(self):
print('in func')
print(getattr(A, 'price'))
# 反射类的方法 (这里的方法包括普通方法,类方法和静态方法)
class A:
price = 20
@classmethod
def func(cls):
print('in func')
ret = getattr(A, 'func')
ret()
class A:
price = 20
@staticmethod
def func():
print('in func')
ret = getattr(A, 'func')
ret()
# mymodule 是我自定义的一个模块
import mymodule
print(getattr(mymodule, 'my_packet'))
# 反射模块的方法
import mymodule
ret = getattr(mymodule, 'get_money')
ret()
# 反射自己模块的属性和方法
def qqxing():
print('wahaha')
year = 2020
import sys
print(getattr(sys.modules[__name__], 'year'))
ret = getattr(sys.modules[__name__], 'qqxing')
ret()
hasattr()通常与getattr()配合使用:
import mymodule
if hasattr(mymodule, 'my_packet'):
print(getattr(mymodule, 'my_packet'))
# setattr(): 修改一个变量
class A:
pass
a = A()
setattr(a, 'name', 'alex')
setattr(A, 'name', 'lux')
print(a.name)
print(A.name)
# delattr():删除一个属性
class A:
name = 'zoe'
a = A()
a.name = 'jax'
delattr(a, 'name')
print(a.name)
delattr(A, 'name')
print(A.name)
注意:当对象的方法和属性找不到时,就会在类里面找
2 一些魔法方法(双下划线方法):
# __str__
class Teacher:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def __str__(self):
return 'Tecaher is %s' % self.name
def func(self):
return 'wahaha'
dasi = Teacher('大司马', 3000)
print(dasi)
总结:当直接打印一个对象的时候,会自动执行__str__方法
当执行%s的时候,会自动执行__str__方法
当执行str()的时候,也会自动执行__str__方法
# __repr__
class Teacher:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def __str__(self):
return 'Tecaher is %s' % self.name
def __repr__(self):
return '<<<Tecaher is %s' % self.name
def func(self):
return 'wahaha'
dasi = Teacher('大司马', 3000)
print(repr(dasi))
print('%s' % dasi)
print('%r' % dasi)
总结:当执行%r的时候,会自动执行__str__方法
当执行repr()的时候,也会自动执行__str__方法
小结:
__repr__是__str__的备胎,当需要__str__但是找不到__str__时候,就会找本类中的__repr__方法,(但是__str__不是__repr__的备胎),再找不到就在父类中找,直到object类,__repe__只会找__repe__方法,找不到就去父类找
class Teacher:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def __repr__(self):
return '<<<Tecaher is %s' % self.name
def func(self):
return 'wahaha'
dasi = Teacher('大司马', 3000)
print(repr(dasi))
print('%s' % dasi)
print('%r' % dasi)
# __len__
class Teacher:
def __init__(self, name):
self.name = name
self.student = []
def __len__(self):
return 10
def __str__(self):
return 'nmsl'
py_s9 = Teacher('九七')
py_s9.student.append('jinx')
print(len(py_s9))
注意:当执行len的时候就会执行__len__方法,单纯的直接打印才会执行__str__方法,print(len(py_s9))相当于先执行len(py_s9),将__len__返回的结果打印出来,这个结果不是对象,所以和__str__没有关系
# __del__:析构方法,当对象在内存中被释放时,自动触发执行
class A:
def __del__(self):
print('执行了del方法')
a = A()
del a
print(a)
总结:当执行了del的时候,先执行该__del__方法,再删除对象
__del__的作用;在删除一个对象之前,做一些收尾工作
# __call__
class A:
def __call__(self):
print('执行了__call__方法')
a = A()
a()
注意:当一个对象加()后,执行__call__方法,在看源码的时候,我们可能会看到A()()这种
# item系列:与字典有关的方法
# Item系列一共有三种方法:__getitem__ __setitem__ __delitem__
class Foo:
def __init__(self, name):
self.name = name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item)
f1 = Foo('sb')
f1['age'] = 18
f1['age1'] = 19
print(f1.__dict__)
del f1.age1 # 和__delattr__相关联
del f1['age'] # 和__delitem__想关联
f1['name'] = 'alex'
print(f1.__dict__)
# __new__
# 当对象在实例化的时候,先自动执行__new__,再执行__init__
__new__一般用于设计模式,下面介绍一种常见的单例模式
class A:
__instance = False
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, *args, **kwargs):
if cls.__instance:
return cls.__instance
cls.__instance = object.__new__(A)
return cls.__instance
egon = A('二哥', 99)
alex = A('哪吒', 520)
egon.cloth = '羽绒服'
print(egon.name)
print(alex.name)
print(alex.__dict__)
注意:对于单例模式而言,新对象的属性会覆盖旧对象的属性,如果没有这个属性,则会增加上
class Teacher:
def __init__(self):
print('__init__执行了')
def __new__(cls, *args, **kwargs):
print('__new__执行了')
return object.__new__(Teacher)
def __call__(self):
print('__call__执行了')
dasi = Teacher()
dasi()
# __eq__
当出现==时,会自动执行__eq__
class A:
def __init__(self, name):
self.name = name
def __eq__(self, other):
if self.name == other.name:
return True
else:
return False
a1 = A('lux')
a2 = A('lux')
print(a1 == a2)
注意:’==‘ 会自动调用__eq__函数,如果没有__eq__函数,就会比较内存地址,比如上述的代码,没有没有__eq__ 结果就是False(刚又验证了一次)
# __hash__
class A:
def __init__(self, name, sex):
self.name = name
self.sex = sex
def __hash__(self):
return hash(self.name + self.sex)
a1 = A('lux', '男')
a2 = A('lux', '男')
print(hash(a1))
print(hash(a2))
注意:没有__hash__的话,如果是可哈希的类型,会根据内存地址来哈希,如果有__hash__的话,就会根据hash函数来进行哈希
关于__del__; delattr; delitem__的区别:
0)del :用来删除一个对象
1)delattr:用来删除一个对象的属性
2)delitem: 与字典有关,用来删除一个字典的键
关于 init__和__new:
class A:
pass
class B(A):
def __new__(cls):
print("__new__方法被执行")
return super().__new__(cls)
def __init__(self):
print("__init__方法被执行")
b = B()
小结:我们比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作,结合到代码,也就是__new__的返回值正是__init__中self。
经过测试,如果返回了一个不相关的变量,__init__也不会被执行。
3 内置函数的一些遗留问题
from random import choice
from collections import namedtuple
import json
from random import shuffle
Card = namedtuple('Card', ['rank', 'suit'])
class FranchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = ['红心', '方板', '梅花', '黑桃']
def __init__(self):
self._cards = [Card(rank, suit) for rank in FranchDeck.ranks
for suit in FranchDeck.suits]
def __len__(self):
return len(self._cards)
def __getitem__(self, item):
return self._cards[item]
def __str__(self):
return json.dumps(self._cards, ensure_ascii=False)
deck = FranchDeck()
print(deck[0])
print(choice(deck))
print(len(deck))
print(deck)
小结:一定要学会使用namedtuple
4 hashlib模块
Hashlib模块是一个提供摘要算法的模块,比如md5,sha1等
摘要算法:
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
import hashlib
md = hashlib.md5()
md.update(b'alex')
print(md.hexdigest())
import hashlib
md = hashlib.md5()
md.update(b'how to use md5 in python hashlib?')
print(md.hexdigest())
小结: 对于同一个内容,使用同一个摘要算法,得到的内容是相同的
对于同一个内容,使用不同的摘要算法,得到的内容是不同的
算法的复杂度越高,造成的时间成本也越高
一个有关登录的代码
import hashlib
usr = input('请输入用户名:')
pwd = input('请输入密码:')
with open('userinfo.txt') as f:
for line in f:
(usrs, pwds, role) = line.split('|')
md5 = hashlib.md5()
md5.update(bytes(pwd, encoding='utf-8'))
ret = md5.hexdigest()
if usr == usrs and ret == pwds:
print('登陆成功')
else:
print('登陆失败')
userinfo.txt文件的内容
为了使密码不容易被破解,可以使用‘加盐’来增加复杂度
import hashlib
md = hashlib.md5()
md = hashlib.md5(bytes('1', encoding='utf-8'))
md.update(b'blessing')
print(md.hexdigest())
小结:太简单的盐还是会被识别出来,而比较复杂的盐被识别出来的几率就小了很多
登陆的时候可以加盐,文件的一致性校验不需要加盐
对于一个文件而言,通常不一次性把所有的内容都转化为md5值,而是分多次,这种方式与前者得到的结果完全相同
5 一个改输出效果的小技巧
Python的print可以附带一些小花样,比如说前景色和背景色。
print('\033[0;36m爆竹声中一岁除,')
print('春风送暖入屠苏。')
print('千门万户曈曈日,')
print('总把新桃换旧符。\033[0m')
6 configparser模块
# 利用py程序自动生成一个ini文件(配置文件)
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9',
'ForwardX11':'yes'
}
config['bitbucket.org'] = {'User':'hg'}
config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
with open('example.ini', 'w') as configfile:
config.write(configfile)
run后会得到一个ini文件(配置文件)
查找ini文件的内容
import configparser
config = configparser.ConfigParser()
#---------------------------查找文件内容,基于字典的形式
print(config.sections()) # []
config.read('example.ini')
print(config.sections()) # ['bitbucket.org', 'topsecret.server.com']
print('bytebong.com' in config) # False
print('bitbucket.org' in config) # True
print(config['bitbucket.org']["user"]) # hg
print(config['DEFAULT']['Compression']) #yes
print(config['topsecret.server.com']['ForwardX11']) #no
print(config['bitbucket.org']) #<Section: bitbucket.org>
for key in config['bitbucket.org']: # 注意,有default会默认default的键
print(key)
print(config.options('bitbucket.org')) # 同for循环,找到'bitbucket.org'下所有键
print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有键值对
print(config.get('bitbucket.org','compression')) # yes get方法Section下的key对应的value
更改ini文件的内容
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
config.add_section('yuanyuan')
config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com', "forwardx11")
config.set('topsecret.server.com', 'k1', '11111')
config.set('yuanyuan', 'k2', '22222')
config.write(open('example.ini', "w"))
7 logging 模块
Logging模块用来记录一些重要的操作和错误(日志)
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
import logging
logging.basicConfig(level=logging.ERROR,
format='%(asctime)s %(filename)s',
filename='test.log',
filemode='a')
logging.error('你好')
一张提供参考输出格式的表
日志是很有必要的,不会写日志就是睿智
basicConfig的两大缺点:
中文的乱码问题
不能同时往文件和屏幕上打印
为了解决问题,我们必须配置log对象
import logging
logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log', encoding='utf-8')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
使用上述对log配置的方法,可以解决这两大缺点
小结:
5种级别的日志记录模式
2种配置模式:basicConfig 和 log配置
8 网络知识
0) 架构
C/s架构和b/s架构
1)一些网络知识
每台电脑都有唯一的一个mac地址(物理地址)通常由12位十六进制组成,其中每两位隔开
其中前三组是厂商号,后三组是流水号
由于mac地址太过抽象且不好记忆,所以我们引入了ip地址的方式,每台电脑对应着唯一一个ip地址
Ip地址由4个八位的二进制组成(ipv4),或者最新推出的(ipv6)
Arp协议:可以通过ip地址找到对应的mac地址。
网关:处于不同局域网的电脑想要通信,必须通过网关
怎么判断两台电脑处于同一个局域网呢?
方法:ip地址与子网掩码按位与
如果两台电脑得到的结果的前三组一样,就说明两台电脑处于同一个局域网
Ip协议主要有两个功能:
为每一台电脑分配一个ip地址, 确定哪些地址在同一个网络
保留字段 192.168.—.---
本地的回环地址 127.0.0.1
Ip:找到唯一的一台电脑
端口:找到唯一的一个程序 端口的范围是0——65535 一般情况下使用8000后的 端口,之前的端口都是系统端口
Ip➕端口:找到唯一的一台电脑上的唯一的一个程序
9 Tcp协议和udp协议
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议
Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
tcp的三次握手和四次挥手
详情查看:添加链接描述
Tcp和udp的对比:
Tcp安全可靠 需要建立连接才能通信,耗时长
Udp不需要建立连接就能通信,所以它不是安全可靠的,效率高
互联网协议按照功能不同分为osi七层和osi五层,以下是对五层的一些理解
换句话说,通信就是包快递和拆快递的过程
一个基于tcp的socket模块:可以实现自身的自收自发
# server.py
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8090))
sk.listen()
conn, add = sk.accept()
# print(add)
while True:
ret = conn.recv(1024).decode('utf-8')
print(ret)
if ret == 'bye':
break
info = input()
conn.send(bytes(info, encoding='utf-8'))
conn.close()
sk.close()
# client.py
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
while True:
info = input()
if info == 'bye':
sk.send(bytes(info, encoding='utf-8'))
break
sk.send(bytes(info, encoding='utf-8'))
ret = sk.recv(1024).decode('utf-8')
print(ret)
sk.close()
一个基于udp的socket模块:可以实现自身的自收自发
# server.py
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 8080))
while True:
msg, addr = sk.recvfrom(1024)
ret = msg.decode('utf-8')
print(ret)
if ret == 'bye':
break
info = input('>>>')
sk.sendto(bytes(info, encoding='utf-8'), addr)
sk.close()
# client.py
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ('127.0.0.1', 8080)
while True:
info = input('<<<')
sk.sendto(bytes(info, encoding='utf-8'), ip_port)
if info == 'bye':
break
msg, addr = sk.recvfrom(1024)
print(msg.decode('utf-8'))
sk.close()
10 黏包
Tcp会出现黏包现象,但不会出现丢包现象,如果没接收完的包会在下一次接收的时候接收到
而udp不会出现黏包现象,但是会出现丢包现象,没有接收完的包会直接丢弃掉
这里插播一个有关编码和解码的知识点:
解码和编码
举个例子,这里我们不妨将人类可以很容易理解的字符作为“明文”,将人类的明文加密成不易懂但是更易于存储和传输的消息字节作为“密文”。那么编码和解码的关系如下: 明文就是人类可以直接一眼就看得懂的字符,密文就是明文被加密后一般人无法立马看懂的字节。

UTF-8,是对Unicode编码的压缩和优化,它不再要求最少使用2个字节,而是将所有的字符和符号进行分类:ASCII码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存。
当计算机在工作时,内存中的数据一直是以Unicode的编码方式表示的,当数据要保存到磁盘或者网络传输时,才会使用utf-8编码进行操作。
Tcp协议的拆包机制:
当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。
MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。
解决黏包问题的方法:
0)在传输大文件的时候,提前发生文件的长度
1) struct模块:是一个可以将任意大小的数字转换成一个固定长度编码的模块
# server端
import socket
import struct
sk = socket.socket()
sk.bind(('127.0.0.1', 8090))
sk.listen()
conn, addr = sk.accept()
while True:
cmd = input(">>>")
if cmd == 'q':
conn.send(b'q')
break
conn.send(cmd.encode('gbk'))
num = conn.recv(4)
num = struct.unpack('i', num)[0]
# print(num)
res = conn.recv(int(num)).decode('gbk')
print(res)
conn.close()
sk.close()
# client端
import socket
import subprocess
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
while True:
cmd = sk.recv(1024).decode('gbk')
if cmd == 'q':
break
res = subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
std_out = res.stdout.read()
std_err = res.stderr.read()
len_sum = len(std_out) + len(std_err)
num_by = struct.pack('i', len_sum)
sk.send(num_by)
sk.send(std_out)
sk.send(std_err)
sk.close()
struct模块
常用的两个方法: pack和unpack
模式 “i”
pack之后的长度:4个字节
unpack之后拿到的数据是一个元组,元组的第一个内容才是pack的值
subprocess模块
subprocess这个模块可以用来产生子进程,并连接到子进程的标准输入/输出/错误中去,还可以得到子进程的返回值。
11ftp:文件传输协议(和自定义报头)
# server端
import socket
import struct
import json
sk = socket.socket()
sk.bind(('127.0.0.1', 8090))
sk.listen()
buffer = 4096
conn, addr = sk.accept()
# 接收
head_len = conn.recv(4)
head_len = struct.unpack('i', head_len)[0]
json_head = conn.recv(head_len).decode('utf-8')
# 字符串转字典
head = json.loads(json_head)
filesize = head['filesize']
with open(head['filename'], 'wb') as f:
while filesize:
if filesize >= buffer:
content = conn.recv(buffer)
f.write(content)
filesize -= buffer
else:
content = conn.recv(filesize)
f.write(content)
break
conn.close()
sk.close()
# client端
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
buffer = 4096
head = {'filepath': '/Users/gaoye/Desktop',
'filename': 'test1.mov',
'filesize': None}
# 拼接,将路径和名字拼接在一起
file_path = os.path.join(head['filepath'], head['filename'])
# 得到文件字节大小
filesize = os.path.getsize(file_path)
head['filesize'] = filesize
# 字典转字符串
json_head = json.dumps(head)
# 字符串转字节
bytes_head = json_head.encode('utf-8')
# 计算head的长度
head_len = len(bytes_head)
pack_len = struct.pack('i', head_len)
# 先发送报头的长度
sk.send(pack_len)
# 再发送bytes类型的报头
sk.send(bytes_head)
with open(file_path, 'rb') as f:
while filesize:
if filesize >= buffer:
content = f.read(buffer)
sk.send(content)
filesize -= buffer
else:
content = f.read(filesize)
sk.send(content)
break
sk.close()
12 hamc模块
hamc模块
hashlib : 不可逆加密
hmac : 不可逆键值对方式加密
base64: 可逆加密
一个验证客户端的合法性的例子:
# server端
import socket
import hmac
import os
import hashlib
secret_key = b'egg'
sk = socket.socket()
sk.bind(('127.0.0.1', 8090))
sk.listen()
def check_conn(conn):
# os.urandom得到的本身就是字节,所以不用encode
msg = os.urandom(32)
conn.send(msg)
h = hmac.new(secret_key, msg, digestmod=hashlib.sha1)
digest = h.digest()
client_digest = conn.recv(1024)
return hmac.compare_digest(digest, client_digest)
conn, addr = sk.accept()
res = check_conn(conn)
if res:
print('合法的客户端')
else:
print('不合法的客户端')
conn.close()
sk.close()
# client端
import socket
import hmac
import hashlib
secret_key = b'egg'
sk = socket.socket()
sk.connect(('127.0.0.1', 8090))
msg = sk.recv(1024)
h = hmac.new(secret_key, msg, digestmod=hashlib.sha1)
digest = h.digest()
sk.send(digest)
sk.close()
注意:
Hmac.new()一定要有digestmod参数 之前没有设置这个变量,所以一直报错
再遇继承:
__author__ = 'Eva_J'
class Base(object):
def __init__(self, name):
self.name = name
self.Testfunc()
def Testfunc(self):
print('do Base Testfunc')
class Son(Base):
def Testfunc(self):
print('do Son Testfunc')
class Base2(object):
def Testfunc(self):
print('do Base2 Testfunc')
class GrandSon(Base2, Son):
pass
sonobj = Son('sonobj')
总结:即使调用了父类的__init__,但是在执行别的方法时,还是首先考虑自身,没有再考虑父类
小技巧:
pycharm把.py文件识别成.text文件,代码提示没有了,改掉文件名才能出现提示。
可能是因为创造文件的时候不小心把这个文件名与text关联了。
解决方案:
File->Settings->Editor->File Types 里面找到text,然后在text里找到这个文件名,删除就可以了