From 1923eae1e3047f76dbe4f3513011ff39aaf5bc78 Mon Sep 17 00:00:00 2001 From: Eugen Wintersberger Date: Wed, 1 Nov 2017 13:32:17 +0100 Subject: [PATCH] Updated users guide on files Update #110 --- doc/source/users_guide/CMakeLists.txt | 3 +- doc/source/users_guide/files.rst | 236 ++++++++++++++++---------- doc/source/users_guide/index.rst | 3 +- 3 files changed, 152 insertions(+), 90 deletions(-) diff --git a/doc/source/users_guide/CMakeLists.txt b/doc/source/users_guide/CMakeLists.txt index efcc078a18..ce1d1582e8 100644 --- a/doc/source/users_guide/CMakeLists.txt +++ b/doc/source/users_guide/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES index.rst - using.rst) + using.rst + files.rst) add_sphinx_source(${SOURCES}) copy_to_current_build(${SOURCES}) diff --git a/doc/source/users_guide/files.rst b/doc/source/users_guide/files.rst index 8b02c74bcf..2dfe63b909 100644 --- a/doc/source/users_guide/files.rst +++ b/doc/source/users_guide/files.rst @@ -8,128 +8,188 @@ Working with files .. todo:: How do we deal with the meta-data cache? - -Open and create files -===================== + +The first things you have to do when using HDF5 is to create a new file or +open an already existing one. This chapter deals with this very basic topic. +Unlike in the C-API filenames are not represented by mere strings but by +instances of :cpp:class:`boost::filesystem::path`. This avoids problems +when using different seperator characters in a path on different platforms. +Additionally a file system path has a particular semantic which is not +reflecetd by a simple string. + +Identifying an HDF5 file +======================== + +Before opening an HDF5 file we should check whether or not the object +referenced by :cpp:class:`boost::filesystem::path` is indeed an HDF5 file. +The simpliest way to achieve this goal is to use the +:cpp:func:`hdf5::file::is_hdf5_file` utiltiy function function. .. code-block:: cpp - using namespace fs = boost::filesystem; - //creating a new file - fs::path file_path("name.h5"); - h5::file_t f1 = h5::file_t::create(file_path, - h5::file_t::flag_t::TRUNCATE, - file_creation_plist(), - file_access_plist()); - - //opening an existing file - h5::file_t f2 = h5::file_t::open(file_path, - h5::file_t::flag_t::READ_WRITE, - file_access_plist()); - -Unlike in the C-API an instance of :cpp:class:`h5::file_t` is not a valid parent object. -For this purpose the root group of the file must be obtained using the -:cpp:func:`root()` method of a file instance + boost::filesystem::path file_path = ...; + + if(!hdf5::file::is_hdf5_file(file_path)) + { + //deal with the error situation + } + + //continue with opening the file -.. code-block:: cpp +Creating files +============== - h5::group_t root_group = f.root(); +The first thing one may wants to do is to create a new file. Use the +:cpp:func:`hdf5::file::create` function -.. admonition:: Rational +.. code-block:: cpp - Though in the C-API the ID of a group and a file can both act as valid - parent object, this approach does not run well with an object oriented - appraoch. It would mean that :cpp:class:`file_t` and :cpp:class:`group_t` - would have to provide a common, group-like interface. + #include + #include - In order to avoid code duplications we :cpp:class:`file_t` would have to - derive from :cpp:class:`group_t` making it also a valid group object. From - the point of semantics this is simply wrong. A file is not a group. + using namespace hdf5; + using namespace fs = boost::filesystem; - Though the approach choosen here requires a single line of code more to - obtain the root group of a file before doing any useful work on the file, - however, I think a clean difference between :cpp:class:`file_t` and - :cpp:class:`group_t` is worth the additional effort. + int main() + { + //creating a new file + fs::path file_path("data.h5"); + file::File f1 = file::create(file_path); -Methods -======= + //do something with the file + } + +By default, the :cpp:func:`hdf5::file::create` function will throw an +exception if the file already exists. To overwrite an already existing file +use -.. cpp:class:: file_t +.. code-block:: cpp - .. cpp:enum-struct:: flag_t : uint8_t + file::File f1 = file::create(file_path,file::AccessFlags::TRUNCATE); + +HDF5 uses property lists to pass additional information to API functions. +The :cpp:func:`hdf5::file::create` function accepts two additional arguments +* a reference to a file creation property list + (:cpp:class:`hdf5::property::FileCreateList`) +* and a reference to a file access property list + (:cpp:class:`hdf5::property::FileAccessList`) + +There are several situations when you have to use these property lists to +create a file. The most common might be - .. cpp:function:: public boost::filesystem_path path() const - - Return the file system path for this instance of :cpp:class:`file_t`. +* you want better control over object and link iteration +* you want to use the SWMR feature introduced with HDF5 1.10. +We will deal with the iterator problem a bit later. For now we have a look +on the SWMR feature. Provided you link *h5cpp* against HDF5 1.10.0 or higher +you have to provide a custom file access property list - .. cpp:function:: public void flush() const +.. code-block:: cpp - Flush data to the file. + property::FileCreationList fcpl; //can use the default here + property::FileAccessList fapl; + + //we need to set the appropriate version flags + fapl.library_version_bounds(property::LibVersion::LATEST, + property::LibVersion::LATEST); + + file::File f = file::create("swmr_file.h5", + file::AccessFlags::TRUNCATE, + fcpl,fapl); + + +Opening an existing file +======================== + +To open a file use the :cpp:func:`hdf5::file::open` function - .. cpp:function:: public flag_t mode() const +.. code-block:: cpp - Return the current mode the file is opened. + #include + #include - .. cpp:function:: public group_t root() const + using namespace hdf5; + using namespace fs = boost::filesystem; + + int main() + { + //creating a new file + fs::path file_path("data.h5"); + file::File f1 = file::open(file_path); - Return the root group of the file as an instance of - :cpp:class:`group_t`. + //do something with the file + } + +By default, files are opened in read only mode to avoid accidental modification +of the file. To write to an existing file use +.. code-block:: cpp + file::File f1 = file::open(file_path,file::AccessFlags::READWRITE); + +The only additional argument :cpp:func:`hdf5::file::open` takes is a +reference to file access property list. We have to use this to open a file +for SWMR access. However, in addition we need some custom flags to use +SWMR. To open a file for writing in SWMR mode use -Flags -===== +.. code-block:: cpp -The :cpp:class:`file_t` class has a nested scoped enumeration type -:cpp:enum:`file_t::flags` with flags used to open and create files as well as -to denote the status of a file. + property::FileAccessList fapl; + //we need to set the appropriate version flags + fapl.library_version_bounds(property::LibVersion::LATEST, + property::LibVersion::LATEST); + + file::File write_fiel = file::open(file_path, + file::AccessFlags::READWRITE | + file::AccessFlags::SWMR_WRITE, + fapl); + +and to open a file for reading in SWMR mode use -+----------------------------------------------+------------------------------+ -| Flag | Description | -+==============================================+==============================+ -| :cpp:enumerator:`file_t::flag_t::TRUNCATE` | overwrite an already existing| -| | file during file creation! | -+----------------------------------------------+------------------------------+ -| :cpp:enumerator:`file_t::flag_t::EXCL` | file creation will fail if a | -| | file of equal name already | -| | exists | -+----------------------------------------------+------------------------------+ -| :cpp:enumerator:`file_t::flag_t::READ_WRITE` | open a file for read write | -| | access or the file is in | -| | read write mode | -+----------------------------------------------+------------------------------+ -| :cpp:enumerator:`file_t::flag_t::READ_ONLY` | open a file in read only mode| -| | or the file is in read only | -| | mode | -+----------------------------------------------+------------------------------+ -| :cpp:enumerator:`file_t::flag_t::SWMR_WRITE` | open the file in SWMR write | -| | mode or the file is in SWMR | -| | write mode | -+----------------------------------------------+------------------------------+ -| :cpp:enumerator:`file_t::flag_t::SWMR_READ` | open a file in SWMR read mode| -| | or the file is in SWMR read | -| | mode. | -+----------------------------------------------+------------------------------+ +.. code-block:: cpp + property::FileAccessList fapl; + //we need to set the appropriate version flags + fapl.library_version_bounds(property::LibVersion::LATEST, + property::LibVersion::LATEST); + + file::File write_fiel = file::open(file_path, + file::AccessFlags::READONLY | + file::AccessFlags::SWMR_READ, + fapl); -Utility types and functions -=========================== +Getting access to the object tree +================================= -The function :cpp:func:`is_hdf5_file` checks whether or not a file system path -points to an HDF5 file or not. +Unlike in the C-API an instance of :cpp:class:`hdf5::File` is not a valid +parent object. For this purpose the root group of the file must be obtained +using the :cpp:func:`File::root()` method of a file instance .. code-block:: cpp - boost::filesystem::path file_path = ...; + hdf5::file::File f = ....; + hdf5::node::Group root_group = f.root(); - if(!h5::is_hdf5_file(file_path)) - { - std::cerr<<"Some error message!"<