存储

有时你需要存储有用的信息。这些信息以数据(信息的表现形式)的方式存储(在电脑中以数字的形式存储)。若你将数据存储在电脑中,即使关闭或重启设备,数据应该会一直保留。

令人高兴的是,micro:bit可以让你用一个非常简单的文件系统来做到这一点。 由于内存限制,文件系统上 大约有30k的可用存储空间

什么是文件系统呢?

它是一种以持久方式存储和组织数据的方法 - 存储在文件系统中的任何数据在设备重新启动后不会丢失。 顾名思义,存储在文件系统中的数据被组织后形成文件。

../_images/files.jpg

计算机文件是存储在文件系统上的被命名的数字资源。这些资源以有用的信息作为数据。 这正是纸质文件的工作原理。它是一种包含有用信息的被命名的容器。 通常,纸质和数字文件都被命名以指示它们包含的内容。在计算机上,大多以 .something 为后缀结尾文件。 “something” 表示信息数据的类型。 例如, .txt 表示文本文件, .jpg 表示JPEG图像和 .mp3 表示编码为mp3的声音数据。

某些文件系统(例如笔记本电脑或PC上的文件系统)可以让你将文件组织到目录中(目录指的是将相关文件和子目录组合在一起的命名容器)。 但是, MicroPython提供的文件系统是一个平面文件系统, 平面文件系统没有目录 - 所有的文件都存储在同一个地方。

Python编程语言包含使用计算机文件系统的易用且强大的方法。 micro:bit上的MicroPython实现了这些功能的一个有用子集,以便在设备上读取和写入文件,同时还与其他版本的Python保持一致。

警告

对你的micro:bit做刷新操作(Flashing your micro:bit)会破坏所有数据,因为它重写了设备使用的所有闪存,并且文件系统存储在闪存中。但是,如果您关闭设备,数据将保持不变,直到您将其删除或重刷设备(re-flash)。

“芝麻开门”-[打开文件]

在文件系统上读写文件是通过 open 函数实现的。 一旦文件被打开,您可以使用该文件,直到关闭(与我们使用纸质文件的方式类似)。 你必须关闭文件,这样MicroPython就知道你已经完成了该文件。

确保这一点的最好方法是使用像下面这样的 with 语句:

with open('story.txt') as my_file:
    content = my_file.read()
print(content)

with 语句调用 open 函数来打开一个文件并指定其为一个对象。上面的例子中, open 函数打开了一个名为 story.txt 的文件(显然是一个包含某种故事的文本文件)。在Python代码中用于表示文件的对象称为 my_file。 其后,在 with 语句下缩进的代码块中, my_file 对象用于 read() 文件的内容并将其分配给 content 对象。

这点很重要, 下一行中包含 print 的语句没有缩进处理。 与 with 语句相关的代码块只是用于读取文件的单行。 一旦与 with 语句关联的代码块关闭,Python(和MicroPython)将自动关闭该文件。 这称为上下文处理, open 函数创建对象作为文件的上下文处理程序。

简而言之,你与文件交互的范围由与打开文件的 with 语句相关联的代码块定义。

感到困惑吗?

完全不用。我只是说你的代码应该看起来像这样:

with open('some_file') as some_object:
    # Do stuff with some_object in this block of code
    # associated with the with statement.

# When the block is finished then MicroPython
# automatically closes the file for you.

像纸质文件一样,打开一个数字文件有以下两个原因:读取内容(如上所述)或往文件中写入内容。默认模式是读取文件,若是想往文件中写入内容,你需要用下面的方法告诉 open 函数:

with open('hello.txt', 'w') as my_file:
    my_file.write("Hello, World!")

注意下参数 'w' 用于将 my_file 对象设置为写入模式。你也可以传递给程序参数 'r' 来将文件对象设置为读取模式,但由于读取模式是默认模式,一般不用。

将数据写入文件时通过(你猜到了) write 方法来完成的,该方法将你想要写入文件的字符串作为参数。 在上面的例子中,我将文本 “Hello, World!” 写入到一个名为”hello.txt”的文件。

如此简单!

注解

当你打开一个文件写入内容时(文件打开状态下可能多次写入),若是文件已经存在,你将会是在原文件内容“上”(OVER the content of the file)写入内容。

如果你想在某文件中添加数据,应首先读取该文件,将文件内容存储在某处并将其关闭,然后将数据追加到该内容中,接着打开它以将修改后的内容再次写入同一个文件。

MicroPython就是这样, “一般” 的Python可以打开文件以 “追加” 模式写入内容。 我们无法在micro:bit上执行此操作,这是因为它的文件系统实现简单。

OS SOS “操作系统”

Python不仅可以读取和写入文件,也可以处理(manipulate)文件。你肯定知道文件系统中都有哪些文件,有时,你也会需要删除文件。

普通计算机由操作系统来实现,比如Windows,OSX或Linux,Python实现该功能等同于操纵系统。Python通过名为 os 的模块来完成该功能。由于MicroPython 操纵系统,因此我们决定在 os 模块中保留相应的功能以保持一致性,因此当你在笔记本电脑或Raspberry Pi(小型单板计算机)等设备上使用 “常规” Python时,会知道在哪里找到它们。

总的来说,你可以执行三个与文件系统相关的操作:列出文件,删除文件和询问文件大小。

要列出文件系统中的文件,需调用 listdir 函数,它会返回一个字符串列表,用于指出文件系统上文件的文件名:

import os
my_files = os.listdir()

删除文件需调用 remove 函数,它用一个字符串来表示要删除的文件的文件名作为参数,就像这样:

import os
os.remove('filename.txt')

最后,有时在阅读文件之前知道文件大小是很有用的。要实现这一点,需调用 size 函数。像 remove 函数一样,它用一个字符串来表示你想要知道其尺寸的文件的文件名。 它会返回一个整数来告诉你文件占用的字节数:

import os
file_size = os.size('a_big_file.txt')

有一个文件系统很好,但若是我们想要将文件放入设备或从设备中移除文件时该怎么办呢?

只需使用 microfs 工具即可。

文件传输

如果你在用于编程BBC micro:bit的电脑上安装了Python,可以使用一个叫做 microfs 的特殊工具(在命令行中使用它时缩写为 ufs )。你可以在 其文档中 找到关于安装和使用microfs的所有功能的完整说明。

尽管如此,只需四个简单的命令就可以完成大部分工作:

$ ufs ls
story.txt

ls 子命令列出了文件系统上的文件(它以通用Unix命令 ls 命名,具有相同的功能)。

$ ufs get story.txt

get 子命令从连接的micro:bit中获取文件并将其保存在你电脑当前的位置(它以 get 命令命名,是通用文件传输协议[FTP]的一部分,具有相同的功能)。

$ ufs rm story.txt

rm 子命令从连接的micro:bit文件系统中删除已命名的文件(它以通用Unix命令 rm 命名,具有相同的功能)。

$ ufs put story2.txt

最终, put 子命令将计算机中的文件放入连接的设备中(它以 put 命令命名,是FTP的一部分,具有相同的功能)。

优先运行的“main.py”

该文件系统还有一个有趣的属性:如果只是将MicroPython要运行的程序“上传”(flash)到设备上,那么当它启动时,它只是在等待运行指令。但是,如果将名为 main.py 的特定文件复制到文件系统中,则在重新启动设备时,MicroPython将运行 main.py 文件的内容。

此外,如果你将其他Python文件复制到文件系统上,你可以像引用其他Python的模块一样 import引用 )它们。例如,如果你有一个包含以下简单代码的 hello.py 文件:

def say_hello(name="World"):
    return "Hello, {}!".format(name)

…你可以像下面这样引用 say_hello 函数:

from microbit import display
from hello import say_hello

display.scroll(say_hello())

当然,在显示屏上会滚动显示文本“Hello,World!”。 重要的一点是,这个例子是在两个Python模块之间进行分割的, import 语句用于共享代码。

注解

如果你不是在MicroPython运行期间将脚本上传到设备上,那么MicroPython将会忽略 main.py 部分,直接运行已嵌入的脚本。

在MicroPython运行时上传到设备上,仅需确保你不再编辑器中编写脚本即可。一旦上传完成,则可以覆盖 main.py 文件的赋值。