首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >读写数据的DataStream接口

读写数据的DataStream接口
EN

Code Review用户
提问于 2015-07-31 16:54:21
回答 2查看 2.4K关注 0票数 2

我正在编写一个C++库,它将对文件、内存缓冲区和使用HTTP访问的远程文件进行交互。

为了处理这个问题,我决定创建一些使用以下接口的类:

DataStreamInterface.h

代码语言:javascript
复制
class DataStreamInterface {
 public:
  virtual bool open() = 0;
  virtual void close() = 0;
  virtual std::streamsize length() const = 0;
  virtual std::streamsize tell() const = 0;
  virtual std::streamsize seek(std::streamsize position) = 0;
  virtual std::streamsize read(char *buffer,
                               std::streamsize length) = 0;
  virtual std::streamsize read(int8_t *buffer) = 0;
  virtual std::streamsize read(uint8_t *buffer) = 0;
  virtual std::streamsize read(int16_t *buffer) = 0;
  virtual std::streamsize read(uint16_t *buffer) = 0;
  virtual std::streamsize read(int32_t *buffer) = 0;
  virtual std::streamsize read(uint32_t *buffer) = 0;
  virtual std::streamsize read(float *buffer) = 0;
  virtual std::streamsize read(double *buffer) = 0;
  virtual std::streamsize read(std::string *buffer) = 0;
  virtual std::streamsize peek(uint8_t *buffer,
                               std::streamsize length) = 0;
  virtual std::streamsize peek(int8_t *buffer) = 0;
  virtual std::streamsize peek(uint8_t *buffer) = 0;
  virtual std::streamsize peek(int16_t *buffer) = 0;
  virtual std::streamsize peek(uint16_t *buffer) = 0;
  virtual std::streamsize peek(int32_t *buffer) = 0;
  virtual std::streamsize peek(uint32_t *buffer) = 0;
  virtual std::streamsize peek(float *buffer) = 0;
  virtual std::streamsize peek(double *buffer) = 0;
  virtual std::streamsize peek(std::string *buffer) = 0;
  virtual std::streamsize write(const char *buffer,
                                std::streamsize length) = 0;
  virtual std::streamsize write(int8_t value) = 0;
  virtual std::streamsize write(uint8_t value) = 0;
  virtual std::streamsize write(int16_t value) = 0;
  virtual std::streamsize write(uint16_t value) = 0;
  virtual std::streamsize write(int32_t value) = 0;
  virtual std::streamsize write(uint32_t value) = 0;
  virtual std::streamsize write(float value) = 0;
  virtual std::streamsize write(double value) = 0;
  virtual std::streamsize write(const std::string &value) = 0;

  virtual ~DataStreamInterface() { }
};

然后,我创建了用于在MemoryDataStream d缓冲区中读写的malloc、用于读写文件的FileDataStream和用于读取远程文件的HttpDataStream

MemoryDataStream.cc

代码语言:javascript
复制
MemoryDataStream::MemoryDataStream(const DataStreamInit &dsInit) :
  _bigEndian(dsInit.bigEndian) {
}

MemoryDataStream::~MemoryDataStream() {
  this->_buffer.clear();
}

bool MemoryDataStream::open() {
  return true;
}

void MemoryDataStream::close() {
}

std::streamsize MemoryDataStream::length() const {
  return this->_buffer.size();
}

std::streamsize MemoryDataStream::seek(std::streamsize position) {
  if (position < 0 ||
      static_cast<std::streamsize>(this->_cursor) +
      position > this->_buffer.size()) {
    return -1;
  }
  this->_cursor = position;
  return this->_cursor;
}

std::streamsize MemoryDataStream::tell() const {
  return this->_cursor;
}

std::streamsize MemoryDataStream::read(char *buffer,
                                       std::streamsize length) {
  std::streamsize result = 0;

  for (int i = 0; i < length; i++) {
    result += this->_read(buffer++);
  }

  return result;
}

std::streamsize MemoryDataStream::read(int8_t *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(uint8_t *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(int16_t *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(uint16_t *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(int32_t *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(uint32_t *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(float *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(double *buffer) {
  return this->_read(buffer);
}

std::streamsize MemoryDataStream::read(std::string *buffer) {
  std::streamsize i;
  std::string result;

  i = this->peek(&result);
  if (i < 1) {
    return i;
  }

  *buffer = result;
  this->_cursor += i;
  return i;
}

template <typename T>
std::streamsize MemoryDataStream::_read(T *buffer) {
  std::streamsize result = this->_peek(buffer);

  if (result > 0) {
    this->_cursor += result;
  }
  return result;
}

std::streamsize MemoryDataStream::peek(uint8_t *buffer,
                                       std::streamsize length) {
  std::streamsize result = 0;

  for (int i = 0; i < length; i++) {
    result += this->_peek(buffer++);
  }
  return result;
}

std::streamsize MemoryDataStream::peek(int8_t *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(uint8_t *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(int16_t *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(uint16_t *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(int32_t *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(uint32_t *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(float *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(double *buffer) {
  return this->_peek(buffer);
}

std::streamsize MemoryDataStream::peek(std::string *value) {
  int8_t c;
  std::streamsize i;
  int size;
  std::stringstream strm;

  for (i = 0; i < 32768; ++i) {
    if (this->_peek(&c) < 1 || c == '\0') {
      break;
    } else {
      this->_cursor += 1;
    }
    size = i;
    strm << c;
  }

  *value = strm.str();
  this->_cursor -= size;
  return i;
}

template <typename T>
std::streamsize MemoryDataStream::_peek(T *buffer) {
  T value;
  T finalValue;
  uint8_t *originalData;
  uint8_t *finalData;
  std::streamsize size = static_cast<std::streamsize>(sizeof(T));

  if (static_cast<std::streamsize>(this->_cursor) +
      size > this->_buffer.size()) {
    return -1;
  }

  value = *(reinterpret_cast<T*>(&this->_buffer[this->_cursor]));
  if (_bigEndian && sizeof(T) > 1) {
    originalData = reinterpret_cast<uint8_t*>(&value);
    finalData = reinterpret_cast<uint8_t*>(&finalValue);
    for (int i = 0; i < sizeof(T); ++i) {
      finalData[i] = originalData[(sizeof(T) - i) - 1];
    }
    value = finalValue;
  }

  *buffer = value;
  return sizeof(T);
}

std::streamsize MemoryDataStream::write(const char *buffer,
                                        std::streamsize length) {
  return this->_write(buffer, length);
}

std::streamsize MemoryDataStream::write(int8_t value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(uint8_t value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(int16_t value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(uint16_t value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(int32_t value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(uint32_t value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(float value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(double value) {
  return this->_write(value);
}

std::streamsize MemoryDataStream::write(const std::string &value) {
  return this->_write(value.c_str(), strlen(value.c_str()) + 1);
}

template <typename T>
std::streamsize MemoryDataStream::_write(T buffer,
                                         std::streamsize length) {
  size_t pos = static_cast<size_t>(this->_cursor);
  size_t size = static_cast<size_t>(length);

  if (pos + size > this->_buffer.size()) {
    this->_buffer.resize(pos + size);
  }

  memcpy(&this->_buffer[pos], static_cast<T>(buffer), size);
  this->_cursor += size;
  return size;
}

template <typename T>
std::streamsize MemoryDataStream::_write(T value) {
  T finalValue = value;
  uint8_t *originalData = reinterpret_cast<uint8_t*>(&value);
  uint8_t *finalData = reinterpret_cast<uint8_t*>(&finalValue);

  if (_bigEndian && sizeof(T) > 1) {
    for (int i = 0; i < sizeof(T); ++i) {
      finalData[i] = originalData[(sizeof(T) - i) - 1];
    }
    originalData = finalData;
  }

  return this->_write(originalData, sizeof(T));
}

我想提出以下问题:

DataStreamInterface成为抽象类而不是接口,这样我就可以像这样使用模板了吗?它会影响性能或内存消耗吗?

代码语言:javascript
复制
  std::streamsize read(T *buffer);
  std::streamsize peek(T *buffer);
  std::streamsize write(T value);

我最近意识到,任何安卓和iOS应用程序在使用自己的DataStream实现库时都会冻结。

例如,如果"C++ side“调用用Java实现的HttpDataStream类来下载文件,它将冻结整个过程,甚至整个应用程序,直到下载结束。

下面是一个例子,调用在Java中定义的远程DataStream类:

代码语言:javascript
复制
std::streamsize DataStreamJava::read(double value) {
  jmethodID m = jni->GetMethodID(j_dataStream_class_,
                                 "read", "(D)J");
  jni->CallLongMethod(j_dataStream_global_, m);
  return 0;
}

我一直在考虑在“DataStreamObserver端”上创建一个名为C++的类,DataStream构造函数将接受DataStreamObserver类的一个实例,然后每次完成读或写操作时都调用它。

我是否应该将DataStreamObserver作为一个带有模板的抽象类来创建,以避免实现这样的方法?

代码语言:javascript
复制
virtual void onReadSuccess(int8_t value, std::steamsize length) = 0;
virtual void onReadSuccess(uint8_t value, std::steamsize length) = 0;
virtual void onReadSuccess(int16_t value, std::steamsize length) = 0;
virtual void onReadSuccess(uint16_t value, std::steamsize length) = 0;
EN

回答 2

Code Review用户

回答已采纳

发布于 2015-08-01 02:05:29

接口

似乎所有这些方法都不应该是虚拟的。

代码语言:javascript
复制
class DataStreamInterface {
 public:
  virtual bool open() = 0;
  virtual void close() = 0;
  virtual std::streamsize length() const = 0;
  virtual std::streamsize tell() const = 0;
  virtual std::streamsize seek(std::streamsize position) = 0;
  virtual std::streamsize read(char *buffer,
                               std::streamsize length) = 0;
  virtual std::streamsize read(int8_t *buffer) = 0;
  virtual std::streamsize read(uint8_t *buffer) = 0;
  virtual std::streamsize read(int16_t *buffer) = 0;
  virtual std::streamsize read(uint16_t *buffer) = 0;
  virtual std::streamsize read(int32_t *buffer) = 0;
  virtual std::streamsize read(uint32_t *buffer) = 0;
  virtual std::streamsize read(float *buffer) = 0;
  virtual std::streamsize read(double *buffer) = 0;
  virtual std::streamsize read(std::string *buffer) = 0;
  virtual std::streamsize peek(uint8_t *buffer,
                               std::streamsize length) = 0;
  virtual std::streamsize peek(int8_t *buffer) = 0;
  virtual std::streamsize peek(uint8_t *buffer) = 0;
  virtual std::streamsize peek(int16_t *buffer) = 0;
  virtual std::streamsize peek(uint16_t *buffer) = 0;
  virtual std::streamsize peek(int32_t *buffer) = 0;
  virtual std::streamsize peek(uint32_t *buffer) = 0;
  virtual std::streamsize peek(float *buffer) = 0;
  virtual std::streamsize peek(double *buffer) = 0;
  virtual std::streamsize peek(std::string *buffer) = 0;
  virtual std::streamsize write(const char *buffer,
                                std::streamsize length) = 0;
  virtual std::streamsize write(int8_t value) = 0;
  virtual std::streamsize write(uint8_t value) = 0;
  virtual std::streamsize write(int16_t value) = 0;
  virtual std::streamsize write(uint16_t value) = 0;
  virtual std::streamsize write(int32_t value) = 0;
  virtual std::streamsize write(uint32_t value) = 0;
  virtual std::streamsize write(float value) = 0;
  virtual std::streamsize write(double value) = 0;
  virtual std::streamsize write(const std::string &value) = 0;

  virtual ~DataStreamInterface() { }
};

在您的实现中,添加了执行实际工作的_write()_read()_peek()。似乎这些都是您的虚拟函数,其他的应该在基类DataStreamInterface中实现,以使用这些虚拟函数。

我想我会这样实施:

代码语言:javascript
复制
class DataStreamInterface {
 public:
    // Virtual Interface:
    virtual ~DataStreamInterface() { }

    virtual bool open() = 0;
    virtual void close() = 0;
    virtual std::streamsize length() const = 0;
    virtual std::streamsize tell() const = 0;
    virtual std::streamsize seek(std::streamsize position) = 0;
 private:
    // All the interesting stuff for each class is encapsulated in
    // these threee virtual methods. All the other read/peek/write
    // methods should delagate their work to these and not need to 
    // be re-implemented in each class.
    virtual std::streamsize vread(char *buffer, std::size_t size) = 0;
    virtual std::streamsize vwrite(char *buffer, std::size_t size) = 0;
    virtual std::streamsize vpeek(char *buffer, std::size_t size) = 0;

    template<typename T>
    std::streamsize tread(T *buffer, std::size_t size = sizeof(T))
    {
        return vread(reinterpret_cast<char*>(buffer), size);
    }
    template<typename T>
    std::streamsize twrite(T *buffer, std::size_t size = sizeof(T))
    {
        return vwrite(reinterpret_cast<char*>(buffer), size);
    }
    template<typename T>
    std::streamsize tpeek(T *buffer, std::size_t size = sizeof(T))
    {
        return vpeak(reinterpret_cast<char*>(buffer), size);
    }

    // standard interface.
    // I did these in a hurry there will be mistakes.
  public: 
    std::streamsize read(char *buffer, std::streamsize length){return tread(buffer, length);}
    std::streamsize read(int8_t *buffer)   {return tread(buffer);}
    std::streamsize read(uint8_t *buffer)  {return tread(buffer);}
    std::streamsize read(int16_t *buffer)  {return tread(buffer);}
    std::streamsize read(uint16_t *buffer) {return tread(buffer);}
    std::streamsize read(int32_t *buffer)  {return tread(buffer);}
    std::streamsize read(uint32_t *buffer) {return tread(buffer);}
    std::streamsize read(float *buffer)    {return tread(buffer);}
    std::streamsize read(double *buffer)   {return tread(buffer);}
    std::streamsize read(std::string *buffer) {return tread(buffer);}
    std::streamsize peek(uint8_t *buffer, std::streamsize length) {return tpeek(buffer, length);}
    std::streamsize peek(int8_t *buffer)   {return tpeek(buffer);}
    std::streamsize peek(uint8_t *buffer)  {return tpeek(buffer);}
    std::streamsize peek(int16_t *buffer)  {return tpeek(buffer);}
    std::streamsize peek(uint16_t *buffer) {return tpeek(buffer);}
    std::streamsize peek(int32_t *buffer)  {return tpeek(buffer);}
    std::streamsize peek(uint32_t *buffer) {return tpeek(buffer);}
    std::streamsize peek(float *buffer)    {return tpeek(buffer);}
    std::streamsize peek(double *buffer)   {return tpeek(buffer);}
    std::streamsize peek(std::string *buffer) {return tpeek(buffer.c_str(), buffer->length());}
    std::streamsize write(const char *buffer,std::streamsize length) {return tpeek(buffer, length);}
    std::streamsize write(int8_t value)    {return twrite(buffer);}
    std::streamsize write(uint8_t value)   {return twrite(buffer);}
    std::streamsize write(int16_t value)   {return twrite(buffer);}
    std::streamsize write(uint16_t value)  {return twrite(buffer);}
    std::streamsize write(int32_t value)   {return twrite(buffer);}
    std::streamsize write(uint32_t value)  {return twrite(buffer);}
    std::streamsize write(float value)     {return twrite(buffer);}
    std::streamsize write(double value)    {return twrite(buffer);}
    std::streamsize write(const std::string &value) {return twrite(buffer.c_str(), value.size());}

};

注释

让DataStreamInterface成为抽象类而不是接口,这样我就可以像这样使用模板了吗?

抽象类是一个接口。不同之处在于术语。

它会影响性能或内存消耗吗?

好的。但不是以任何有意义的方式。但在我给出更准确的答案之前,我需要你说得更具体些。

例如,如果"C++ side“调用用Java实现的HttpDataStream类来下载文件,它将冻结整个过程,甚至整个应用程序,直到下载结束。

一点都不奇怪。但这与它是一个C++函数无关。如果你要求处理器做一些事情,它不能做任何事情直到它完成。所以它会结冰。

除非您显式地将代码线程化,并在不同的线程上执行一些工作。

我一直在考虑在“DataStreamObserver端”上创建一个名为C++的类,DataStream构造函数将接受DataStreamObserver类的一个实例,然后每次完成读或写操作时都调用它。

好的。但这本身并不能帮助你的拖延过程。

票数 3
EN

Code Review用户

发布于 2015-08-02 13:18:22

如果您不想处理基于任何原因的虚拟函数,CRTP也可以是另一种设计。

代码语言:javascript
复制
template<typename T>
class DataStreamInterface
{
    public:
        void read(double* buffer)
        {
            static_cast<T*>(this)->StreamRead(buffer, sizeof(double));
        }

        void write(double* buffer)
        {
            static_cast<T*>(this)->StreamWrite(buffer, sizeof(double));
        }
};

class Stream : public DataStreamInterface<Stream>
{
    public:
        void StreamWrite(void* buffer, std::size_t size) {}
        void StreamRead(void* buffer, std::size_t size){}
};
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/98694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档