Boost logo

Boost :

Subject: [boost] [iostreams] detecting io errors
From: Johan Grafstrom (grafoid_at_[hidden])
Date: 2009-02-27 05:44:56


Hello,

I use boost:iostreams for reading and writing a binary data
format. There is currently no use of filters, but the reason for using
boost was to try using compression by adding a filter.

I have run into some problems/questions regarding the
boost:iostreams::stream class though, and was hoping that someone here
might give me a hint.

The files I save is project files, and the users use a versioning system
to lock the files while editing. Occasionally they forget to lock and
would get an error when trying to save, since the files in write
protected unless locked.

My first (and worst) problem was that i did not get any error at all
when the write failed, I found out that this was my own fault since I
used:

   bio::stream<bio::file_sink> outs(tstFileName,
                                    std::ios_base::out);
   // ... write etc...
   if (outs.is_open())
     // error ...

instead of

   if (outs->is_open())
     // ^^ '->', not '.' must be used here
     // error ...

but it seem like an easy pitfall for newbies like me. A different method
name or at least a warning in the documentation maybe?

The second problem is that I cannot find any way to get information on
the nature of the write error. E g is it an access permission problem or
a hardware error?

The third problem is that seem to be no way to detect an error when
closing the file. I have attached a short c-file to illustrate what I
would want to know. I pause and remove the USB-stick with the open file
before closing. c-runtime streams will give me error on close, but I
cant get the same information out of boost::iostreams.

Any help, directions or opinions would be appreciated.

Best regards,

   Johan Grafström


/* -*- mode: C++; coding: utf-8-dos; -*- */
/* ==========================================================================
 * boost_test2.cpp
 *
 * Problems:
 *
 * * Boost only reports false for outs->is_open() after error but gives no
 * details (write failure, invalid handle, access violation)
 *
 * * An error on file close cannot be detected
 *
 * * The worst problem was my own:
 * using outs.is_open() (always returns true)
 * instead of outs->is_open() returns false after error
 *
 * ========================================================================== */

#include <stdio.h>
#include <conio.h>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>

void boostWriteTestFile();
void streamsWriteTestFile();
void userInteract();

namespace bio = boost::iostreams;

char tstFileName[] = "write_test.txt";

int main(int argc, char *argv[])
{
  // DebugBreak();

  if (argc == 2 && strcmp(argv[1],"streams") == 0) {
    printf("Write using c-runtime stream i/o\n");
    streamsWriteTestFile();
  }
  else {
    printf("Write using boost:iostreams\n");
    boostWriteTestFile();
  }

  return 0;
}

void boostWriteTestFile()
{
  char streamText[] = "Written by boost iostreams api\n";
  int msgSize = strlen(streamText);

  // write using boost
  bio::stream<bio::file_sink> outs(tstFileName,
                                   std::ios_base::out | std::ios_base::binary);

  int bytesWritten = outs->write(streamText, msgSize);
  
  if (bytesWritten != msgSize)
    printf("Error boost writing\n");

  if (!outs->is_open())
    printf("Error boost file closed\n");

  userInteract();

  // Problem: how to get error status from outs.close() ??
  // returns void
  // in boost/iostreams/device/file.hpp:175
  // template<typename Ch>
  // void basic_file<Ch>::close() { pimpl_->file_.close(); }
  // returns void thus ignoring the return value from
  // basic_filebuf.close() in c++ runtime <fstream>

  outs.close();
}

void streamsWriteTestFile()
{
  char streamText[] = "Written by c-runtume streams api\n";
  int msgSize = strlen(streamText);

  // write using c-runtime streams
  FILE *fh = fopen(tstFileName, "w");
  if (fh == NULL) {
    perror("on fopen()");
    return;
  }

  size_t countWritten = fwrite(
      streamText, // const void *buffer,
      1, // size_t size,
      msgSize, // size_t count,
      fh // FILE *stream
      );
  
  if (countWritten != msgSize) {
    perror("On fwrite()");
    return;
  }
  
  userInteract();

  int status = fclose(fh);
  if (status == 0) {
    // ok
  }
  else {
    // status == EOF
    perror("on fclose()");
    return;
  }
}

void userInteract()
{
  printf("Please remove the file %s, in some apropriate manner e g \n"
         "remove the floppy or usb-drive, delete with Unlocker or equivalent.\n"
         "Then press any key to continue.\n",
         tstFileName);
  _getch();
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk