If I want to copy the contents of a file to a vector, I can do it like that:
std::ifstream file("path_to_file");
std::vector<char> buffer(std::istream_iterator<char>(file),
std::istream_iterator<char>());
My question is, how would I do this if I want to copy only the first n
chars?
Edit I could write my own version of 开发者_开发问答copy
, but is there a way to do this using only existing components?
As Alexander points out, the fastest way would be
std::vector<char> buffer(n);
file.read(&buffer[0], n);
In C++0x, you can use buffer.data()
instead of &buffer[0]
; the latter has undefined behavior if n == 0
.
As was noted by Steve, this would need copy_n()
, which, due to an oversight, isn't in the current standard library, but will be in C++1x. You can implement one yourself easily, here's one I believe to be correct:
template<class InIt, class OutIt>
OutIt copy_n(InIt src, OutIt dest, size_t n)
{
if (!n) return dest;
*dest = *src;
while (--n)
*++dest = *++src;
return ++dest;
}
Note that std::copy_n()
presumes the input iterator to be able to deliver n
objects. When reading from a file, this could be problematic.
Absent of std::copy_n()
, you could use std::generate_n
.
template< typename InIt >
struct input_generator {
typedef std::iterator_traits<InIt>::value_type value_type;
input_generator(InIt begin, InIt end) begin_(begin), end_(end) {}
value_type operator()()
{
assert(it_ != end);
return *it_++;
}
Init begin_;
Init end_;
};
std::vector<char> buffer;
buffer.reserve(42);
std::generate_n( std::back_inserter(buffer)
, 42
, input_generator(std::istream_iterator<char>(file))
, input_generator(std::istream_iterator<char>()) );
However, I don't see this as an advantage over reading directly from the file as avakar showed.
The "STL way" is to use copy_n
, which is in the STL but not the C++ standard.
char *buffer = new char[n];
file.read(buffer,n);
std::vector<char> myVector
for (int i=0;i<n;i++) myVector.push_back(buffer[i]);
delete [] buffer;
// myVector now holds the first n bytes of file.
It may not be the prettiest or quickest way, but it is how I would do it.
Credit due to @sbi, I forgot about generate_n
.
The streambuf
inside file
has a function snextc
which returns the next character, qualifying it as a generator function, once its implicit this
argument is bound.
generate_n( back_inserter( buffer ), 42,
tr1::bind( tr1::mem_fn( &streambuf::snextc ), file.rdbuf() ) );
For vector
, just read directly. This is good for deque
or whatever.
精彩评论