Надо сконвертить FILE* в ofstream
От: Аноним  
Дата: 10.12.04 12:29
Оценка:
Это возможно?
если брать fstream.h, а не fstream то у ofstream есть метод attach
и тогда:
  FILE*f;
  . . .
  ofstream fs;
  fs.attach(_fileno(f))


в fstream с этим как-то напряг:

template <class E, class T = char_traits<E> >
    class basic_ofstream : public basic_ostream<E, T> {
public:
    explicit basic_ofstream();
    explicit basic_ofstream(const char *s,
        ios_base::openmode mode = ios_base::out | ios_base::trunc);
    basic_filebuf<E, T> *rdbuf() const;
    bool is_open() const;
    void open(const char *s,
        ios_base::openmode mode = ios_base::out | ios_base::trunc);
    void close();
    };
Re: Надо сконвертить FILE* в ofstream
От: korzhik Россия  
Дата: 10.12.04 12:55
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Это возможно?

А>если брать fstream.h, а не fstream то у ofstream есть метод attach
А>и тогда:
А>
А>  FILE*f;
А>  . . .
А>  ofstream fs;
А>  fs.attach(_fileno(f))

А>


А>в fstream с этим как-то напряг:


переносимого решения нет, а так в VC7.1 есть конструктор который принимает FILE*
Re: Надо сконвертить FILE* в ofstream
От: MaximE Великобритания  
Дата: 10.12.04 20:04
Оценка: 27 (4)
wrote:

> Это возможно?


Да.

> если брать fstream.h, а не fstream то у ofstream есть метод attach

> и тогда:

[]

> в fstream с этим как-то напряг:


[]

Ты можешь написать собственный streambuf, который будет легким враппером над fread/fwrite.

Пример: буфер + поток в одном флаконе.

#include <stdio.h>
#include <iostream>

class filehandle_stream : private std::streambuf, public std::iostream
{
private:
     FILE* f_;

public:
     filehandle_stream(FILE* f) : std::iostream(this), f_(f) {}
     ~filehandle_stream() { if(f_) fclose(f_); }

     FILE* release() { FILE* t = f_; f_ = 0; return t; }

public:
     typedef std::streambuf::traits_type traits_type;
     typedef std::streambuf::char_type char_type;
     typedef std::streambuf::int_type int_type;

private: // интерфейс вывода
     std::streamsize xsputn(char_type const* s, std::streamsize n)
     {
         return fwrite(s, 1, n, f_);
     }

     int_type overflow(int_type c)
     {
         if(!traits_type::eq_int_type(c, traits_type::eof()))
         {
             char_type const t = traits_type::to_char_type(c);
             this->filehandle_stream::xsputn(&t, 1);
         }
         return !traits_type::eof();
     }

     int sync() { return !fflush(f_) ? 0 : -1; }

private: // интерфейс ввода
     std::streamsize xsgetn(char_type* s, std::streamsize n)
     {
         return fread(s, 1, n, f_);
     }

     int_type underflow()
     {
         char_type c;
         return 1 == this->xsgetn(&c, 1) ? traits_type::to_int_type(c) : traits_type::eof();
     }
};

int main()
{
     filehandle_stream s(stdout);
     s << "hey!" << std::endl;
     s.release();
}


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9 delta
Re[2]: Надо сконвертить FILE* в ofstream
От: _Vi  
Дата: 31.05.06 22:06
Оценка:
Здравствуйте, MaximE, Вы писали:
ME>Пример: буфер + поток в одном флаконе.
Вывод в этом примере работает. Ввод нет. (описание ошибки
Автор: _Vi
Дата: 01.06.06
).
Re[3]: Надо сконвертить FILE* в ofstream
От: MaximE Великобритания  
Дата: 01.06.06 08:21
Оценка:
Здравствуйте, _Vi, Вы писали:

_Vi>Здравствуйте, MaximE, Вы писали:

ME>>Пример: буфер + поток в одном флаконе.
_Vi>Вывод в этом примере работает. Ввод нет. (описание ошибки
Автор: _Vi
Дата: 01.06.06
).


Действительно, ввод не работает, неправильно реализован underflow/uflow. Приношу свои извинения. Пользуй boost::iostream.
Re[4]: Надо сконвертить FILE* в ofstream
От: MaximE Великобритания  
Дата: 01.06.06 09:02
Оценка: 2 (1)
MaximE wrote:

> Здравствуйте, _Vi, Вы писали:

>
> _Vi>Здравствуйте, MaximE, Вы писали:
> ME>>Пример: буфер + поток в одном флаконе.
> _Vi>Вывод в этом примере работает. Ввод нет. (описание ошибки
> <http://rsdn.ru/Forum/Message.aspx?mid=1929472&amp;only=1&gt;
Автор: _Vi
Дата: 01.06.06
).

>
> Действительно, ввод не работает, неправильно реализован underflow/uflow.
> Приношу свои извинения. Пользуй boost::iostream.

fix:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <limits>
#include <cassert>

class filehandle_stream : private std::streambuf, public std::iostream
{
private:
     FILE* f_;

public:
     filehandle_stream(FILE* f) : std::iostream(this), f_(f) {}
     ~filehandle_stream() { if(f_) fclose(f_); }

     FILE* release() { FILE* t = f_; f_ = 0; return t; }

public:
     typedef std::streambuf::traits_type traits_type;
     typedef std::streambuf::char_type char_type;
     typedef std::streambuf::int_type int_type;

private:
     std::streamsize xsputn(char_type const* s, std::streamsize n)
     {
         return fwrite(s, 1, n, f_);
     }

     int_type overflow(int_type c)
     {
         if(!traits_type::eq_int_type(c, traits_type::eof()))
         {
             char_type const t = traits_type::to_char_type(c);
             this->filehandle_stream::xsputn(&t, 1);
         }
         return !traits_type::eof();
     }

     int sync() { return !fflush(f_) ? 0 : -1; }

private:
     std::streamsize xsgetn(char_type* s, std::streamsize n)
     {
         return fread(s, 1, n, f_);
     }

     char buf_[1];
     int_type underflow()
     {
         std::streamsize s = this->xsgetn(buf_, sizeof buf_);
         if(s > 0)
         {
             this->setg(buf_, buf_, buf_ + s);
             return traits_type::to_int_type(*buf_);
         }
         else
         {
             return traits_type::eof();
         }
     }
};

int main()
{
     {
         FILE* f = fopen("file.txt", "w");
         filehandle_stream fs(f);
         fs << "hey!" << '\n' << 1 << '\n' << 3.14 << '\n' << 
0x0102030405060708ull << std::endl;
     }

     std::string s;
     int i;
     double d;
     unsigned long long ull;

     {
         FILE* f = fopen("file.txt", "r");
         filehandle_stream fs(f);
         fs >> s >> i >> d >> ull;
     }

     assert("hey!" == s);
     assert(1 == i);
     assert(std::abs(3.14 - d) < std::numeric_limits<double>::epsilon());
     assert(0x0102030405060708ull == ull);
}


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 2.0
Re[5]: Надо сконвертить FILE* в ofstream
От: _Vi  
Дата: 01.06.06 11:27
Оценка:
Здравствуйте, MaximE, Вы писали:
ME>MaximE wrote:
>> Здравствуйте, _Vi, Вы писали:
>> _Vi>Здравствуйте, MaximE, Вы писали:
>> ME>>Пример: буфер + поток в одном флаконе.
>> _Vi>Вывод в этом примере работает. Ввод нет. (описание ошибки
>> Действительно, ввод не работает, неправильно реализован underflow/uflow.
ME>fix:
Спасибо, работает, буду использовать.
Но есть один маленький нюанс: если дополнить Pi, например, до 3.1415926534, то оно вылетит, т.к. почему-то по умолчанию округляется до 5 цифр. (Фиксится добавлением "fs.precision(...);" при выводе).
Re[6]: Надо сконвертить FILE* в ofstream
От: MaximE Великобритания  
Дата: 01.06.06 11:37
Оценка:
Здравствуйте, _Vi, Вы писали:

_Vi>Здравствуйте, MaximE, Вы писали:

ME>>MaximE wrote:
>>> Здравствуйте, _Vi, Вы писали:
>>> _Vi>Здравствуйте, MaximE, Вы писали:
>>> ME>>Пример: буфер + поток в одном флаконе.
>>> _Vi>Вывод в этом примере работает. Ввод нет. (описание ошибки
>>> Действительно, ввод не работает, неправильно реализован underflow/uflow.
ME>>fix:
_Vi>Спасибо, работает, буду использовать.

На чтение он не очень эффективен: streambuf требует буферизации, хотя она бывает не нужна, как для случая с FILE*, когда буферизация осуществляется в libc. Отсюда и char buf_[1].

Я не знаю, решена ли эта проблема в boost::iostream.

_Vi>Но есть один маленький нюанс: если дополнить Pi, например, до 3.1415926534, то оно вылетит, т.к. почему-то по умолчанию округляется до 5 цифр. (Фиксится добавлением "fs.precision(...);" при выводе).


Это уже тараканы в ostream.
Re[7]: Надо сконвертить FILE* в ofstream
От: _Vi  
Дата: 01.06.06 20:59
Оценка:
Здравствуйте, MaximE, Вы писали:
ME>На чтение он не очень эффективен: streambuf требует буферизации, хотя она бывает не нужна, как для случая с FILE*, когда буферизация осуществляется в libc. Отсюда и char buf_[1].
По умолчанию оно читает побайтово, но если изменить char buf_[1]; на char buf_[16];, например, то оно начинает читать блоками по 16 байт и сохранять у себя. (По идее мне это и нужно). Или там получается дублирование буфферизации? (в этом классе и ещё где-то stream'ах)
(Вообще я собираюсь написать вместо fread/fwrite своё и использовать это для сокетов или ReadFile/WriteFile или ещё чего-либо...).
Re[8]: Надо сконвертить FILE* в ofstream
От: MaximE Великобритания  
Дата: 02.06.06 05:53
Оценка:
_Vi wrote:

> Здравствуйте, MaximE, Вы писали:

> ME>На чтение он не очень эффективен: streambuf требует буферизации, хотя
> она бывает не нужна, как для случая с FILE*, когда буферизация
> осуществляется в libc. Отсюда и char buf_[1].
> По умолчанию оно читает побайтово, но если изменить char buf_[1]; на
> char buf_[16];, например, то оно начинает читать блоками по 16 байт и
> сохранять у себя. (По идее мне это и нужно). Или там получается
> дублирование буфферизации? (в этом классе и ещё где-то stream'ах)

С блочного устройства (hard disk, к примеру) операционная система считывает
блоками — кэширование. FILE* по-умолчанию буферизуется. streambuf обязывает
использовать буферизацию при чтении.

Чтобы избежать ненужной буферизации и копирования kernel -> user space часто
гораздо проще отобразить файл в память.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 2.0
Re[9]: Надо сконвертить FILE* в ofstream
От: _Vi  
Дата: 03.06.06 20:31
Оценка:
Здравствуйте, MaximE, Вы писали:
ME>Чтобы избежать ненужной буферизации и копирования ...
ME>Maxim Yegorushkin
Но для сокетов и pipe'ов это пойдёт нормально? (Какой размер буффера посоветуешь?).
Re[10]: Надо сконвертить FILE* в ofstream
От: MaximE Великобритания  
Дата: 04.06.06 09:19
Оценка:
_Vi wrote:

> Здравствуйте, MaximE, Вы писали:

> ME>Чтобы избежать ненужной буферизации и копирования ...

> Но для сокетов и pipe'ов это пойдёт нормально? (Какой размер буффера

> посоветуешь?).

Зависит от протокола (поверх tcp/udp/...), который использует твоя программа.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 2.0
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.