Копирование одного потока станд. другому эффективно

Хорошо, Вот некоторый код, который обрисовывает в общих чертах то, что я пытаюсь сделать.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>

#include <iostream>
#include <sstream>

int main( int c, char *v[] )
{
    int fd = open( "data.out", O_RDONLY | O_NONBLOCK );
    std::cout << "fd = " << fd << std::endl;

    char buffer[ 1024000 ];
    ssize_t nread;

    std::stringstream ss;

    while( true )
    {
        if ( (nread = read( fd, buffer, sizeof( buffer ) - 1 )) < 0 )
            break;

        ss.write( buffer, nread );

        while( true )
        {
            std::stringstream s2;

            std::cout << "pre-get  : " <<
                (((ss.rdstate() & std::ios::badbit) == std::ios::badbit) ? "bad" : "") << " " <<
                (((ss.rdstate() & std::ios::eofbit) == std::ios::eofbit) ? "eof" : "") << " " <<
                (((ss.rdstate() & std::ios::failbit) == std::ios::failbit) ? "fail" : "" ) << " " <<
                std::endl;

            ss.get( *s2.rdbuf() );

            std::cout << "post-get : " <<
                (((ss.rdstate() & std::ios::badbit) == std::ios::badbit) ? "bad" : "") << " " <<
                (((ss.rdstate() & std::ios::eofbit) == std::ios::eofbit) ? "eof" : "") << " " <<
                (((ss.rdstate() & std::ios::failbit) == std::ios::failbit) ? "fail" : "" ) << " " <<
                std::endl;

            unsigned int linelen = ss.gcount() - 1;

            if ( ss.eof() )
            {
                ss.str( s2.str() );
                break;
            }
            else if ( ss.fail() )
            {
                ss.str( "" );
                break;
            }
            else
            {
                std::cout << s2.str() << std::endl;
            }
        }
    }
}

Это во-первых читает большие блоки данных в буфер данных. Я знаю, что существует лучший C++ способы внести свой вклад, но в моем реальном приложении мне вручают символ [] буфер и длину.

Я затем пишу буфер в станд.:: stringstream возражают, таким образом, я могу удалить строку за один раз из него.

Я думал, что буду использовать получение (streambuf и) метод на stringstream для записи одной строки в другой stringstream, где я могу затем произвести его.

Игнорирование того, что это не может быть лучшим способом извлечь строку за один раз из буфера, в котором я читал (хотя я хотел бы, чтобы любой предложил лучшую альтернативу той, я отправляю здесь), как только первое ss.get( *s2.rdbuf() ) назван ss находится в состоянии сбоя, и я не могу удаться почему. Существует много данных во входном файле так ss должен определенно содержать больше чем одну строку входа.

Какие-либо идеи?

8
задан falstro 18 January 2010 в 08:35
поделиться

2 ответа

Я проверил это в Windows, чтобы вы могли захотеть проверить это;

Если данные. Начты начинается с новой строки, я получаю такую ​​же проблему, у вас есть SS .get (* s2.rdbuf ()) работает нормально для первого звонка.

Когда он называется во второй раз, текущее положение потока не продвинулось мимо EOL. Поэтому, когда во второй момент немедленно попытайтесь прочитать EOL, и поскольку никакие другие символы не были скопированы, он устанавливает бит провал.

Быстро и, возможно, грязное исправление:

ss.get( *s2.rdbuf() );
// Get rid of EOL (may need an extra if file contains both \r and \n)
ss.get();
0
ответ дан 6 December 2019 в 02:25
поделиться

Мне кажется, что первый (и, вероятно, самый большой) шаг, чтобы стать приличным Эффективность состоит в том, чтобы минимизировать копирование данных. Поскольку вам дают данные в CHAR [] с длиной, моя первая тенденция будет начать с создания Strestream , используя этот буфер. Затем вместо копирования строки за раз на другой Stretream (или StringStream) я копировал строки по одному в то время, который вы будете использовать, чтобы написать их на вывод.

Если вам разрешено изменить содержимое буфера, другая возможность будет разбирать буфер в строки, просто заменяя каждого «\ n» с A '\ 0'. Если вы собираетесь сделать это, вы обычно хотите создать вектор (DECE и т. Д.) УК на начало каждой строки, а также (то есть найдите первое «\ R» или «\ n», а также Замените его «\ 0». Затем следующее, кроме «\ R» или '\ N', является началом следующей строки, поэтому ее адрес в вашем векторе).

Я также усердно подумал, сможете ли вы избежать вывода линии на A-A-Time. Чтение через большой буфер, чтобы найти новую линию относительно медленного. В любом случае, если вы собираетесь в конечном итоге написать одну строку за другим, вы можете избежать всего этого, просто пишете на весь буфер до выходного потока и выполняемой с ним.

1
ответ дан 6 December 2019 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: