2010-08-22 5 views
8

Как я прочитал ровно 128 байт из потока в строковый объект?Как я могу прочитать ровно 128 байт из потока в строковый объект?

Я написал код для чтения первых 128 байт файла и распечатал его, а затем последние 128 байт файла и напечатал это. Последняя часть работает, так как вы можете легко перебирать EOF, но как мне получить ровно 128 байт с фронта? Код ниже не работает, так как вы не можете добавить 128 в итератор ifstream, он не индексируемый, только инкрементный (кажется).

Несомненно, я мог бы сделать итератор и * ++ его 128 раз, но для этого должна быть единственная прямая линия, верно?

#include <iostream> 
#include <fstream> 
#include <string> 

int main(int argc, char **argv) 
{ 
    std::ifstream ifs ("input.txt",std::ifstream::in | std::ifstream::binary); 

    if (ifs.good()) 
    { 
    // read first 128 bytes into a string 
     ifs.seekg(0,std::ifstream::beg); 
     std::string first128((std::istreambuf_iterator<char>(ifs)), 
          (std::istreambuf_iterator<char>(ifs))+128); 

     std::cout << first128 << std::endl; 

    // read last 128 bytes into a string 
     ifs.seekg(-128,std::ifstream::end); 
     std::string last128((std::istreambuf_iterator<char>(ifs)), 
          std::istreambuf_iterator<char>()); 

     std::cout << last128 << std::endl; 

     return 0; 
    } 

    return 1; 
} 
+0

Как насчет istream :: readsome? – Chubsdad

+0

read/readsome работает только на char * s, и вы не можете получить char * (только const char *) из строкового типа, поэтому вы не можете напрямую читать строковый тип. –

ответ

1
char buffer[129]; 
ifs.read (buffer,128); 
buffer[128] = '\0'; 
first128 = buffer; 

Как об этом потом:

template <typename Itr, typename Out> 
void copy_n(Itr it, size_t count, Out out) 
{ 
    for(size_t i=0;i<count;++i) 
     out = *it++; 
} 

... 

std::string first128; 
std::istreambuf_iterator<char> it(ifs); 
copy_n(it, 128, 
    std::back_inserter<std::string>(first128)); 
+0

байт waster! char buffer [128]; ifs.read (buffer, 128); std :: string first128 (buffer, 128); Но на самом деле я хочу сделать это как можно чище. Ответы без угловых скобок не должны применяться! –

+0

@Southern Hospitality: Я отредактировал, чтобы включить другую версию. – ngoozeff

+0

Я думаю, что первый ответ прекрасен. Вы хотите перейти в строку, просто создайте std :: string размером 128 и передайте это как буфер для чтения. Думая, что это не чисто, говорится, что стандартная библиотека как-то нечиста. –

0

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

std::vector<char> buffer(128); // create a buffer 
ifs.read(&buffer[0], buffer.size()); // read to buffer 
std::string first128(buffer.begin(), buffer.end()); // copy from vector 

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

Кстати, я подозреваю, что реализация, которую вы пытались, будет под обложкой выполнять различные промежуточные буферизации (возможно, некоторые в ядре, некоторые в библиотеке), а также перераспределение и копирование строки несколько раз по мере его роста.

Еще одна идея: вам действительно нужен результат в стандартной строке? Вы можете просто работать с вектором - избегая последнего шага копирования в строку. Или, если вы чувствуете себя авантюрно, вы можете создать свой собственный класс строк, который делает, чтобы вы могли открыть внутренний буфер так же, как это делает вектор.

+0

Будет ли std :: string предоставлять доступ для записи в смежный буфер в C++ 0x? – nobar

+0

вектор char для буфера veeeery плохая идея, очень неэффективна. – Alecs

+0

@Alecs: Не могли бы вы немного разобраться? Вы имеете в виду, что это не сработает, или просто это не самый эффективный метод? – nobar

0

Вот у меня есть некоторые исследования над streambuffer, читать непосредственно в строку из IStream конструктором:

class mystringbuf : public std::stringbuf 
{ 
public: 
    explicit mystringbuf(std::istream& istr, size_t n, 
         std::ios_base::openmode __mode = std::ios_base::in) 
    { 
     _M_string.resize(n); 
     std::stringbuf::_M_stringbuf_init(__mode); 
     istr.read(gptr(), n); 
    } 
public: 
    std::stringbuf::char_type* gptr() const 
    { 
     return std::stringbuf::gptr(); 
    } 
    std::string& str_ref(){ 
     return _M_string; 
    } 
}; 
std::ostream& operator << (std::ostream& ostr, mystringbuf& buf){ 
    ostr << buf.str_ref(); 
    return ostr; 
} 

Пример использования:

using std::cout; 
using std::endl; 

int main() 
{ 
    std::stringbuf buffer;   // empty buffer 
    buffer.str("abc def ABC DEF "); // not empty now 
    std::istream is (&buffer);  // associate stream buffer to stream 
    mystringbuf data(is, 10);  // read 10 bytes 
    cout << "data=" << data << endl; 
    return 0; 
} 

Выход:

data=abc def AB 

Пожалуйста перешлите меня, если я где-то ошибся.