Я использовал std::istream
и ostream
в качестве полиморфного интерфейса для двоичного ввода-вывода с произвольным доступом в C ++, но он кажется неоптимальным во многих отношениях:
- 64-битзапросы являются непереносимыми и подвержены ошибкам из-за ограничений streampos / streamoff;в настоящее время используется boost / iostreams / positioning.hpp в качестве обходного пути, но для этого требуется бдительность
- Отсутствие таких операций, как усечение или расширение файла (ala POSIX
ftruncate
) - Несоответствие между конкретными реализациями;например,
stringstream
имеет независимые позиции get / put, тогда как filestream
не - Несоответствие между реализациями платформы;Например, поведение поиска передается в конец файла или использование
failbit
/ badbit
при ошибках - Не нужно все средства форматирования
stream
или, возможно, даже буферизация streambuf
streambuf
сообщение об ошибке (т.е. исключения и возврат индикатора ошибки) предположительно зависит от реализации на практике
Мне нравится упрощенный интерфейс, предоставляемый Boost.Iostreams Концепция устройства , но она предоставляется в виде шаблонов функций, а не полиморфного класса.(Существует device
класс , но он не полиморфный и является просто вспомогательным классом реализации, не обязательно используемым реализациями поставляемых устройств.) Я в основном использую большие файлы на диске, но я действительно хочу полиморфизмтак что я могу легко заменить альтернативные реализации (например, использовать stringstream
вместо fstream
для модульных тестов) без всей сложности и сопряжения во время компиляции глубокого создания шаблона.
Есть ли у кого-нибудь какие-либо рекомендации стандартаподход к этому?Это похоже на обычную ситуацию, поэтому я не хочу изобрести свои собственные интерфейсы без необходимости.Например, что-то вроде java.nio.FileChannel кажется идеальным.
Мое лучшее решение на данный момент - это положить тонкий полиморфный слой поверх устройств Boost.Iostreams.Например:
class my_istream
{
public:
virtual std::streampos seek(stream_offset off, std::ios_base::seekdir way) = 0;
virtual std::streamsize read(char* s, std::streamsize n) = 0;
virtual void close() = 0;
};
template <class T>
class boost_istream : public my_istream
{
public:
boost_istream(const T& device) : m_device(device)
{
}
virtual std::streampos seek(stream_offset off, std::ios_base::seekdir way)
{
return boost::iostreams::seek(m_device, off, way);
}
virtual std::streamsize read(char* s, std::streamsize n)
{
return boost::iostreams::read(m_device, s, n);
}
virtual void close()
{
boost::iostreams::close(m_device);
}
private:
T m_device;
};