Skip to content

文件

11 / 44

我们需要处理的数据一定是很多所以才必须由计算机帮我们处理 —— 大量的数据保存读取写入需要的就是文件(Files)。在这一章里我们只介绍最简单的文本文件

创建文件

创建一个文件最简单的方式就是用 Python 的内建函数 open()

open() 函数的官方文档很长以下是个简化版

open(file, mode='r')

第二个参数mode默认值是 'r'可用的 mode 有以下几种

| 参数字符 | 意义 |

|

--- |






  • | | 'r' | 只读模式 | | 'w' | 写入模式重建)| | 'x' | 排他模式 —— 如果文件已存在则打开失败 | | 'a' | 追加模式 —— 在已有文件末尾追加 | | 'b' | 二进制文件模式 | | 't' | 文本文件模式默认)| | '+' | 读写模式更新)|

创建一个新文件用这样一个语句就可以

python
open('/tmp/test-file.txt', 'w')
plaintext
<_io.TextIOWrapper name='/tmp/test-file.txt' mode='w' encoding='UTF-8'>

当然更多的时候我们会把这个函数的返回值一个所谓的 file object保存到一个变量中以便后面调用这个 file object 的各种 Methods,比如获取文件名 file.name比如关闭文件 file.close()

python
f = open('/tmp/test-file.txt', 'w')
print(f.name)
f.close()
plaintext
/tmp/test-file.txt

删除文件

删除文件就得调用 os 模块了删除文件之前要先确认文件是否存在否则删除命令会失败

python
import os

f = open('/tmp/test-file1.txt', 'w')
print(f.name)
f.close() #关闭文件,否则无法删除文件
if os.path.exists(f.name):
    os.remove(f.name)
    print(f'{f.name} deleted.')
else:
    print(f'{f.name} does not exist.')
plaintext
/tmp/test-file1.txt
/tmp/test-file1.txt deleted.

读写文件

创建文件之后我们可以用 f.write() 把数据写入文件也可以用 f.read() 读取文件

python
f = open('/tmp/test-file.txt', 'w')
f.write('first line\nsecond line\nthird line\n')
f.close()

f = open('/tmp/test-file.txt', 'r')
s = f.read()
print(s)
f.close()
plaintext
first line
second line
third line

文件有很多行的时候我们可以用 file.readline() 操作这个 Method 每次调用都会返回文件中的新一行

python
f = open('/tmp/test-file.txt', 'w')
f.write('first line\nsecond line\nthird line\n')
f.close()

f = open('/tmp/test-file.txt', 'r')
s = f.readline()    # 返回的是 'first line\n'
print(s)
s = f.readline()    # 返回的是 'second line\n'
print(s)
f.close()
plaintext
first line
second line

注意返回结果好像跟你想的不太一样这时候之前见过的 str.strip() 就派上用场了

python
f = open('/tmp/test-file.txt', 'w')
f.write('first line\nsecond line\nthird line\n')
f.close()

f = open('/tmp/test-file.txt', 'r')
s = f.readline().strip()    # 返回的是 'first line','\n' 被去掉了……
print(s)
s = f.readline().strip()    # 返回的是 'second line','\n' 被去掉了……
print(s)
f.close()
plaintext
first line
second line

与之相对的我们可以使用 file.readlines() 这个 Method,将文件作为一个列表返回列表中的每个元素对应着文件中的每一行

python
f = open('/tmp/test-file.txt', 'w')
f.write('first line\nsecond line\nthird line\n')
f.close()

f = open('/tmp/test-file.txt', 'r')
s = f.readlines()    # 返回的是一个列表,注意,readlines,最后的 's'
print(s)
f.close()
plaintext
['first line\n', 'second line\n', 'third line\n']

既然返回的是列表那么就可以被迭代逐一访问每一行

python
f = open('/tmp/test-file.txt', 'w')
f.write('first line\nsecond line\nthird line\n')
f.close()

f = open('/tmp/test-file.txt', 'r')
for line in f.readlines():
    print(line)
f.close()
plaintext
first line
second line
third line

与之相对的我们也可以用 file.writelines() 把一个列表写入到一个文件中按索引顺序 0 开始逐行写入列表的对应元素::

python
a_list = ['first line\n', 'second line\n', 'third line\n']
f = open('/tmp/test-file.txt', 'w')
f.writelines(a_list)
f.close()

f = open('/tmp/test-file.txt', 'r')
for line in f.readlines():
    print(line)
f.close()
plaintext
first line
second line
third line

with 语句块

针对文件操作,Python 有个另外的语句块写法更便于阅读

python
with open(...) as f:
    f.write(...)
    ...

这样就可以把针对当前以特定模式打开的某个文件的各种操作都写入同一个语句块了

python
import os

with open('/tmp/test-file.txt', 'w') as f:
    f.write('first line\nsecond line\nthird line\n')

with open('/tmp/test-file.txt', 'r') as f:
    for line in f.readlines():
        print(line)

if os.path.exists(f.name):
    os.remove(f.name)
    print(f'{f.name} deleted.')
else:
    print(f'{f.name} does not exist.')
plaintext
first line
second line
third line
test-file.txt deleted.

另外 with 语句块的另外一个附加好处就是不用写 file.close() ……

另一个完整的程序

若干年前我在写某本书的时候需要一个例子 —— 用来说明即便是结论正确,论证过程乱七八糟也不行!

作者就是这样主要任务之一就是给论点找例子找论据找得到不仅恰当且又精彩的例子和论据的就是好作者后面这个精彩二字要耗费很多时间精力因为它意味着说要找到很多例子而后在里面选出最精彩的那个!” —— 根本不像很多人以为的那样是所谓的信手拈来”。

找了很多例子都不满意…… 终于有一天我看到这么个说法

如果把字母 a 计为 1b 计为 2c 计为 3 …… z 计为 26那么

  • knowledge = 96
  • hardwork = 98
  • attitude = 100

所以结论是

  • 知识knowledge与勤奋hardwork固然都很重要
  • 但是决定成败的却是态度attitude)!

结论虽然有道理 —— 可这论证过程实在是太过分了罢……

我很高兴觉得这就是个好例子并且加工一下会让读者觉得很精彩 —— 如果能找到一些按照同样的计算方式能得到 100 的单词并且还是那种一看就是反例的单词……

凭直觉英文单词几十万如此这般等于 100 的单词岂不是数不胜数并且一定会有很多负面意义的单词如此计算也等于 100 然而这种事情凭直觉是不够的手工计算又会被累死…… 于是面对如此荒谬的论证过程我们竟然无话可说”。

幸亏我是会写程序的人所以不会干着急没办法”,我有能力让计算机帮我把活干了

很快就搞定了找到很多很多个如此计算加起来等于 100 的英文单词其中包括

  • connivance(纵容
  • coyness(羞怯
  • flurry(慌张
  • impotence(阳痿
  • stress(压力
  • tuppence(微不足道的东西
  • ……

所以决定成败的可以是慌张”(flurry),甚至是阳痿”(impotence)?这不明显是胡说八道嘛

—— 精彩例子制作完毕我把它放进了书里

具体的过程是什么样的呢

首先我得找到一个英文单词列表很全的那种这事用不着写程序,Google 一下就可以了我搜索的关键字是english word list”,很直观吧然后就找到一个https://github.com/dwyl/english-words这个链接里有一个 words-alpha.txt 文件其中包含接近 37,0101 个单词应该够用了下载下来用程序处理就可以了

因为文件里每行一个单词所以就让程序打开文件将文件读入一个列表而后迭代这个列表逐一计算那个单词每个字母所代表的数字并加起来看看是否等于 100?如果是就将它们输出到屏幕…… 好像不是很难

python
with open('words_alpha.txt', 'r') as file:
    for word in file.readlines():
        pass # 先用 pass 占个位,一会儿再写计算过程

按照上面那说法 a 记为 1直至把 z 记为 26这事并不难因为有 ord() 函数啊 —— 这个函数返回字符的 Unicode 编码ord('a') 的值是 97那按上面的说法 ord('a') - 96 就相当于得到了 1 这个数值…… ord('z') - 96 就会得到 26 这个数值

python
ord('a')
plaintext
97

那么计算 'knowledge' 这个字符串的代码很简单

python
word = 'knowledge'
sum = 0
for char in word:
    sum += ord(char) - 96
print(sum)
plaintext
96

果然得到的数值等于 96 —— 不错把它写成一个函数罢sum_of_word(word):

python
def sum_of_word(word):
    sum = 0
    for char in word:
        sum += ord(char) - 96
    return sum

sum_of_word('attitude')
plaintext
100

那让程序就算把几十万行都算一遍也好像很简单了

python
def sum_of_word(word):
    sum = 0
    for char in word:
        sum += ord(char) - 96
    return sum

with open('words_alpha.txt', 'r') as file:
    for word in file.readlines():
        if sum_of_word(word) == 100:
            print(word)
plaintext
abstrusenesses
acupuncturist
adenochondrosarcoma
...
worshipability
zeuctocoelomatic
zygapophysis

怎么输出结果跟想得不一样找到的词怎么都奇形怪状…… 而且输出结果中也没有 attitude 这个词

插入个中止语句break把找到的第一个词中的每个字符和它所对应的值都拿出来看看

python
def sum_of_word(word):
    sum = 0
    for char in word:
        sum += ord(char) - 96
    return sum

with open('words_alpha.txt', 'r') as file:
    for word in file.readlines():
        if sum_of_word(word) == 100:
            print(word)
            for c in word:        # 把字母和值都打出来,看看对不对?
                print(c, ord(c) - 96)
            break                 # 找到一个之后就停下来。
plaintext
abstrusenesses

a 1
b 2
s 19
t 20
r 18
u 21
s 19
e 5
n 14
e 5
s 19
s 19
e 5
s 19

 -86

怎么有个 -86?!仔细看看输出结果看到每一行之间都被插入了一个空行想到应该是从文件里读出的行中包含 \n 这种换行符…… 如果是那样的话那么 ord('\n') -96 返回的结果是 -86 怪不得找到的词都奇形怪状……

python
ord('\n') -96
plaintext
-86

改进一下呗 —— 倒也简单在计算前把读入字符串前后的空白字符都给删掉就好了 str.strip() 就可以了

python
def sum_of_word(word):
    sum = 0
    for char in word:
        sum += ord(char) - 96
    return sum

with open('words_alpha.txt', 'r') as file:
    for word in file.readlines():
        if sum_of_word(word.strip()) == 100:
            print(word)
plaintext
abactinally
abatements
abbreviatable
...
zithern
zoogleas
zorgite

如果想把符合条件的词保存到一个文件 results.txt 里的话那么

python
def sum_of_word(word):
    sum = 0
    for char in word:
        sum += ord(char) - 96
    return sum

with open('results.txt', 'w') as result:
    with open('words_alpha.txt', 'r') as file:
        for word in file.readlines():
            if sum_of_word(word.strip()) == 100:
                result.write(word)

竟然这么简单就搞定了?!

10 行的代码在几秒钟内从 370,101 个英文单词中找到 3,771 个如此计算等于 100 的词汇

喝着咖啡翻一翻 results.txt很快就找到了那些用来做反例格外恰当的词汇

真无法想象当年的自己若是不懂编程的话现在会是什么样子……

总结

这一章我们介绍了文本文件的基本操作

  • 打开文件直接用内建函数open()基本模式有 r w
  • 删除文件得调用 os 模块使用 os.remove()删除文件前最好确认文件确实存在……
  • 读写文件分别有 file.read()file.write()file.readline()file.readlines()file.writelines()
  • 可以用 with 把相关操作都放入同一个语句块……