2.2. Opening Files

The simplest way to open a file is to pass a file name to the constructor of either tutorial::File_Database or tutorial::Readonly_Database.

tutorial::File_Database db("file.joedb");
tutorial::Readonly_Database db("file.joedb");

2.2.1. joedb::Open_Mode

You can change the way the file is opened by passing an extra parameter to the constructor of tutorial::File_Database. Available modes are:

#ifndef joedb_Open_Mode_declared
#define joedb_Open_Mode_declared

namespace joedb
{
 /// @ingroup journal
 enum class Open_Mode
 {
  read_existing,                ///< fails if does not exist
  write_existing,               ///< fails if does not exist or locked, locks the file for writing
  create_new,                   ///< fails if already exists, locks the file for writing
  write_existing_or_create_new, ///< either write_existing or create_new depending on whether the file exists. Racy in Posix, not in Windows.
  shared_write,                 ///< like write_existing_or_create_new, but does not lock the file, and does not fail if locked
  write_lock,                   ///< like write_existing_or_create_new, but waits instead of failing if already locked
  mode_count                    ///< number of modes
 };
}

#endif

shared_write is dangerous, and requires synchronization. Users of the library should not directly manipulate files with this mode, and instead use transactions. Other write modes will use file locking to prevent more than one process from writing to the same file simultaneously. write_lock is like write_existing_or_create_new, but waits instead of failing if anybody else is already write-locking.

For example:

#include "tutorial/File_Database.h"
#include "tutorial/Readonly_Database.h"

#include "joedb/ui/main_exception_catcher.h"

/////////////////////////////////////////////////////////////////////////////
static int file_tutorial_main(int argc, char **argv)
/////////////////////////////////////////////////////////////////////////////
{
 const char * const file_name = "file_tutorial.joedb";

 //
 // Create a new database and write something
 // (If a file already exists, it will fail)
 //
 {
  tutorial::File_Database db(file_name, joedb::Open_Mode::create_new);
  db.new_city("Villeneuve d'Ascq");
  db.soft_checkpoint();
 }

 //
 // Re-open the database and add one more city
 // (If the file does not exist, it will fail)
 //
 {
  tutorial::File_Database db(file_name, joedb::Open_Mode::write_existing);
  db.new_city("Tombouctou");
  db.soft_checkpoint();
 }

 //
 // Open the database read-only
 //
 {
  tutorial::Readonly_Database db(file_name);
  for (const auto city: db.get_city_table())
   std::cout << db.get_name(city) << '\n';
 }

 return 0;
}

/////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
/////////////////////////////////////////////////////////////////////////////
{
 return joedb::main_exception_catcher(file_tutorial_main, argc, argv);
}

2.2.2. tutorial::File_Client

Writes to a tutorial::File_Database must be manually checkpointed, which is not very convenient. You can avoid having to explicitly checkpoint your writes by using transactions with a tutorial::File_Client instead.

2.2.3. Buffered_File

tutorial::File_Database is a shortcut that allows opening a database directly with a file name. Its more generic superclass tutorial::Writable_Database can access data stored in the various specializations of the Buffered_File class. tutorial::Readonly_Database can also take a read-only Buffered_File as constructor parameter.

Here are some specializations of Buffered_File:

You can also create your own file class by subclassing Buffered_File and implementing the virtual functions of the Abstract_File superclass.