在我们用语言的过程中,比如要往文件内进行读写,那么势必要进行文件操作,那么咋操作呢?用眼睛直接看么?今天就定个小目标,把文件读写那些事扯一扯

文件操作

把大象放进冰箱分几步?

第一步:打开冰箱

第二步:把大象放进冰箱

第三步:把冰箱门关上

对文件的操作不也是一样么:

1、打开文件获取文件的句柄,句柄就理解为这个文件

2、通过文件句柄操作文件

3、关闭文件

辣么,我们就逐一来看一哈怎么进行这三步,文件的基本读写就完事了

打开文件

f = open('文件名','打开模式',指定字符集编码)

模式一般有几下几种方式:(这里的文件读写,指的是对于文件的操作)

r     只读模式:文件不存在的时候会报错;只能读不能写。如果进行写也会报错:not writeable

w   只写模式:文件不存在的话,帮你创建;打开文件会清空原来的文件内容,且不能读。可以理解为把原来的删除了,重新建了个文件

f = open('users2.txt','w',encoding='utf-8')
f.write('后天是周二')
f.close()

f = open('users2.txt','r',encoding='utf-8')
res = f.read()
print('第一次写入打开后的结果:%s\n'%(res))
f.close()

f = open('users2.txt','w',encoding='utf-8')
f.close()

f = open('users2.txt','r',encoding='utf-8')
res = f.read()
print('第二次写入打开后的结果:%s\n'%(res))
f.close()

结果:

第一次写入打开后的结果:后天是周二

第二次写入打开后的结果:

a    追加模式:文件不存在的话,帮你创建;不会清空原来文件的内容,但是不能读

f = open('users2.txt','a',encoding='utf-8')
f.write('后天是周二')
f.close()

f = open('users2.txt','r',encoding='utf-8')
res = f.read()
print('第一次写入打开后的结果:%s\n'%(res))
f.close()

f = open('users2.txt','a',encoding='utf-8')
f.write('再后天是周三')
f.close()

f = open('users2.txt','r',encoding='utf-8')
res = f.read()
print('第二次写入打开后的结果:%s\n'%(res))
f.close()

结果:

第一次写入打开后的结果:后天是周二

第二次写入打开后的结果:后天是周二再后天是周三

看到这里,你可能会问,这三种模式或多或少都有优缺点,就没有一种模式既能读又能写,能抗能打的么?

当然是 yes,升级版往下看:

 r+  读写模式:文件不存在会报错;可读,可写,可追加。要注意,默认写是从最开头写

# 第一次打开文件读
f = open('users2.txt','r+',encoding='utf-8')
res = f.read()
print('直接读的内容:%s'%(res))
f.close()

# 再次打开文件写
f = open('users2.txt','r+',encoding='utf-8')
f.write('abc')
res = f.read()
print('写完 abc 后的内容:%s'%(res))
f.close()

文件内的结果:

abc天是周二再后天是周三

打印结果:

直接读的内容:今天是周二再后天是周三
写完 abc 后的内容:天是周二再后天是周三

这里是因为我们再次打开写,文件指针是从最开始写的,那么就是从最开头写

我们可以发现:文件打开进行写,文件指针会指向最前面,然后往后面写,那么如果我先读完不关闭直接写呢?

f = open('users2.txt','r+',encoding='utf-8')
res = f.read()
print('直接读的内容:%s'%(res))

f.write('abc')
res2 = f.read()
print('写完 abc 后的内容:%s'%(res2))

结果:

文件内的结果:

今天是周二再后天是周三abc

打印的结果:

直接读的内容:今天是周二再后天是周三
写完 abc 后的内容:

从上边显而易见,只打开一次直接写的话,默认指针还是从最前面开始,read 一下,指针到最后,然后再写就是在最后面追加的内容了

w+  写读模式:文件不存在的话,帮你创建;打开文件会清空原来的文件内容,能读,但是由于清空了内容,读出来也是为空。

a+  追加读写模式:文件不存在的话,帮你创建;文件存在则往最后面追加内容,能写能读

∴ 要既能读也能写,就要用 r+ 或者 a+ 的方式,r+ 要追加写的话,要把文件指针移到最后;a+ 要读的话,要把文件指针移到最前

小结1:

  • 只要沾上 r 的,文件不存在会报错
  • 只要沾上 w 的,文件内容都会被清空

文件指针

个人理解:r  打开文件指针在最开头,w 打开文件指针在最开头,a 打开文件指针在最后

要理解这文件覆不覆盖,其实理解好文件指针就好了,那么啥是文件指针呢?简单理解为输入时的小光标,那么假设有个空文件,那么在一开始指针是指向文件内容的开端的,伴随着读写的进行指针一步一步往后挪。

那么,对于单次打开某文件,其实文件指针都指向了最开头,我们看一个例子:

假设有一个txt文件(filetest.txt),其中的内容如下:

今年是佩奇年,平安健康!
Python能做好多事!
今年要多写代码,写得多了也就熟练了!!

现在,我们写一段读的程序,

# coding=utf-8
import os
# os.getcwd()获取当前路径,即项目工程的目录
f = open('filetest.txt','r')
print("第一次读到的内容:\n", f.read())
print("第二次读到的内容:\n", f.read())

读取的结果如下:

第一次读到的内容:
今年是佩奇年,平安健康!
Python能做好多事!
今年要多写代码,写得多了也就熟练了!!
第二次读到的内容:

我们发现,第二次没有读出来任何内容,这是为什么呢?
从程序本身来看,前后两次调用 f.read() 函数,本意是将文件内容读两遍,可是第二次未读到任何内容。

针对这样的问题,其实是文件有一个文件指针(也叫 文件游标)的概念。实际上,当我们打开(open)这个文件的时候,此时,文件指针就定位在了文件的开头,当第一次调用 f.read() 函数时,相当于从文件指针的当前位置(即:文件开头)将这个文件全部读取出来;当第二次调用 f.read() 的时候,实际上此时文件指针已经定位在了文件的末尾,再次读取的时候,指向的内容就为空了。

下面再看一个例子:

# coding=utf-8
import os
# os.getcwd()获取当前路径,即项目工程的目录
f = open('filetest.txt','r')
print("第一次读到的内容:\n", f.read(2))  # 读取 2 个字节的内容
print("第二次读到的内容:\n", f.read(4))  # 读取 4 个字节的内容

读取的结果如下:

第一次读到的内容:
今年
第二次读到的内容:
是佩奇年

我们看到第二次读取到的内容并不是 【 今年是佩】,而是【是佩奇年】 ,那也就是说,当我们第一次f.read(2)的时候,当前文件指针已经定位到了第2个字节的位置,当第二次执行f.read(4)的时候,实际上是从当前文件指针位置开始读取4个字节的内容。

下面接着看另一个例子:

# coding=utf-8
import os
# os.getcwd()获取当前路径,即项目工程的目录
f = open('filetest.txt','r')
print("第一次读到的内容:", f.readline())
print("第二次读到的内容:", f.readline())

经过之前的解释,相信大家也能知道这段程序读取的结果,应该是读取文件的前两行内容,实际结果也是如此:

第一次读到的内容:今年是佩奇年,平安健康!
第二次读到的内容:Python能做好多事!

现在我们改变一下需求,要求两次读取的内容都是 文件的第一行 内容,该怎么办?
此时,我们应该要做的是改变文件指针的位置。

如何改变文件指针呢?这里需要用到 seek() 函数,其语法:seek(offset, wherece)

offset:偏移量,即表示文件指针所在的当前位置要偏移的字节数
wherece: 0 - 从文件开头;1 - 文件的当前位置; 2 - 文件的末尾

也就是说:快速移动到文件末尾f.seek(0,2),快速移动到文件开头f.seek(0)
有了这个 seek() 函数,我们就可以实现上面的需求了,如下:

# coding=utf-8
import os
# os.getcwd()获取当前路径,即项目工程的目录
f = open('filetest.txt','r')
print("第一次读到的内容:", f.readline())
f.seek(0,0)  # 重置文件指针到文件开头的第0个位置
print("第二次读到的内容:", f.readline())

结果如下:

第一次读到的内容:今年是佩奇年,平安健康!
第二次读到的内容:今年是佩奇年,平安健康!

那么,能不能查看当前文件指针的位置呢?答案是肯定的,就是 tell()函数。
例如:

# coding=utf-8
import os
# os.getcwd()获取当前路径,即项目工程的目录
f = open('filetest.txt','r')
print("当前文件指针的位置:", f.tell())
print("第一次读到的内容:", f.readline())
print("当前文件指针的位置:", f.tell())
print("第二次读到的内容:", f.read(6))
print("当前文件指针的位置:", f.tell())

结果如下:

当前文件指针的位置:0
第一次读到的内容:今年是佩奇年,平安健康!

当前文件指针的位置:26
第二次读到的内容:Python
当前文件指针的位置:32

这里总结一下关于文件指针的运用方式:

file.seek(offset, wherece)  # 移动 file 指针

file.seek(0,0)  # 移动指针指文件最开头

file.seek(9,1)  # 将文件指针从当前位置往后移动 9 个位置

file.seek(0,2)  # 移动指针指文件最末尾

file.tell()  # 读取当前文件指针,每次统计都是从文件头到当前指针所在位置

f.truncate()  # 截断,参照物永远都是文件开头

总结

  • r 打开,文件指针在最前;
  • w 打开,文件清空文件指针在最前;
  • a 打开,文件指针在最后面

文件模式

打开文件有以下几个模式:

模式 说明
r 只读模式:文件不存在的时候会报错;只能读不能写。如果进行写也会报错:not writeable
w 只写模式:文件不存在的话,帮你创建;不能读,重复打开文件会清空原来的文件内容。可以理解为把原来的删除了,重新建了个文件
a 追加模式:文件不存在的话,帮你创建;不会清空原来文件的内容,但是不能读
r+ 读写模式:可读、可写;可追加,如果打开的文件不存在的话,会报错
w+ 写读模式:使用w+的话,已经存在的文件内容会被清空,可以读到已经写的文件内容
a+ 追加读写模式:文件不存在则创建;存在则只追加内容,能写能读
rU "U"表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)
r+U "U"表示在读取时,可以将 \r \n \r\n自动转换成 \n (与 r 或 r+ 模式同使用)
rb "b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
wb "b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)
ab "b"表示处理二进制文件(如:FTP发送上传ISO镜像文件,linux可忽略,windows处理二进制文件时需标注)

常用操作文件方式

f.read()  # 读取文件内所有的内容

f.readlne()  # 读取文件内一行的内容,如果调用两次,那么会在往下读取一行,返回的是一个字符串

f.readlines()  # 读取文件内所有内容,按行转化成一个 list ,每一行都是这个 list 的一个元素

f.writelines()  # 括号内传一个 list ,会将 list 内的每一个元素写入

f.truncate()  # 从文件指针的位置开始清除内容到最后,所以要清空文件要先 f.seek(0,0)

f.truncae(size)  # 从文件当前指针的位置删出固定 size 的字符数

f.tell()  # 当前指针的位置

f.seek(offset, wherece)  # 移动文件指针

file.seek(0,0)  # 移动指针指文件最开头

file.seek(9,1)  # 将文件指针从当前位置往后移动 9 个位置

file.seek(0,2)  # 移动指针指文件最末尾

with open('a.txt') as f1, open('b.txt','w') as f2:  # 可以用 with 打开一个或多个文件,不用手动 close 去显式关闭,会自动给关闭(这里要注意是什么时候关闭,答案是:视情况而定)

场景1、把一个 list  = [123,456,789] 存入到 文件内,那么按照我们之前的方式:

list = [123,456,789]
for i in list:
    f.write(i+'\n')

那么简单方式:

其实 writelines() 里面内置了一个循环

list = [123,456,789]
f.writelines(list)

操作文件

功能 说明
f = open('file.txt','r+',encoding='utf-8') encoding参数可以指定文件的编码
f.readline() 读一行
f.readable() 判断文件是否可读
fr.writable() 判断文件是否可写
fr.encoding 打印文件的编码
f.read() 读取所有内容,大文件时不要用,
因为会把文件内容都读到内存中,
内存不够的话,会把内存撑爆
f.readlines() 读取所有文件内容,返回一个list,
元素是每行的数据,大文件时不要用,
因为会把文件内容都读到内存中,
内存不够的话,会把内存撑爆
f.tell() 获取当前文件的指针指向
f.seek(0) 把当前文件指针指向哪
f.write('爱情证书') 写入内容
f.fulsh() 写入文件后,立即从内存中把数据写到磁盘中
f.truncate() 清空文件内容
f.writelines(['爱情证书','孙燕姿']) 将一个列表写入文件中
f.close() 关闭文件

大文件修改

升级版的问题操作,以上只是基本的打开文件以及操作方式,那么思考一个问题,我们打开文件,读取/修改文件,都是和内存打交道。那么假设我们文件很大,那么会有什么问题?以及怎么避免掉这些问题呢?

往下看:

1、读取大文件显示

如果我们要读取一个大文件,如果直接将文案全部取出来存为一个变量打印,那样太费内存,循环每行打印可以节省内存。

with open('file.txt',encording = 'utf-8') as f:
    for line in f:
        print(line)

2、分析日志

  统计超过规定访问次数的 ip。假设有一个日志文件,该日志统计了本服务器被其他 ip 的访问记录,假设要预防攻击,则看有哪些 ip 频繁访问就好了,我们将 ip > 20 的,筛选出来。而且假设我们要统计没分钟内,访问量超过 20 次的 ip ,将其禁用,怎么做?

178.210.90.90 - - [04/Jun/2017:03:44:13 +0800] "GET /wp-includes/logo_img.php HTTP/1.0" 302 161 "http://nnzhp.cn/wp-includes/logo_img.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4" "10.3.152.221"
178.210.90.90 - - [04/Jun/2017:03:44:13 +0800] "GET /blog HTTP/1.0" 301 233 "http://nnzhp.cn/wp-includes/logo_img.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4" "10.3.152.221"
178.210.90.90 - - [04/Jun/2017:03:44:15 +0800] "GET /blog/ HTTP/1.0" 200 38278 "http://nnzhp.cn/wp-includes/logo_img.php" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4" "10.3.152.221"…… 

那么日志文件一般比较大,行数较多,怎么处理呢?而且要解决每次对该日志进行统计的问题

解决方案:

1、打开文件;

2、依次读取文件内的每行;

3、读取每行里面的 ip 地址,利用 split() 的空格分割,取第一列数据

4、写一个字典,ip 存为 key,count 为 value ,假设 ip 在 key 内,则对应的 key 初始值为1 ,每次仔出现一次对应的 key ,则 value值 +1 ,这样可以统计到每个 ip 的出现次数,在打印出 value > 20 的 ip;

5、写一个延时,每 60s 调用一次

import time
point = 0
while True:
    with open('access.log',encoding='utf-8') as f:
        f.seek(point)
        ips  = {}
        for line in f:
            ip = line.split()[0] #取到ip地址
            if ip not in ips: #判断ip是否出现过,没有出现过ip的次数就是1
                ips[ip] = 1
            else:#出现过的话,次数就在原来的基础上+1
                ips[ip]+=1
        point = f.tell()#记录读完的位置
        for k,v in ips.items():
            if v>=20:
                print('有问题的ip地址是%s'%k)
    time.sleep(60)

3、大文件修改之——替换操作

假设有一个文件,一般来讲我们进行替换,比如说将 S 替换成 Python ,最无脑的方式:

  1. 先读取到所有的内容,修改
  2. 然后清空原有文件的内容,再写入新的
f = open('names.txt','a+')
f.seek(0)
res = f.read().replace('S','Python')
f.seek(0)
f.truncate()
f.write(res)

显而易见,直接 read 出整个文件,存为一个变量,进行替换操作,这样的影响是会占用大量内存!

因为把整个文件一次性取出来……那么怎么优化呢?

那我们每次取出一行,赋值给变量,然后写入一个新文件,再读取第二行,依次循环……再用新文件把旧的文件给替换,就 ok

with open('file.txt') as fr,with open('file_new','w') as fw: #这个是多文件的操作,打开两个文件,fr是读file.txt,fw是新建一个file_bak文件
for line in fr:#循环file.txt中的每一行
    new_line = line.replace('我','me')
    fw.write(new_line)#写到file_bak文件中
    fw.flush() #立即写入文件
os.remove('file.txt')
os.rename('file_new','file.txt')

4、修改文件内容

假设这里是每个同学的分数,我们要计算每个同学的平均分,加到每个童鞋的最后面

xiaohei,80,91,100,90
xiaohei,80,93,100,91
xiaohei,80,90,100,90

想一想,每一行都要修改如果逐行读取逐行系修改到本文件内,有点太难了。

简单粗暴的方式:

1、先读取到所有的内容,修改

2、然后清空原有文件的内容,再写入新的

f = open('account.txt','a+')
f.seek(0)
l = []
for line in f:
    line = line.strip()
    line_list = line.split(',')
    sum = int(line_list[1])+int(line_list[2])+int(line_list[3])    #sum = sum(int(line_list[1:]))  #切片取后三列再求和
    avg = sum//3  #这里 //3 是因为如果单个 / ,打印出的结果会保留好多位,这个是清除不必要的 0
    new_line = '%s,%s\n'%(line,avg)
    l.append(new_line)
f.seek(0)
f.truncate()
f.writelines(l)

这种方式不好的地方在哪?这还是把所有的东西都存下来,因为是把所有的值存成 list ,文件大也不好弄

高效率的方式:

1、打开2个文件 a b

2、a 只负责读,b 负责写,再将 a 删除,b 改成 a 文件名

import os
with open('account.txt') as  f,open('account2','w') as fw:
    for line in f:
        line = line.strip()
        line_list = line.split(',')
        sum = int(line_list[1])+int(line_list[2])+int(line_list[3])        #sum = sum(int(line[1:])  #切片算后三列和
        avg = sum//3  # 这里加两个 / 是因为一个 / 默认会有小数点,加两个就取整数
        new_line = '%s,%s\n'%(line,avg)
        fw.write(new_line)
        fw.flush() #立即写入文件,将缓冲区的内容写到磁盘里面。有时候 write 后没进入文件,那是因为缓冲区没有满,加入这个 flush 就能将缓冲区的内容写入
    os.remove('account.txt')
    os.rename('account2','account.txt')

json 操作

这个是一种特殊情况,假设我们要往文件内存东西,要存 key-value 形式,之前我们的操作是:key,value 这种方式写进去,虽然也是比较直观但是我们如果要把文件取出来读写的话,还是有些麻烦,要先一行一行把文件的内容读出来,转成一个字典,再用处理字典的方式进行处理完字符串再写入文件内。这样做太麻烦。

有没有一种方式,在文件内就存成类似字典的形式,且直观,而且取出数据有固定的方法,取成一个字典呢?

在接口测试我们看过 json 串,是存数据的,也是 key-value 形式,那么字典能不能以 json 形式存在文件内,取出的时候再将 json 转成字典呢?

首先我们要知道,存在文件内取出的东西都是字符串,写进去的也是字符串。你如果将一个字典写进文件是写入不了的

比如说:

d = {","abc":123,'bcd':'哈哈哈','sdfsd':'sdfs'}
f = open('user4.txt','w',encoding='utf-8')
f.write(d)

会报错:TypeError: write() argument must be str, not dict

那么我们先要将字典转成字符串,可以直接用 str(d) 方法,但是这样写入的还是一行,文件里面存的虽然像是字典,其实也是字符串,取出来还是要处理,因为不是 json 格式。

怎么将字典转成 json 串(json 也是个字符串)呢?利用 json 模块处理

1、字典转成 json 串 —— json.dumps

三步:1、打开文件;2、把字典 dumps 转成字符串;3、把字符串写到文件内

d = {","abc":123,'bcd':'哈哈哈','sdfsd':'sdfs'}
res = json.dumps(d,indent=4,ensure_ascii=False) #把字典转成json串,indent 是每一行前面的空格,ensure_ascii=False代表存入文件的格式不为ascii码,否则中文会为乱码
print(type(res))
print(res)

结果为:

<class 'str'>
{
        ",
        ",
        "abc": 123,
        "bcd": "哈哈哈",
        "sdfsd": "sdfs"
}

那么再将这个结果写入文件内就 ok:

如果存入文件为 json ,最好将文件名改成 xxx.json 这样里面的数字等是彩色显示,直观

f = open('a.json','w',encoding='utf-8')
f.write(res)

文件内的结果:

{
        ",
        ",
        "abc": 123,
        "bcd": "哈哈哈",
        "sdfsd": "sdfs"
}

2、json 串读取成字典 —— json.loads

存入看起来像是字典,但是其实还是字符串,是 json 串而已,那我们怎么将 json 取出来做字典呢?

三步:1、打开文件;2、读取文件内容;3、json.loads 把读到的字符串转换成字典

f = open('a.json',encoding='utf-8')
res = f.read()
print('res的类型',type(res))
d = json.loads(res) #把json串转成字典
print('字典:',d)

结果:

res的类型 <class 'str'>
字典: {', 'abc': 123, 'bcd': '哈哈哈', 'sdfsd': 'sdfs'}

注意:如果要使用 json.loads 那么传入的必须是 json.dumps 或者 json.dump 写入的,如果直接将字典强制性 strf(dict) 写入,键值对显示的是 {'ksy':'value'} 但是 json 串的key-value 形式用的是  {"key":"value"} 双引号,所以强制转换写入的,用 json.load 读取不出来,请勿给自己挖坑

3、升级版本 —— json.dump 和 json.load

上述的其实只是针对字符串处理,比如我们在打印的时候可以将字典 json.dumps 格式化打印出来。那么针对于写入文件以及读取文件的 json 形式,我们用更简单的方式:

两步:1、打开文件;2、json.dump 写入

d= {
        "error_code": 0,
        "stu_info": [
                {
                        "id": 8485,
                        "name": "矿泉水2",
                        "sex": "未知",
                        "age": 38,
                        "addr": "天通苑",
                        "grade": "双子座",
                        ",
                        "gold": 100
                }
        ]
}

fw = open('kqs.json','w',encoding='utf-8')
json.dump(d,fw,indent=4,ensure_ascii=False)

load 可以少写一步,只有两步:1、打开文件;2、load

f = open('user4.txt',encoding='utf-8')
result = json.load(f)
print(result)

小总结:带 s 的是 string 相关的,要利用变量写进去;不带 s 的是文件相关的,直接写入文件内

作业

要求:

1、商品存在文件里面

2、添加商品的时候,商品存在的就不能添加了,数量只能是大于0的整数,价格可以是小数、整数,但是只能是大于0的

  • 商品名称
  • 商品价格
  • 商品数量

3、删除的商品的时候输入商品名称,商品不存在,要提示

4、修改商品的时候

  • 商品名称
  • 商品价格
  • 商品数量

5、查看商品,输入商品名称,查询到商品的信息

import json
#常量
FILENAME='product.json' #全局变量

def write_file(d):
    with open(FILENAME,'w',encoding='utf-8') as fw:
        json.dump(d,fw,indent=4,ensure_ascii=False)

def read_file():
    with open(FILENAME,encoding='utf-8') as fw:
        return json.load(fw)

def check_int(num): #校验是否为大于0的整数
    num = str(num)
    if num.isdigit() and int(num)>0:
        return True

def check_price(num):
    num = str(num)
    if num.count('.')==1:
        left,right = num.split('.') # 0.0
        if left.isdigit() and right.isdigit() and int(right)>0:
            return True
    elif check_int(num):
        return True

all_product = read_file()  #获取到所有的商品

def add_product():
    name = input('name:').strip()
    count = input('count:').strip()
    price = input('price:').strip()
    if name and count and price:
        if not check_int(count):
            print('商品数量错误')
        elif not check_price(price):
            print('价格错误')
        elif name in all_product:
            print('商品已存在')
        else:
            all_product[name]= {'price':price,'count':count}
            write_file(all_product)
            print('商品添加成功!')
    else:
        print('不能为空!')

def edit_product():
    while True:
        name = input('name:').strip()
        if name in all_product:
            break
        elif name=='q':
            quit('退出')
    count = input('count:').strip()
    price = input('price:').strip()
    if name and count and price:
        all_product[name] = {'price': price, 'count': count}
        write_file(all_product)
        print('修改成功!')
    else:
        print('不能为空!')

def show_product():
    while True:
        name = input('name:').strip()
        if name in all_product:
            print(all_product.get(name))
            break
        elif name=='all':
            print(json.dumps(all_product,indent=4,ensure_ascii=False))
            break
        elif name=='q':
            quit('退出')

def del_product():
    while True:
        name = input('name:').strip()
        if name in all_product:
            all_product.pop(name)
            write_file(all_product)
            print('删除成功!')
        elif name=='q':
            quit('退出')

func_map = {
    ":add_product,
    ":del_product,
    ":edit_product,
    ":show_product,
    ":quit
}
for i in range(4):
    choice = input('请输入你的选择:\n'
                   '1、添加商品\n'
                   '2、删除商品\n'
                   '3、修改商品信息\n'
                   '4、查看商品\n'
                   '5、退出')

    if choice in func_map:
        func_map.get(choice)()
    else:
        print('请输入正确的选项!')

最新文章

  1. 【手记】WebBrowser响应页面中的blank开新窗口及window.close关闭本窗体
  2. 再谈HashMap
  3. Titanium studio介绍
  4. .net学习之路——调试程序
  5. JavaScript强化教程 -- cocosjs场景切换
  6. java实现MD5加密
  7. JDK源码包结构分类
  8. 递推DP 赛码 1005 Game
  9. Android开发把项目打包成apk
  10. KAFKA分布式消息系统[转]
  11. angularjs现学现记之—$apply()和$digest()
  12. Chapter 3.单一职责原则
  13. Glide的常用方法注释
  14. 【JAVASCRIPT】React学习- 数据流(组件通信)
  15. Web原理
  16. 简单的纯js三级联动
  17. php7 + 新特性 部分
  18. elasticsearch索引合并
  19. day1 查看当前目录命令:pwd
  20. every day a practice —— morning(5)

热门文章

  1. 一:配置Linux Centos7 .netCore 部署环境
  2. python单列模式
  3. [Java] [Singleton] [DCL][happens-before]
  4. mysql5.7通过json类型替代关联表
  5. Qt设置创建部分半透明,上面控件不透明
  6. 【解决】Server Tomcat v7.0 Server at localhost failed to start.
  7. 浅谈在java中list集合的排序问题
  8. 同一个服务器部署两个Tomcat并用Nginx实现反向代理
  9. SpringJPA主键生成采用自定义ID,自定义ID采用年月日时间格式
  10. linux下mysql的启动与关闭