diff --git a/setup.py b/setup.py
index 69d357ac4d9550b5058c0cea2e89e4c3d91cdc11..281463879025be22db3cdbda88e0f403b6d3b689 100644
--- a/setup.py
+++ b/setup.py
@@ -98,6 +98,7 @@ setup(
     ext_modules = [
       Extension("xbob.io._library",
         [
+          "xbob/io/file.cpp",
           "xbob/io/main.cpp",
           ],
         define_macros=define_macros,
diff --git a/xbob/io/file.cpp b/xbob/io/file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a57458633f0f782723949393a9fe6be8cd99ef48
--- /dev/null
+++ b/xbob/io/file.cpp
@@ -0,0 +1,211 @@
+/**
+ * @author Andre Anjos <andre.anjos@idiap.ch>
+ * @date Tue  5 Nov 11:16:09 2013
+ *
+ * @brief Bindings to bob::io::File
+ */
+
+#define XBOB_IO_MODULE
+#include <xbob.io/api.h>
+#include <bob/io/CodecRegistry.h>
+#include <bob/io/utils.h>
+#include <stdexcept>
+
+#define FILETYPE_NAME file
+PyDoc_STRVAR(s_file_str, BOOST_PP_STRINGIZE(XBOB_IO_MODULE_PREFIX) "." BOOST_PP_STRINGIZE(FILETYPE_NAME));
+
+/* How to create a new PyBobIoFileObject */
+static PyObject* PyBobIoFile_New(PyTypeObject* type, PyObject*, PyObject*) {
+
+  /* Allocates the python object itself */
+  PyBobIoFileObject* self = (PyBobIoFileObject*)type->tp_alloc(type, 0);
+
+  self->f.reset();
+
+  return reinterpret_cast<PyObject*>(self);
+}
+
+static void PyBobIoFile_Delete (PyBobIoFileObject* o) {
+
+  o->f.reset();
+  o->ob_type->tp_free((PyObject*)o);
+
+}
+
+/* The __init__(self) method */
+static int PyBobIoFile_Init(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) {
+
+  /* Parses input arguments in a single shot */
+  static const char* const_kwlist[] = {"filename", "mode", "pretend_extension", 0};
+  static char** kwlist = const_cast<char**>(const_kwlist);
+
+  char* filename = 0;
+  char* mode = 0;
+  int mode_len = 0;
+  char* pretend_extension = 0;
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|s", kwlist, &filename,
+        &mode, &mode_len, &pretend_extension)) return -1;
+
+  if (mode_len != 1 || !(mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a')) {
+    PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write) or 'a' (append)");
+    return -1;
+  }
+
+  try {
+    if (pretend_extension) {
+      self->f = bob::io::open(filename, mode[0], pretend_extension);
+    }
+    else {
+      self->f = bob::io::open(filename, mode[0]);
+    }
+  }
+  catch (std::exception& e) {
+    PyErr_Format(PyExc_RuntimeError, "cannot open file `%s' with mode `%s': %s", filename, mode, e.what());
+    return -1;
+  }
+  catch (...) {
+    PyErr_Format(PyExc_RuntimeError, "cannot open file `%s' with mode `%s': unknown exception caught", filename, mode);
+    return -1;
+  }
+
+  return 0; ///< SUCCESS
+}
+
+PyDoc_STRVAR(s_file_doc,
+"file(filename, mode, [pretend_extension]) -> new bob::io::File\n\
+\n\
+Use this object to read and write data into files.\n\
+\n\
+Constructor parameters:\n\
+\n\
+filename\n\
+  [str] The file path to the file you want to open\n\
+\n\
+mode\n\
+  [str] A single character (one of ``'r'``, ``'w'``, ``'a'``),\n\
+  indicating if you'd like to read, write or append into the file.\n\
+  If you choose ``'w'`` and the file already exists, it will be\n\
+  truncated.\n\
+\n\
+pretend_extension\n\
+  [str, optional] Normally we read the file matching the extension\n\
+  to one of the available codecs installed with the present release\n\
+  of Bob. If you set this parameter though, we will read the file\n\
+  as it had a given extension. The value should start with a ``'.'``.\n\
+  For example ``'.hdf5'``, to make the file be treated like an HDF5\n\
+  file.\n\
+\n\
+"
+);
+
+static PyObject* PyBobIoFile_Repr(PyBobIoFileObject* self) {
+  return PyUnicode_FromFormat("%s()", s_file_str);
+}
+
+PyTypeObject PyBobIoFile_Type = {
+    PyObject_HEAD_INIT(0)
+    0,                                          /*ob_size*/
+    s_file_str,                                 /*tp_name*/
+    sizeof(PyBobIoFileObject),                  /*tp_basicsize*/
+    0,                                          /*tp_itemsize*/
+    (destructor)PyBobIoFile_Delete,             /*tp_dealloc*/
+    0,                                          /*tp_print*/
+    0,                                          /*tp_getattr*/
+    0,                                          /*tp_setattr*/
+    0,                                          /*tp_compare*/
+    (reprfunc)PyBobIoFile_Repr,                 /*tp_repr*/
+    0,                                          /*tp_as_number*/
+    0,                                          /*tp_as_sequence*/
+    0,                                          /*tp_as_mapping*/
+    0,                                          /*tp_hash */
+    0,                                          /*tp_call*/
+    (reprfunc)PyBobIoFile_Repr,                 /*tp_str*/
+    0,                                          /*tp_getattro*/
+    0,                                          /*tp_setattro*/
+    0,                                          /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /*tp_flags*/
+    s_file_doc,                                 /* tp_doc */
+    0,		                                      /* tp_traverse */
+    0,		                                      /* tp_clear */
+    0,                                          /* tp_richcompare */
+    0,		                                      /* tp_weaklistoffset */
+    0,		                                      /* tp_iter */
+    0,		                                      /* tp_iternext */
+    0, //PyBobIoFile_methods,                               /* tp_methods */
+    0,                                          /* tp_members */
+    0,                                          /* tp_getset */
+    0,                                          /* tp_base */
+    0,                                          /* tp_dict */
+    0,                                          /* tp_descr_get */
+    0,                                          /* tp_descr_set */
+    0,                                          /* tp_dictoffset */
+    (initproc)PyBobIoFile_Init,                 /* tp_init */
+    0,                                          /* tp_alloc */
+    PyBobIoFile_New,                            /* tp_new */
+};
+
+/**
+static object file_read_all(bob::io::File& f) {
+  bob::python::py_array a(f.type_all());
+  f.read_all(a);
+  return a.pyobject(); //shallow copy
+}
+
+static object file_read(bob::io::File& f, size_t index) {
+  bob::python::py_array a(f.type_all());
+  f.read(a, index);
+  return a.pyobject(); //shallow copy
+}
+
+static boost::shared_ptr<bob::io::File> string_open1 (const std::string& filename,
+    const std::string& mode) {
+  return bob::io::open(filename, mode[0]);
+}
+
+static boost::shared_ptr<bob::io::File> string_open2 (const std::string& filename,
+    const std::string& mode, const std::string& pretend_extension) {
+  return bob::io::open(filename, mode[0], pretend_extension);
+}
+
+static void file_write(bob::io::File& f, object array) {
+  bob::python::py_array a(array, object());
+  f.write(a);
+}
+
+static void file_append(bob::io::File& f, object array) {
+  bob::python::py_array a(array, object());
+  f.append(a);
+}
+
+static dict extensions() {
+  typedef std::map<std::string, std::string> map_type;
+  dict retval;
+  const map_type& table = bob::io::CodecRegistry::getExtensions();
+  for (map_type::const_iterator it=table.begin(); it!=table.end(); ++it) {
+    retval[it->first] = it->second;
+  }
+  return retval;
+}
+
+void bind_io_file() {
+
+  class_<bob::io::File, boost::shared_ptr<bob::io::File>, boost::noncopyable>("File", "Abstract base class for all Array/Arrayset i/o operations", no_init)
+    .def("__init__", make_constructor(string_open1, default_call_policies(), (arg("filename"), arg("mode"))), "Opens a (supported) file for reading arrays. The mode is a **single** character which takes one of the following values: 'r' - opens the file for read-only operations; 'w' - truncates the file and open it for reading and writing; 'a' - opens the file for reading and writing w/o truncating it.")
+    .def("__init__", make_constructor(string_open2, default_call_policies(), (arg("filename"), arg("mode"), arg("pretend_extension"))), "Opens a (supported) file for reading arrays but pretends its extension is as given by the last parameter - this way you can, potentially, override the default encoder/decoder used to read and write on the file. The mode is a **single** character which takes one of the following values: 'r' - opens the file for read-only operations; 'w' - truncates the file and open it for reading and writing; 'a' - opens the file for reading and writing w/o truncating it.")
+    .add_property("filename", make_function(&bob::io::File::filename, return_value_policy<copy_const_reference>()), "The path to the file being read/written")
+    .add_property("type_all", make_function(&bob::io::File::type_all, return_value_policy<copy_const_reference>()), "Typing information to load all of the file at once")
+    .add_property("type", make_function(&bob::io::File::type, return_value_policy<copy_const_reference>()), "Typing information to load the file as an Arrayset")
+    .add_property("codec_name", make_function(&bob::io::File::name, return_value_policy<copy_const_reference>()), "Name of the File class implementation -- for compatibility reasons with the previous versions of this library")
+    .def("read", &file_read_all, (arg("self")), "Reads the whole contents of the file into a NumPy ndarray")
+    .def("write", &file_write, (arg("self"), arg("array")), "Writes an array into the file, truncating it first")
+    .def("__len__", &bob::io::File::size, (arg("self")), "Size of the file if it is supposed to be read as a set of arrays instead of performing a single read")
+    .def("read", &file_read, (arg("self"), arg("index")), "Reads a single array from the file considering it to be an arrayset list")
+    .def("__getitem__", &file_read, (arg("self"), arg("index")), "Reads a single array from the file considering it to be an arrayset list")
+    .def("append", &file_append, (arg("self"), arg("array")), "Appends an array to a file. Compatibility requirements may be enforced.")
+    ;
+
+  def("extensions", &extensions, "Returns a dictionary containing all extensions and descriptions currently stored on the global codec registry");
+
+}
+
+**/
diff --git a/xbob/io/include/xbob.io/api.h b/xbob/io/include/xbob.io/api.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d72af969cc448de5591ea47f56d6ab98a2f82b3
--- /dev/null
+++ b/xbob/io/include/xbob.io/api.h
@@ -0,0 +1,162 @@
+/**
+ * @author Andre Anjos <andre.anjos@idiap.ch>
+ * @date Tue  5 Nov 12:22:48 2013 
+ *
+ * @brief C/C++ API for bob::io
+ */
+
+#ifndef XBOB_IO_H
+#define XBOB_IO_H
+
+#include <xbob.io/config.h>
+#include <bob/io/File.h>
+#include <boost/preprocessor/stringize.hpp>
+#include <boost/shared_ptr.hpp>
+#include <Python.h>
+
+#define XBOB_IO_MODULE_PREFIX xbob.io
+#define XBOB_IO_MODULE_NAME _library
+
+/*******************
+ * C API functions *
+ *******************/
+
+/**************
+ * Versioning *
+ **************/
+
+#define PyXbobIo_APIVersion_NUM 0
+#define PyXbobIo_APIVersion_TYPE int
+
+/*****************************
+ * Bindings for xbob.io.file *
+ *****************************/
+
+/* Type definition for PyBobIoFileObject */
+typedef struct {
+  PyObject_HEAD
+
+  /* Type-specific fields go here. */
+  boost::shared_ptr<bob::io::File> f;
+
+} PyBobIoFileObject;
+
+#define PyBobIoFile_Type_NUM 1
+#define PyBobIoFile_Type_TYPE PyTypeObject
+
+/* Total number of C API pointers */
+#define PyXbobIo_API_pointers 2
+
+#ifdef XBOB_IO_MODULE
+
+  /* This section is used when compiling `xbob.core.random' itself */
+
+  /**************
+   * Versioning *
+   **************/
+
+  extern int PyXbobIo_APIVersion;
+
+  /*****************************
+   * Bindings for xbob.io.file *
+   *****************************/
+
+  extern PyBobIoFile_Type_TYPE PyBobIoFile_Type;
+
+#else
+
+  /* This section is used in modules that use `blitz.array's' C-API */
+
+/************************************************************************
+ * Macros to avoid symbol collision and allow for separate compilation. *
+ * We pig-back on symbols already defined for NumPy and apply the same  *
+ * set of rules here, creating our own API symbol names.                *
+ ************************************************************************/
+
+#  if defined(PY_ARRAY_UNIQUE_SYMBOL)
+#    define XBOB_IO_MAKE_API_NAME_INNER(a) XBOB_IO_ ## a
+#    define XBOB_IO_MAKE_API_NAME(a) XBOB_IO_MAKE_API_NAME_INNER(a)
+#    define PyBlitzArray_API XBOB_IO_MAKE_API_NAME(PY_ARRAY_UNIQUE_SYMBOL)
+#  endif
+
+#  if defined(NO_IMPORT_ARRAY)
+  extern void **PyXbobIo_API;
+#  else
+#    if defined(PY_ARRAY_UNIQUE_SYMBOL)
+  void **PyXbobIo_API;
+#    else
+  static void **PyXbobIo_API=NULL;
+#    endif
+#  endif
+
+  static void **PyXbobIo_API;
+
+  /**************
+   * Versioning *
+   **************/
+
+# define PyXbobIo_APIVersion (*(PyXbobIo_APIVersion_TYPE *)PyXbobIo_API[PyXbobIo_APIVersion_NUM])
+
+  /*****************************
+   * Bindings for xbob.io.file *
+   *****************************/
+
+# define PyBobIoFile_Type (*(PyBobIoFile_Type_TYPE *)PyXbobIo_API[PyBobIoFile_Type_NUM])
+
+  /**
+   * Returns -1 on error, 0 on success. PyCapsule_Import will set an exception
+   * if there's an error.
+   */
+  static int import_xbob_io(void) {
+
+#if PY_VERSION_HEX >= 0x02070000
+
+    /* New Python API support for library loading */
+
+    PyXbobIo_API = (void **)PyCapsule_Import(BOOST_PP_STRINGIZE(XBOB_IO_MODULE_PREFIX) "." BOOST_PP_STRINGIZE(XBOB_IO_MODULE_NAME) "._C_API", 0);
+
+    if (!PyXbobIo_API) return -1;
+
+#else
+
+    /* Old-style Python API support for library loading */
+
+    PyObject *c_api_object;
+    PyObject *module;
+
+    module = PyImport_ImportModule(BOOST_PP_STRINGIZE(XBOB_IO_MODULE_PREFIX) "." BOOST_PP_STRINGIZE(XBOB_IO_MODULE_NAME));
+
+    if (module == NULL) return -1;
+
+    c_api_object = PyObject_GetAttrString(module, "_C_API");
+
+    if (c_api_object == NULL) {
+      Py_DECREF(module);
+      return -1;
+    }
+
+    if (PyCObject_Check(c_api_object)) {
+      PyXbobIo_API = (void **)PyCObject_AsVoidPtr(c_api_object);
+    }
+
+    Py_DECREF(c_api_object);
+    Py_DECREF(module);
+
+#endif
+    
+    /* Checks that the imported version matches the compiled version */
+    int imported_version = *(int*)PyXbobIo_API[PyIo_APIVersion_NUM];
+
+    if (XBOB_IO_API_VERSION != imported_version) {
+      PyErr_Format(PyExc_RuntimeError, "%s.%s import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOOST_PP_STRINGIZE(XBOB_IO_MODULE_PREFIX), BOOST_PP_STRINGIZE(XBOB_IO_MODULE_NAME), XBOB_IO_API_VERSION, imported_version);
+      return -1;
+    }
+
+    /* If you get to this point, all is good */
+    return 0;
+
+  }
+
+#endif /* XBOB_IO_MODULE */
+
+#endif /* XBOB_IO_H */
diff --git a/xbob/io/main.cpp b/xbob/io/main.cpp
index 7526754b43469e774915b69c7d9a77166d36032d..3822dd9109cd859137631aa10af7dfff2c5b22a0 100644
--- a/xbob/io/main.cpp
+++ b/xbob/io/main.cpp
@@ -6,11 +6,7 @@
  */
 
 #define XBOB_IO_MODULE
-#include <xbob.io/config.h>
-#include <boost/preprocessor/stringize.hpp>
-
-#define XBOB_IO_MODULE_PREFIX xbob.io
-#define XBOB_IO_MODULE_NAME _library
+#include <xbob.io/api.h>
 
 #ifdef NO_IMPORT_ARRAY
 #undef NO_IMPORT_ARRAY
@@ -23,11 +19,16 @@ static PyMethodDef module_methods[] = {
 
 PyDoc_STRVAR(module_docstr, "bob::io classes and methods");
 
+int PyXbobIo_APIVersion = XBOB_IO_API_VERSION;
+
 #define ENTRY_FUNCTION_INNER(a) init ## a
 #define ENTRY_FUNCTION(a) ENTRY_FUNCTION_INNER(a)
 
 PyMODINIT_FUNC ENTRY_FUNCTION(XBOB_IO_MODULE_NAME) (void) {
 
+  PyBobIoFile_Type.tp_new = PyType_GenericNew;
+  if (PyType_Ready(&PyBobIoFile_Type) < 0) return;
+
   PyObject* m = Py_InitModule3(BOOST_PP_STRINGIZE(XBOB_IO_MODULE_NAME),
       module_methods, module_docstr);
 
@@ -35,6 +36,21 @@ PyMODINIT_FUNC ENTRY_FUNCTION(XBOB_IO_MODULE_NAME) (void) {
   PyModule_AddIntConstant(m, "__api_version__", XBOB_IO_API_VERSION);
   PyModule_AddStringConstant(m, "__version__", BOOST_PP_STRINGIZE(XBOB_IO_VERSION));
 
+  /* register the types to python */
+  Py_INCREF(&PyBobIoFile_Type);
+  PyModule_AddObject(m, "file", (PyObject *)&PyBobIoFile_Type);
+
+  static void* PyXbobIo_API[PyXbobIo_API_pointers];
+
+  /* exhaustive list of C APIs */
+  PyXbobIo_API[PyXbobIo_APIVersion_NUM] = (void *)&PyXbobIo_APIVersion;
+
+  /*****************************
+   * Bindings for xbob.io.file *
+   *****************************/
+
+  PyXbobIo_API[PyBobIoFile_Type_NUM] = (void *)&PyBobIoFile_Type;
+
   /* imports the NumPy C-API */
   import_array();