创建自定义std :: streambuf

时间:2015-06-15 19:23:41

标签: c++ file-io stl

我正在定义一个用于文件I / O的自定义std::streambuf类。在本课程中,我正在重载函数opencloseis_openxsgetnxsputnoverflowunderflowuflow。然后我将此缓冲区插入到std::ifstream中,如下所示(同样的情况适用于std::ofstream):

std::ifstream temp;
Filebuffer *buffer = new Filebuffer();
buffer->open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
temp.basic_ios<char>::rdbuf(buffer);

Filebuffer(我的自定义类)的实现如下:

std::streamsize
Filebuffer::xsputn(const char *s, std::streamsize n)
{
  std::streamsize result = 0;

  if(file && n)
  {
    for(;;)
    {
      size_t buffer_use = this->epptr() - this->pptr();

      if(buffer_use > 0)
      {
        if(static_cast<int>(buffer_use) > n)
        {
          buffer_use = n;
        }

        std::char_traits<char>::copy(this->pptr(), s, buffer_use);

        this->pbump(buffer_use);
        result += buffer_use;
        n -= buffer_use;

        if(n == 0)
        {
          break;
        }

        s += buffer_use;
      }

      this->overflow(static_cast<int>(*s));
    }
  }

  return result;
}

std::streamsize
Filebuffer::xsgetn(char *s, std::streamsize n)
{
  std::streamsize result = 0;

  if(file && n)
  {
    int ch;    do
    {
      size_t buffer_use = this->egptr() - this->gptr();

      if(buffer_use > 0)
      {
        if(static_cast<int>(buffer_use) > n)
        {
          buffer_use = n;
        }

        std::char_traits<char>::copy(s, this->gptr(), buffer_use);

        this->gbump(buffer_use);
        result += buffer_use;
        n -= buffer_use;

        if(n == 0)
        {
          break;
        }

        s += buffer_use;
      }

      ch = this->underflow();
    } while(!(ch == std::char_traits<char>::eof()));
  }

  return result;
}

int
Filebuffer::underflow()
{
  if(file)
  {
    nullify_put_area(); //clears write buffer

    if(!buffer) //allocated in open()
    {
      int value = ungetc(fgetc(file), file);

      if(value == EOF)
      {
        return std::char_traits<char>::eof();
      }

      return value;
    }

    char *begin = buffer;
    char *end = buffer + bufferSize - 1; //bufferSize set to 4 KB
    char *next = end;

    if(this->gptr() < this->egptr())
    {
      size_t buffer_use = this->egptr() - this->gptr();

      memmove(begin, next, buffer_use);
      begin += buffer_use;
    }

    setg(begin, begin, begin);


    size_t m = (bufferSize - 1 - (begin - this->eback()));

    if(m > 0)
    {
      size_t status = fread(begin, 1, m, file);

      if(status == 0)
      {
        return std::char_traits<char>::eof();
      }

      setg(this->eback(), this->gptr(), begin + status);
    }

    return static_cast<int>(*this->gptr());
  }

  return std::char_traits<char>::eof();
}

int
Filebuffer::uflow()
{
  if(!file)
  {
    return std::char_traits<char>::eof();
  }

  int ch = underflow();

  if(ch != std::char_traits<char>::eof())
  {
    if(buffer)
    {
      this->gbump(1);
    }

    else
    {
      fgetc(file);
    }
  }

  return ch;
}

int
Filebuffer::overflow(int c)
{
  if(!file)
  {
    return std::char_traits<char>::eof();
  }

  const char *begin = this->pbase();
  char *next = this->pptr();

  if(buffer)
  {
    setp(buffer, buffer + bufferSize - 1);
  }

  nullify_get_area(); //clears read buffer

  char temp;
  if(c == std::char_traits<char>::eof())
  {
    c = std::char_traits<char>::not_eof(std::char_traits<char>::eof());
  }

  else
  {
    if(!next)
    {
      begin = next = &temp;
    }

    assert(next == &temp || buffer <= next);
    assert(next == &temp || next < buffer + bufferSize);
    *next++ = static_cast<char>(c);
  }

  if(begin != next)
  {
    if(begin == &temp)
    {
      fputc(temp, file);
      return c;
    }

    size_t n = next - begin;
    size_t status = fwrite(begin, 1, n, file);

    if(status != n)
    {
      return std::char_traits<char>::eof();
    }

    return c;
  }

  return std::char_traits<char>::eof();
}

不幸的是,每当我使用(例如)temp >> readVar;时,它都不会使用我的任何重载函数 - 调用堆栈显示调用了STL原始实现 - 而只是简单地读取垃圾。根据{{​​3}},我需要为overflow定义ofstream(可能是underflow ifstream),我已经完成了。我是否正确定义了xsputnxsgetn?为什么我的重载函数没有被调用?

1 个答案:

答案 0 :(得分:1)

似乎尝试使用std::ifstream执行此操作无效,我需要更改std::istream。一旦我做了这个改变,就会调用重载的函数,一切正常。