从文件中读取数据

这次打算调整一下思路,把之前边学边写的代码按照知识点分开附上,看下这样会不会明确一些。

#打开并读取一个文件,并将内容显示到屏幕上
with open('pi_digist.txt') as file_object:
    contents=file_object.read()
print(contents)

这部分代码的作用就是打开当前执行文件目录下的一个叫做pi_digist的文本文件,将文件中的内容当做字符串读出来并且输出。
这里第一行代码的内容比较多,首先是open关键字,这个是用来打开文件并返回一个表示文件的对象,这个对象被赋给了file_object,而最前面的with关键字,是用来在不需要访问文件的时候关闭文件的,这样就省下了close的步骤(省的忘记关闭文件了)。
第二行的read是把文件里面的内容当做字符串输出出来。

文件的路径
#打开并读取一个文件,并将内容显示到屏幕上
with open('text_file/pi_digist.txt') as file_object:
    contents=file_object.read()
print(contents)

这里我们进行了一个操作,就是把执行文件目录中新建了一个文件夹,把pi_digist文本放到了里面,这样的话之前的代码就会找不到文件导致报错。此时就引入了文件路径的概念,这个概念在C的学习中就提到过,这里就不多说了。

逐行读取
#打开并逐行读取一个文件,并将内容显示到屏幕上
with open('text_file/pi_digist.txt') as file_object:
    for line in file_object:
        print(line)

这里通过循环实现了对于文件的逐行读取,这样的话如果要对文本内容进行操作就有了可行的的途径。

把文件内容放进内存
#打开并读取一个文件,将文件的内容用列表存起来,在关闭文件之后使用
with open('text_file/pi_digist.txt') as file_object:
    lines=file_object.readlines()
pi_string=''
for line in lines:
    pi_string+=line.strip()
    print(line.rstrip())
print(pi_string)
print(len(pi_string))

open所返回的对象只能在with代码块内使用,所以我们把对象内容存在列表里,就可以在代码块外进行操作了。

超大型文件
#对于大型文件,此处案例是一百万位的圆周率
with open('pi_million_digits.txt') as file_object:
    lines=file_object.readlines()
pi_string=''
for line in lines:
    pi_string+=line.strip()
#防止终端显示爆炸,只显示小数点后50位,可见文件大小对操作没有影响
print(f"{pi_string[:52]}...")
print(len(pi_string))

这里也把结果附上吧

3.14159265358979323846264338327950288419716939937510...
1000002

我们可以见到,这样的操作其实是对于任意大小文件都可以实现的,只要系统内存够。

娱乐案例,圆周率中有没有你的生日
#看看圆周率中有没有你的生日
birthday=input("enter you birthday,in the form mmddyy:")
if birthday in pi_string:
    print("you birthday appear in the first million digits of pi!")
else:
    print("you birthday does not appear in the first million digits of pi!")

这个也就没啥好讲的了,记得input用终端就行。

写入文件

#写入文件,这里我们提前新建了一个空的文本文件programming
filename='programming.txt'
with open(filename,'w') as file_object:
    file_object.write("i love programming!")

这里的写入文件使我们新建好的,其实没有的话代码也会自己生成一个,不过需要注意的是,如果我们以写入模式(‘w’)来打开文件并且文件之前就存在,Python会清空文件内容。
这里要注意的是,Python只能向文本写入字符串数据,如果要输入数值,就得先用str关键字进行转变。
另外,write()函数不会添加换行符,如果用多次write函数,会出现多句字符串首尾相接,需要自己添加换行符才行

附加到文件

有时候,我们向文件输入内容的同时要保留原有内容,这时候就可以用附加模式(‘a’),这样会自动指向文件的末尾,实现内容的添加。
具体案例如下:

filename='programming.txt'
with open(filename,'w') as file_object:
    file_object.write("i love programming!\n")
    file_object.write("I like python\n")

with open(filename,'a') as file_object:
    file_object.write("i love programming!\n")
    file_object.write("I like python")

结果为:

i love programming!
I like python
i love programming!
I like python

如果第二次还是以写入模式打开就只会有后两行。

异常

异常,是用来管理程序执行期间所发生的一些让计算机不知道怎么处理的错误的(大概就是这个意思,我当时学C++的时候就是这么以为的),最简单的就是除0问题。
异常使用try_except代码块来进行处理。告诉程序遇到这个情况要怎么办。

#异常
try:
    print(5/0)
except ZeroDivisionError:
    print("you cannot divide by 0")

如果没有这个代码块,单纯的输出5/0,用户会看到的是traceback,这样的话可以使得程序顺利输出我们准备好的报错信息。
(ps:那个ZeroDivisionError,是这个错误的名称,没有也不影响使用,但是写错名字了反而会报错)
灵活的使用异常可以避免程序动不动就崩溃,保证程序先运行下去,免得后面可以运行的部分也不能运行。

#异常的具体使用
print("give me 2 number,i will divide them")
while True:
    first_number=input("first_number:  ")
    if first_number=='q':
        break
    second_number=input("second_number:  ")
    if second_number=='q':
        break
    try:
        answer=int(first_number)/int(second_number)
    except ZeroDivisionError:
        print("you cannot divide by 0")
    else:
        print(answer)

(ZeroDivisionError的具体使用案例)

处理FileNotFoundError异常

在使用文件是,很常见的一类问题就是找不到文件,此时也可以使用异常来以更加直观的方式处理:

#文件异常
try:
    with open('alice.txt',encoding='utf-8') as f:
        contents=f.read()
except FileNotFoundError:
    print("Not find the file")
分析文本

这里我们在执行文件目录中添加了《爱丽丝漫游奇境记》,命名问Alice,之后通过代码来大致判断这个文本文件的篇幅

filename='alice.txt'
try:
    with open(filename,encoding='utf-8') as f:
        contents=f.read()
except FileNotFoundError:
    print("Not find the file")
else:
    #计算一个大文本里面有多少单词
    words=contents.split()
    num_words=len(words)
    print(f"the file {filename} has about {num_words} words")

这里我们也可以把这部分写作一个函数,文件路径作为参数,就可以实现使用多个文件了。

静默失败

所谓静默失败,就是在程序出现异常的时候,程序什么都不表示,代码继续运行。这里我们使用的是pass关键字。

#文件异常
try:
    with open('alice.txt',encoding='utf-8') as f:
        contents=f.read()
except FileNotFoundError:
    pass

通过异常,我们可以避免很多时候用户输入,网络连接等不可控情况对代码运行的影响。

存储数据

这里我们使用Python标准库中的json模块,至于Python标准库的相关信息可以看我前面第九章所述。

使用json保存数据
#使用json保存数据
import json
numbers=[2,3,5,7,11,13]
filename='numbers.json'
with open(filename,'w') as f:
    #让数字列表存入json文件中
    json.dump(numbers,f)

#使用json读取数据
with open(filename) as f:
    numbers_2=json.load(f)
print(numbers_2)

使用json保存信息,是为了方式用户信息在程序停止运行时丢失。

总结前面知识点的大代码(相对的)

def get_stored_uesrname():
    '''如果之前就存储了用户名,就获取它'''
    filename='username.json'
    try:
        with open(filename) as f:
            username=json.load(f)
    except FileNotFoundError:
        return None
    else:
        return username

def get_new_username():
    '''输入新的用户名'''
    username=input("what's your name: ")
    filename='username.json'
    with open(filename,'w') as f:
        json.dump(username,f)
    return username

def greet_user():
    '''问候用户'''
    username=get_stored_uesrname()
    if username:
        print(f"welcome back,{username}!")
    else:
        username=get_new_username()
        print(f"we will remember you when you come back,{username}")

greet_user()

这个代码包含了这两个章节的大部分内容,不过功能上还是有点弱,有意愿的同仁可以添加一些功能,这次写的有点多,感觉确实是越往后内容越多啊。