std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 16.01.02 10:25
Оценка: 2 (1)
Есть вектор и файловый поток:

vector<__int16> samples;
fstream *destfile; // уже открыт


если сделать так:

ostream_iterator<__int16> outfile_iter( *destfile);

copy( samples.begin(), samples.end(), outfile_iter );


то в файл естественно пишутся мои цифры как текст, а мне надо их затолкать туда в бинарном виде. Напрашивается что-то типа


transform( samples.begin(), samples.end(), outfile_iter, func );


но вот как написать эту func, чтой-то я не соображу
Re: std::transform
От: grs Россия  
Дата: 16.01.02 12:41
Оценка:
Здравствуйте Odi$$ey, Вы писали:

O$>Есть вектор и файловый поток:

O$>
O$>vector<__int16> samples;
O$>fstream *destfile; // уже открыт
O$>


O$>если сделать так:

O$>
O$>ostream_iterator<__int16> outfile_iter( *destfile);

O$>copy( samples.begin(), samples.end(), outfile_iter );
O$>


O$>то в файл естественно пишутся мои цифры как текст, а мне надо их затолкать туда в бинарном виде. Напрашивается что-то типа


O$>
O$>transform( samples.begin(), samples.end(), outfile_iter, func );
O$>


O$>но вот как написать эту func, чтой-то я не соображу

А что мешает использовать copy, но файловый поток открывать с openmode ios_base::binary?
Re: std::transform
От: TepMuHyc  
Дата: 16.01.02 12:47
Оценка: 12 (1)
Здравствуйте Odi$$ey, Вы писали:

O$>Есть вектор и файловый поток:

Я бы эту проблему решал примерно так:

tamplate<class T>
struct as_binary_class()
{

    T &m_data; //ссылка на контейнер который мы будем выводить
    as_binary(T& t):_data(t) {}
}

//функция-фабрика экземпляров для удобства использования с операторами потока
template<class T> as_binary_class<T> as_binary(T& v)
{
   return as_binary_class<T>(v);
}

template<class T> ostream& operator<<(as_binary<T>&, ostream&);
//имплементации у этого оператора нет. Будем специализировать его
//для каждого Т

//специализация для вектора
template<> ostream& operator<<(as_binary_class<vector<int> >& v, ostream& os)
{
   for(vector<int>::iterator i=v.m_data.begin(); i<v.m_data.end(); i++)
   { 
       int x = *i; 
       os.write((char*)&x, sizeof(x));
   }
}


теперь применение
cout << as_binary(SomeIntVector) << flush;
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 16.01.02 12:50
Оценка:
Здравствуйте grs, Вы писали:

grs>А что мешает использовать copy, но файловый поток открывать с openmode ios_base::binary?


а он так и открыт
Re: std::transform
От: TepMuHyc  
Дата: 16.01.02 12:53
Оценка:
Здравствуйте Odi$$ey, Вы писали:

O$>Есть вектор и файловый поток:
Ответ №2.

Коль скоро речи зашла о бинарном выводе, то я бы рекомендовал
воздержаться от применения потоков вообще.

Впрочем, если ты мазохист — go ahead
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[3]: std::transform
От: grs Россия  
Дата: 16.01.02 14:23
Оценка: 8 (1)
Здравствуйте Odi$$ey, Вы писали:

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

grs>>А что мешает использовать copy, но файловый поток открывать с openmode ios_base::binary?


O$>а он так и открыт

Так должно работать:
[code]
filebuf *buf = destfile->rdbuf();
ostreambuf_iterator<char> outfile_iter(buf);
copy( v.begin(), v.end(), outfile_iter );
[\code]
Re: std::transform
От: Юнусов Булат Россия  
Дата: 16.01.02 17:16
Оценка: 10 (2)
Здравствуйте Odi$$ey, Вы писали:

O$>Есть вектор и файловый поток:

O$>
O$>vector<__int16> samples;
O$>fstream *destfile; // уже открыт
O$>


O$>если сделать так:

O$>
O$>ostream_iterator<__int16> outfile_iter( *destfile);

O$>copy( samples.begin(), samples.end(), outfile_iter );
O$>


O$>то в файл естественно пишутся мои цифры как текст, а мне надо их затолкать туда в бинарном виде. Напрашивается что-то типа


O$>
O$>transform( samples.begin(), samples.end(), outfile_iter, func );
O$>


O$>но вот как написать эту func, чтой-то я не соображу

я вот с CommonC++ библиотекой вожусь — у ней iostream бинарно открывается и потом стл контейнеры сериализуются туда
проект gcc-овый (djgpp, mingw, linux) и msvc-овый (ну бзик у меня на кроссплатформенности)
чего то не получается потом проектные выходные файлы из другой операционки открыть
стал копать нарыл вот что


From: kuehl@ramsen.informatik.uni-konstanz.de (Dietmar Kuehl)
Newsgroups: comp.std.c++
Subject: Re: binary iostreams ?
Date: Sat, 3 Feb 2001 17:17:49 GMT
Message-ID: <95hctq$suu$2@news.BelWue.DE>

Hi,
Plinio Conti (plinio.contiNO@SPAMMINGmclink.it) wrote:
: Why std c++ library stream classes are only text-oriented?

There is only a text oriented front end to stream buffers because text
input and output does not vary between platforms. This is very
different for binary output. For example, binary output has to consider

— word sizes: Is an 'int' two, four, or eight bytes long? The same
questions arise for all other built-in types.

— what is the bit pattern of a value? I think that at least implicitly
in the standard a binary representation for integer types is required.
I don't think that it is required to use two's complement. In any
case, the floating point representations do differ, eg. in their
number of bytes used.

— what "endianess" is to be used?

Basically it is possible to decide a format for each of those. This,
however, implies inefficient implementations on platforms where the
format does not match the internal representation.

What many people asking for binary I/O forget is that binary I/O also
requires some form of formatting! Assuming that just writing data and
then reading it in will work is asking for problems, eg. when the
compiler version changes and they decided to use a 32 bit integer
rather than a 16 bit integer: It is not even necessary to switch
platforms to run into problems!

: I mean, if I want to write an int, a float, etc. AS IT IS I can't use
: streams, because they write and read a human readable text format of
: numbers.

Which is for most I/O a reasonable approach. If it is not for you, you
might want to consider a data base: File I/O is not really useful as a
persistance mechanism. It is fine eg. for user interaction (text I/O),
logging (text I/O), cross platfrom program interaction (formatted I/O),
and data exchange (formatted I/O). In all these cases, the I/O is
formatted, although possible using a binary format. For persistance,
data bases are used. Depending on your needs, a relational or an object
oriented one may be better suited.

That said, it is worth to mention that it is easy to create a hierarchy
similar to IOStreams built on top of stream buffers but doing binary
formatting. A somewhat aged example is found at
<ftp://ftp.fmi.uni-konstanz.de/pub/algo/personal/kuehl/binio.tar.gz&gt;.
This uses XDR formatting of the binary data (well, if I remmeber
correctly, it is easy to plug in a different binary formatting).

: Does anyone know how to solve the problem?

Use a data base, text formatting, or binary formatting. With the
details you have given it is impossible to tell which of those is the
right approach because you haven't told *why* you want a binary format
and *what* you want to do. That basically means that you came up with
solution and you want us to confirm that it is the right one without
telling us what problem is solved! Until I have seen the problem I
doubt that binary I/O is the right approach...

... and, BTW, using 'std::istream::read()' and 'std::ostream::write()'
is almost certainly the *wrong* approach! These functions are an
historical mistake which should have been corrected in the standard:
It is my understanding that these methods were present in the IOStream
version predating the rework from Jerry Schwartz and were left in to
be compatible with the earlier stuff although they were not necessary:
You could get binary I/O from the stream buffer level. The original
IOStream library (maybe you remember using <stream.h>) did not have
stream buffers and thus basic support for binary I/O was also present
on the streams level.

: What do you think about this choice?

When I wrote the above paragraph about confirming your choice, I haven't
read this question! As I said above: You told us what solution you have
choosen without stating what problem is solved. We cannot determine
whether your choice is the right one. Actually, I'm pretty sure it is
the wrong one but without seen the details I can't be certain.
--
<mailto:dietmar_kuehl@yahoo.com&gt; <http://www.dietmar-kuehl.de/&gt;
Phaidros eaSE — Easy Software Engineering: <http://www.phaidros.com/&gt;
Re[4]: std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 17.01.02 05:30
Оценка:
Здравствуйте grs, Вы писали:

grs>Так должно работать:

grs> [code]
grs> filebuf *buf = destfile->rdbuf();
grs> ostreambuf_iterator<char> outfile_iter(buf);
grs> copy( v.begin(), v.end(), outfile_iter );
grs> [\code]

хм, пишется-то оно пишется, только с данными что-то происходит, толи байты местами меняются, толи еще что-то, буду разбираться.
Re[2]: std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 17.01.02 05:34
Оценка:
Здравствуйте Юнусов Булат, Вы писали:

ЮБ>я вот с CommonC++ библиотекой вожусь — у ней iostream бинарно открывается и потом стл контейнеры сериализуются туда

ЮБ>проект gcc-овый (djgpp, mingw, linux) и msvc-овый (ну бзик у меня на кроссплатформенности)
ЮБ>чего то не получается потом проектные выходные файлы из другой операционки открыть
ЮБ>стал копать нарыл вот что

ясно, только кроссплатформенность мне не нужна, из моих samples создается WAV файл, поэтому и надо их в бинарном формате скидывать в файл.
Re[2]: std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 17.01.02 05:38
Оценка:
Здравствуйте TepMuHyc, Вы писали:

TMH>Я бы эту проблему решал примерно так:


TMH>[ccode]

TMH>tamplate<class T>
TMH>struct as_binary_class()
TMH>{

TMH> T &m_data; //ссылка на контейнер который мы будем выводить

TMH> as_binary(T& t):_data(t) {}
TMH>}

это вариант конечно, только чую можно проще, и вариант от grs тому подтверждение
Re[3]: std::transform
От: retalik www.airbandits.com/
Дата: 17.01.02 06:09
Оценка: 38 (4)
Здравствуйте Odi$$ey, Вы писали:

O$>это вариант конечно, только чую можно проще, и вариант от grs тому подтверждение
А почему бы не использовать write()? Элементы std::vector располагаются в памяти последовательно, это какое-то уточнение к STL было.

Ну, если религия так не позволяет, то можно и binary_iterator забабахать(пригодится в будущем):

template<class Stream, class T>
class binary_iterator
{
    Stream* stream;
  public:
    binary_iterator(Stream* f){ stream=f; }
    binary_iterator& operator*(){ return *this; }
    binary_iterator& operator=(T& val)
    { 
        stream->write((const char*)&val, sizeof val); 
        return *this;
    }
    void operator++(){} //заглушка
};


А использовать как обычный итератор:
#include <vector>
#include <fstream>
#include "BinaryIter.h" //этот класс

int main()
{
    std::vector<__int16> samples;
    std::ofstream destfile("a.dat", std::ios::binary);
    samples.push_back(10);
    samples.push_back(20);
    binary_iterator<std::ofstream, __int16> outfile_iter(&destfile);
    std::copy( samples.begin(), samples.end(), outfile_iter );
    return 0;
}
Успехов,
Виталий.
Re[4]: std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 17.01.02 08:26
Оценка:
Здравствуйте retalik, Вы писали:

R>А почему бы не использовать write()? Элементы std::vector располагаются в памяти последовательно, это какое-то уточнение к STL было.


дык а не знал я этого, сейчас проверил, действительно

destfile->write( ( const char* ) &samples.at(0), samples.size() * sizeof( __int16 ) );


и вся недолга.

Жалко только что мне еще над каждым сэмплом надо надругаться определенным образом, перед выводом в файл.
Я это в первом сообщении опустил для простоты.
Re[4]: std::transform
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 17.01.02 09:34
Оценка:
Здравствуйте retalik, Вы писали:

R>Ну, если религия так не позволяет,

религия позволяет только надо данные подшаманивать по ходу дела
R>то можно и binary_iterator забабахать(пригодится в будущем):

остановился пока на этом, действительно, пригодится.

Только надо в одном месте const дописать, а то не компилится —

R>template<class Stream, class T>
R>class binary_iterator
R>{
R>    Stream* stream;
R>  public:
R>    binary_iterator(Stream* f){ stream=f; }
R>    binary_iterator& operator*(){ return *this; }

      binary_iterator& operator=( const T& val)
R>    { 
R>        stream->write((const char*)&val, sizeof val); 
R>        return *this;
R>    }
R>    void operator++(){} //заглушка
R>};
Re[5]: std::transform
От: grs Россия  
Дата: 17.01.02 09:43
Оценка:
Здравствуйте Odi$$ey, Вы писали:

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

grs>>Так должно работать:

grs>> [code]
grs>> filebuf *buf = destfile->rdbuf();
grs>> ostreambuf_iterator<char> outfile_iter(buf);
grs>> copy( v.begin(), v.end(), outfile_iter );
grs>> [\code]

O$>хм, пишется-то оно пишется, только с данными что-то происходит, толи байты местами меняются, толи еще что-то, буду разбираться.

Каюсь, не будет это работать для int, тормознул вчера, с кем не бывает. В качестве компенсации привожу еще вариант решения проблемы (это точно работает, проверял).
[code]
template <class T>
class writeFile
{
private:
ofstream* f;
public:
writeFile(ofstream* _f){f=_f;};
void operator()(const T& value)
{
f->write((const char*)&value, sizeof(T));
};

};

int main(int argc, char* argv[])
{
int a[] = {200,11345, 243, 12, 8};
vector<int> v(a, a+5);
ofstream f("d:/temp/test.txt", ios_base::binary|ios_base::out|ios_base::trunc);
writeFile<int> wf(&f);
for_each(v.begin(), v.end(), wf);
return 0;
}
[\code]
Re[2]: as_binary
От: Anton V. Kolotaev  
Дата: 13.05.02 06:04
Оценка:
Здравствуйте TepMuHyc, Вы писали:

Небольшая поправочка

TMH>
....
TMH>template<class T> ostream& operator<<(as_binary_class<T>, ostream&);
.....
TMH>


Если, конечно, не ошибаюсь
Re[3]: Binary for win32
От: MaximE Великобритания  
Дата: 17.05.02 10:16
Оценка:
У меня вот так была реализована бинарная сериализация. Версия для win32, но крайне просто переделывается под iostream.

Может, кому будет интересно

#pragma once
#include <windows.h>
#include <cassert>
#include <vector>
#include <string>

typedef std::basic_string<TCHAR> TString;

#define RESERVED_SIZE 16

///////////////////////////////////////////////////////////////////////////////

struct TCash {
    SYSTEMTIME    m_stDate;
    int            m_nPurpose;
    TString        m_strOther;
    BYTE        m_PurposeReserved[RESERVED_SIZE];
    double        m_dIncomeRub;
    double        m_dIncomeUsd;
    double        m_dExpenseRub;
    double        m_dExpenseUsd;
    double        m_dCurrency;
    TString        m_strComment;
    BYTE        m_Reserved[RESERVED_SIZE];
};
typedef std::vector< TCash > VecTCash;
void LoadVector( const TCHAR *, VecTCash &);
void SaveVector( const TCHAR *, const VecTCash &);


//////////////////////////////////////////////////////////////////////////////
// Реализация

class T_WriteFile {
    HANDLE hFile;
    DWORD cb;
public:
//    T_WriteFile( const HANDLE hh ) : hFile(hh) {};
    T_WriteFile( const TCHAR *filename )
    {
        hFile = CreateFile(
            filename,
            GENERIC_WRITE, 
            0,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL );
        assert( hFile != INVALID_HANDLE_VALUE );
    };
    ~T_WriteFile() { CloseHandle( hFile ); };

    template< class T >    operator() ( const T &t )
    {
        WriteFile( hFile, (void*) &t, sizeof(t), &cb, NULL );
        assert ( sizeof(t) == cb );
    };

    operator() ( const void *t, const size_t n )
    {
        WriteFile( hFile, t, n, &cb, NULL );
        assert ( n == cb );
    };

    operator() ( const TString& s )
    {
        operator()( (size_t) s.size() * sizeof(TCHAR) );
        WriteFile( hFile, (void*) s.data(), s.size() * sizeof(TCHAR), &cb, NULL );
        assert( s.size() * sizeof(TCHAR) == cb );
    };

private:
    T_WriteFile( const T_WriteFile &b ) {};
    T_WriteFile& operator=( const T_WriteFile &b ) {};
};

class T_ReadFile {
    HANDLE hFile;
    DWORD cb;
public:
//    T_ReadFile( const HANDLE hh ) : hFile(hh) {};
    T_ReadFile( const TCHAR *filename )
    {
        hFile = CreateFile(
            filename,
            GENERIC_READ, 
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL );
        assert( hFile != INVALID_HANDLE_VALUE );
    };
    T_ReadFile() { CloseHandle( hFile ); };

    template< class T >    operator() ( T &t )
    {
        ReadFile( hFile, (void*) &t, sizeof(t), &cb, NULL );
        assert( sizeof(t) == cb );
    };

    operator() ( void *t, const size_t n )
    {
        ReadFile( hFile, t, n, &cb, NULL );
        assert( n == cb );
    };

    operator() ( TString& s )
    {
        size_t cb_size;
        operator()( cb_size );
        TCHAR* buf = (TCHAR*) HeapAlloc( GetProcessHeap(), 0, cb_size );
        ReadFile( hFile, (void*) buf, cb_size, &cb, NULL );
        assert ( cb == cb_size );
        s.assign( buf, cb_size / sizeof(TCHAR) );
        HeapFree( GetProcessHeap(), 0, buf );
    };

private:
    T_ReadFile( const T_ReadFile &b ) {};
    T_ReadFile& operator=( const T_ReadFile &b ) {};
};
/////////////////////////////////////////////////////////////////////////////

void SaveVector( const TCHAR *filename, const VecTCash &vec)
{
    T_WriteFile wf( filename );

    size_t nSize = vec.size();
    wf( nSize );
    for( unsigned i1 = 0; i1 < nSize; ++i1 ) {
        wf( vec[i1].m_stDate.wYear );
        wf( vec[i1].m_stDate.wMonth );
        wf( vec[i1].m_stDate.wDayOfWeek );
        wf( vec[i1].m_stDate.wDay );
        wf( vec[i1].m_stDate.wHour );
        wf( vec[i1].m_stDate.wMinute );
        wf( vec[i1].m_stDate.wSecond );
        wf( vec[i1].m_nPurpose );
        wf( vec[i1].m_strOther );
        wf( vec[i1].m_PurposeReserved, RESERVED_SIZE );
        wf( vec[i1].m_dIncomeRub );
        wf( vec[i1].m_dIncomeUsd );
        wf( vec[i1].m_dExpenseRub );
        wf( vec[i1].m_dExpenseUsd );
        wf( vec[i1].m_dCurrency );
        wf( vec[i1].m_strComment );
        wf( vec[i1].m_Reserved, RESERVED_SIZE );
    }
}

void LoadVector( const TCHAR *filename, VecTCash &vec)
{
    T_ReadFile rf( filename );

    vec.clear();
    size_t nSize;
    rf( nSize );
    vec.assign( nSize, TCash() );
    for( unsigned i1 = 0; i1 < nSize; ++i1 ) {
        rf( vec[i1].m_stDate.wYear );
        rf( vec[i1].m_stDate.wMonth );
        rf( vec[i1].m_stDate.wDayOfWeek );
        rf( vec[i1].m_stDate.wDay );
        rf( vec[i1].m_stDate.wHour );
        rf( vec[i1].m_stDate.wMinute );
        rf( vec[i1].m_stDate.wSecond );
        rf( vec[i1].m_nPurpose );
        rf( vec[i1].m_strOther );
        rf( vec[i1].m_PurposeReserved, RESERVED_SIZE );
        rf( vec[i1].m_dIncomeRub );
        rf( vec[i1].m_dIncomeUsd );
        rf( vec[i1].m_dExpenseRub );
        rf( vec[i1].m_dExpenseUsd );
        rf( vec[i1].m_dCurrency );
        rf( vec[i1].m_strComment );
        rf( vec[i1].m_Reserved, RESERVED_SIZE );
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.