Skip to content

Commit

Permalink
Add a beginner friendly file system tutorial.
Browse files Browse the repository at this point in the history
  • Loading branch information
ntoll committed Jun 12, 2016
1 parent 9dbb461 commit c084920
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 6 deletions.
5 changes: 3 additions & 2 deletions docs/filesystem.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ to work with such file systems.
However, since the micro:bit is a limited device in terms of both hardware and
storage capacity MicroPython provides a small subset of the functions needed
to persist data on the device. Because of memory constraints **there is
approximately 30k of storage available** on the filesystem.
approximately 30k of storage available** on the file system.

.. warning::

Expand Down Expand Up @@ -63,7 +63,8 @@ An example session in the MicroPython REPL may look something like this::
(for reading and writing bytes). If these are not specified then ``'t'``
(text mode) is assumed. When in text mode the file object will be an
instance of ``TextIO``. When in binary mode the file object will be an
instance of ``BytesIO``.
instance of ``BytesIO``. For example, use ``'rb'`` to read binary data from
a file.


.. py:class::
Expand Down
Binary file added docs/tutorials/files.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
231 changes: 227 additions & 4 deletions docs/tutorials/storage.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,231 @@
Storage
-------

A tutorial for the local filesystem will arrive here soon. It will include:
Sometimes you need to store useful information. Such information is stored as
data: representation of information (in a digital form when stored on
computers). If you store data on a computer it should persist, even if you
switch the device off and on again.

* Details of how to open, read and write to files.
* Details of how to manage files stored on the device via the os module.
* Details of how to get, set and delete files from a connected computer.
Happily MicroPython on the micro:bit allows you to do this with a very simple
file system. Because of memory constraints **there is approximately 30k of
storage available** on the file system.

What is a file system?

It's a means of storing and organising data in a persistent manner - any data
stored in a file system should survive restarts of the device. As the name
suggests, data stored on a file system is organised into files.

.. image:: files.jpg

A computer file is a named digital resource that's stored on a file system.
Such resources contain useful information as data. This is exactly how a
paper file works. It's a sort of named container that contains useful
information. Usually, both paper and digital files are named to indicate what
they contain. On computers it is common to end a file with a ``.something``
suffix. Usually, the "something" indicates what type of data is used to
represent the information. For example, ``.txt`` indicates a text file,
``.jpg`` a JPEG image and ``.mp3`` sound data encoded as MP3.

Some file systems (such as the one found on your laptop or PC) allow you to
organise your files into directories: named containers that group related files
and sub-directories together. However, *the file system provided by MicroPython
is a flat file system*. A flat file system does not have directories - all
your files are just stored in the same place.

The Python programming language contains easy to use and powerful ways in which
to work with a computer's file system. MicroPython on the micro:bit implements
a useful subset of these features to make is easy to read and write files on
the device, while also providing consistency with other versions of Python.

.. warning::

Flashing your micro:bit will DESTROY ALL YOUR DATA since it re-writes all
the flash memory used by the device and the file system is stored in the
flash memory.

However, if you switch off your device the data will remain intact until
you either delete it or re-flash the device.

Open Sesame
+++++++++++

Reading and writing a file on the file system is achieved by the ``open``
function. Once a file is opened you can do stuff with it until you close it
(analogous with the way we use paper files). It is essential you close a file
so MicroPython knows you've finished with it.

The best way to make sure of this is to use the ``with`` statement like this::

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

The ``with`` statement uses the ``open`` function to open a file and assign it
to an object. In the example above, the ``open`` function opens the file called
``story.txt`` (obviously a text file containing a story of some sort).
The object that's used to represent the file in the Python code is called
``my_file``. Subsequently, in the code block indented underneath the ``with``
statement, the ``my_file`` object is used to ``read()`` the content of the
file and assign it to the ``content`` object.

Here's the important point, *the next line containing the* ``print`` *statement
is not indented*. The code block associated with the ``with`` statement is only
the single line that reads the file. Once the code block associated with the
``with`` statement is closed then Python (and MicroPython) will automatically
close the file for you. This is called context handling and the ``open``
function creates objects that are context handlers for files.

Put simply, the scope of your interaction with a file is defined by the code
block associated with the ``with`` statement that opens the file.

Confused?

Don't be. I'm simply saying your code should look like this::

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.

Just like a paper file, a digital file is opened for two reasons: to read its
content (as demonstrated above) or to write something to the file. The default
mode is to read the file. If you want to write to a file you need to tell the
``open`` function in the following way::

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

Notice the ``'w'`` argument is used to set the ``my_file`` object into write
mode. You could also pass an ``'r'`` argument to set the file object to read
mode, but since this is the default, it's often left off.

Writing data to the file is done with the (you guessed it) ``write``
method that takes the string you want to write to the file as an argument. In
the example above, I write the text "Hello, World!" to a file called
"hello.txt".

Simple!

.. note::

When you open a file and write (perhaps several times while the file is
in an open state) you will be writing OVER the content of the file if it
already exists.

If you want to append data to a file you should first read it, store the
content somewhere, close it, append your data to the content and then open
it to write again with the revised content.

While this is the case in MicroPython, "normal" Python can open
files to write in "append" mode. That we can't do this on the micro:bit is
a result of the simple implementation of the file system.

OS SOS
++++++

As well as reading and writing files, Python can manipulate them. You
certainly need to know what files are on the file system and sometimes
you need to delete them too.

On a regular computer, it is the role of the operating system (like Windows,
OSX or Linux) to manage this on Python's behalf. Such functionality is made
available in Python via a module called ``os``. Since MicroPython **is** the
operating system we've decided to keep the appropriate functions in the ``os``
module for consistency so you'll know where to find them when you use "regular"
Python on a device like a laptop or Raspberry Pi.

Essentially, you can do three operations related to the file system: list the
files, remove a file and ask for the size of a file.

To list the files on your file system use the ``listdir`` function. It
returns a list of strings indicating the file names of the files on the file
system::

import os
my_files = os.listdir()

To delete a file use the ``remove`` function. It takes a string representing
the file name of the file you want to delete as an argument, like this::

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

Finally, sometimes it's useful to know how big a file is before reading from
it. To achieve this use the ``size`` function. Like the ``remove`` function, it
takes a string representing the file name of the file whose size you want to
know. It returns an integer (whole number) telling you the number of bytes the
file takes up::

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

It's all very well having a file system, but what if we want to put or get
files on or off the device?

Just use the ``microfs`` utility!

File Transfer
+++++++++++++

If you have Python installed on the computer you use to program your BBC
micro:bit then you can use a special utility called ``microfs`` (shortened to
``ufs`` when using it in the command line). Full instructions for installing
and using all the features of microfs can be found
`in its documentation <http://microfs.rtfd.org>`_.

Nevertheless it's possible to do most of the things you need with just four
simple commands::

$ ufs ls
story.txt

The ``ls`` sub-command lists the files on the file system (it's named after
the common Unix command, ``ls``, that serves the same function).

::

$ ufs get story.txt

The ``get`` sub-command gets a file from the connected micro:bit and saves it
into your current location on your computer (it's named after the ``get``
command that's part of the common file transfer protocol [FTP] that serves the
same function).

::

$ ufs rm story.txt

The ``rm`` sub-command removes the named from from the file system on the
connected micro:bit (it's named after the common Unix command, ``rm``, that
serves the same function).

::

$ ufs put story2.txt

Finally, the ``put`` sub-command puts a file from your computer onto the
connected device (it's named after the ``put`` command that's part of FTP that
serves the same function).

Mainly main.py
++++++++++++++

The file system also has an interesting property: if you just flashed the
MicroPython runtime onto the device then when it starts it's simply waiting
for something to do. However, if you copy a special file called ``main.py``
onto the file system, upon restarting the device, MicroPython will run the
contents of the ``main.py`` file.

.. note::
If you have flashed a script onto the device in addition to the MicroPython
runtime, then MicroPython will ignore ``main.py`` and run your embedded
script instead.

To flash just the MicroPython runtime, simply make sure the script you
may have written in your editor has zero characters in it. Once flashed
you'll be able to copy over a ``main.py`` file.

.. footer:: The image of paper files is used under a Creative Commons License and is available here: https://www.flickr.com/photos/jenkim/2270085025

0 comments on commit c084920

Please sign in to comment.