Recently I ported Exaile’s Files panel to use GIO instead of Python’s os
module. The reason is simple: remote browsing.
Yes, you can now browse an SMB share or an SFTP server through the Files panel. Just mount the remote filesystem with gvfs-mount
and enter the URL into the location bar. Previously Aren ported Exaile’s core to GIO as well, so remote files can be played just fine.
This is the kind of convenience you get out of using GIO/GVFS. In this article I’ll briefly explain what GIO is and how to do some basic file operations—similar to what the Files panel does—using GIO.
Note: This article is part of my ongoing GIO tutorial series, which currently consists of: (1) File and path operations (this document); (2) File IO; and (3) Launching files.
What is GIO? GVFS? GnomeVFS?
GIO is an input/output framework. It provides a bunch of functionalities related to files, directories, removable media, networks, and other stuff that fall under the IO category. This article’s focus—file operations—is just one of its features.
GVFS complements GIO by letting it access remote/virtual filesystems (the VFS part of the name).
GnomeVFS is an older technology that GIO and GVFS together replace.
GIO is distributed as part of GLib, while GVFS sits in a separate package. GnomeVFS was part of GNOME and is being phased out.
GFile, the bread and butter of file operations
This is the file class in GIO. By itself GFile represents nothing more than a URI, but it lets you do all sorts of operations on a file or directory. Here’s a simple example:
>>> import gio >>> f = gio.File('.') >>> f.get_uri() file:///home/user >>> f.get_path() /home/user >>> f.delete() Traceback (most recent call last): ... gio.Error: Error removing file: Directory not empty
Check the documentation (C reference, Python reference) to see other operations you can do with GFile.
GFileInfo
GFileInfo represents various properties of a file or stream, such as size, permissions, etc. To obtain the GFileInfo of a file, call GFile’s query_info
method.
>>> f = gio.File('.') >>> info = f.query_info('standard::type,standard::size') >>> info.get_file_type() <enum G_FILE_TYPE_DIRECTORY of type GFileType> >>> info.get_size() 0L
query_info
requires a list of attributes that you want to retrieve. Only the specified attributes are then populated into the GFileInfo. Multiple attributes can be queried by separating them with commas. Wildcards in the form of *
and namespace::*
are also accepted.
In this example, we query the file type and size (by the way, the size is always 0 for directories). The results are stored in the returned GFileInfo.
To retrieve a value from GFileInfo, call its get_attribute_*
methods (e.g. get_attribute_uint32("standard::type")
). Some attributes have special getters (e.g. get_file_type
).
A complete list of file attributes is available. The various attribute getter methods are detailed in the GFileInfo documentation (C reference, Python reference).
Example: getting parent directory
This is just a very simple example showing how to get the parent of a directory.
import gio current = gio.File('.') parent = current.get_parent()
Example: getting contents of a directory
This example shows the meat of the Files panel: displaying the subdirectories and files inside a directory. For each file, we also obtain its size.
import gio current = gio.File('.') subdirs = [] files = [] infos = current.enumerate_children( 'standard::name,standard::type,standard::size') for info in infos: child = current.get_child(info.get_name()) if info.get_file_type() == gio.FILE_TYPE_DIRECTORY: subdirs.append(child) else: files.append((child, info.get_size()))
Notice that enumerate_children
works similarly to query_info
, but it retrieves the properties of all the children of a directory.
What else?
That’s it, we’ve covered everything essential for a file browser. The Files panel just builds a GUI and a history feature on top.
I’ve written a small demonstration of a working GIO file browser; try giving it a remote location to browse (don’t forget to gvfs-mount
the filesystem first).
Great tutorial – very helpful. Thanks!
This is cool, how about if I want to open a zip (.jar) file and enumerate it’s children?
Heres what I tried:
That’s quite tricky; I don’t think GIO/GVFS supports opening zipped files as directories per se. What you can do is mount the zip file with GIO, and then access the file as if you’re accessing a remote GIO mount.
I’ll give it a try later. Might actually be a good topic for another post if I can get it working.
Nice Demonstration 🙂
Pingback: Mount berkas arsip dengan GIO « Dari Tiada Ke Tiada
Hi, I am trying to remove an attribute (“metadata::emblems”) using the call
mydir=gio.File("./tmp")
mydir.set_attribute("metadata::emblems", gio.FILE_ATTRIBUTE_TYPE_STRINGV, ["new", "hot"])
and it works. The problem is that I cannot find how to unset it. In the C call g_file_set_attribute you pass a NULL as the value, but in the python version I can’t pass a None vale. And if I pass an empty array the attribute is set to the empty array… Have you any hint? Thanks!
This does seem to be a PyGTK oversight—I can’t find a way to do it either. But the bigger problem is that unsetting an attribute is not documented even in the GIO docs.
You may want to file bug reports on both GLib and PyGTK. (And if you do, please share the links here.)
In the meantime, you can work around this by running
gvfs-set-attribute -t unset path metadata::emblems
or using ctypes.I l-traced the gvfs-set-attribute command, and it seems that to remove the attribute (from C) you simply call the set_attribute() function passing a NULL pointer.
Unfortunately, it does not work in Python, because it refuses a “None” argument. I do not know how to use ctype… I sent a message to the pygtk-python-hacker list (awaiting moderation because I am not a subscriber).
If I solve something, I’ll post here. Spawning gvfs-set-attribute is a solution, but I need to spawn a process (I was trying to write a tool to keep emblems synchronized between teo rsync-ed trees), and it is not… elegant.