Reading and Writing a Std::Vector into a File Correctly with Iterators

Reading and writing a std::vector into a file correctly with iterators

The file is not ready to be read by the time the second copy is called. (Thanks to Piotr Skotnicki for his answer in the comments)

A call to flush allows the program to work:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <fstream>

int main()
{
std::string path("numbersfile");

std::vector<int> myVector{1,16,32,64};
std::vector<int> newVector{};

std::ofstream FILE(path,std::ios::out | std::ofstream::binary);
std::copy(myVector.begin(),myVector.end(),std::ostreambuf_iterator<char>(FILE));
FILE.flush(); // required here

std::ifstream INFILE(path,std::ios::in | std::ifstream::binary);
std::istreambuf_iterator<char> iter(INFILE);
//std::copy(iter.begin(),iter.end(),std::back_inserter(newVector)); //this doesn't compile
std::copy(iter,std::istreambuf_iterator<char>{},std::back_inserter(newVector)); // this leaves newVector empty
return 0;
}

The ofstream is still in scope when the ifstream is created. Had the ofstream's destructor been called then the file would also have been ready for the ifstream. In the following program the ifstream is automatically destructed:

#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>

std::string filename("numbersfile");

std::vector<double> myVector{1.342, 16.33, 32.1, 12364};

void write_vector_to_file(const std::vector<double>& myVector, std::string filename);
std::vector<double> read_vector_from_file(std::string filename);

int main()
{
write_vector_to_file(myVector, filename);
auto newVector{read_vector_from_file(filename)};
return 0;
}

void write_vector_to_file(const std::vector<double>& myVector, std::string filename)
{
std::ofstream ofs(filename, std::ios::out | std::ofstream::binary);
std::ostream_iterator<double> osi{ofs," "};
std::copy(myVector.begin(), myVector.end(), osi);
}

std::vector<double> read_vector_from_file(std::string filename)
{
std::vector<double> newVector{};
std::ifstream ifs(filename, std::ios::in | std::ifstream::binary);
std::istream_iterator<double> iter{ifs};
std::istream_iterator<double> end{};
std::copy(iter, end, std::back_inserter(newVector));
return newVector;
}

Reading and writing a std::vector into a file correctly

Try using an ostream_iterator/ostreambuf_iterator, istream_iterator/istreambuf_iterator, and the STL copy methods:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

#include <fstream> // looks like we need this too (edit by π)

std::string path("/some/path/here");

const int DIM = 6;
int array[DIM] = {1,2,3,4,5,6};
std::vector<int> myVector(array, array + DIM);
std::vector<int> newVector;

std::ofstream FILE(path, std::ios::out | std::ofstream::binary);
std::copy(myVector.begin(), myVector.end(), std::ostreambuf_iterator<char>(FILE));

std::ifstream INFILE(path, std::ios::in | std::ifstream::binary);
std::istreambuf_iterator iter(INFILE);
std::copy(iter.begin(), iter.end(), std::back_inserter(newVector));

Iterate through a C++ Vector using a 'for' loop

Is there any reason I don't see this in C++? Is it bad practice?

No. It is not a bad practice, but the following approach renders your code certain flexibility.

Usually, pre-C++11 the code for iterating over container elements uses iterators, something like:

std::vector<int>::iterator it = vector.begin();

This is because it makes the code more flexible.

All standard library containers support and provide iterators. If at a later point of development you need to switch to another container, then this code does not need to be changed.

Note: Writing code which works with every possible standard library container is not as easy as it might seem to be.

c++ read and write numeric numbers from text file using vector

std::istream_iterators are different from 'regular' iterators. Stream iterators are single-pass. You can't use the same iterator twice - because every increment reads data from the stream, and data read from the stream is gone from the stream. But this is what you are trying to do:

vector<int> data(start, end);
for(auto it=start; it!=end; ++it)

Here iterator start is used twice - first to populate the vector, than to iterate over stream.

To fix your problem, iterate over vector in the loop, not the (used up) stream.

Using Insert Iterators when reading from file

C++ streams are not compatible with C stdio streams. In other words, you can't use C++ iterators with FILE* or fread. However, if you use the C++ std::fstream facilities along with istream_iterator, you can use an insertion iterator to insert into a C++ container.

Assuming you have an input file "input.txt" which contains ASCII text numbers separated by whitespace, you can do:

#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>

int main()
{
std::ifstream ifs("input.txt");
std::vector<int> vec;
// read in the numbers from disk
std::copy(std::istream_iterator<int>(ifs), std::istream_iterator<int>(), std::back_inserter(vec));
// now output the integers
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, "\n"));
}

Reading binary files and using stream iterators correctly

1- ostreambuf_iterator out_it (FILE);

error: invalid conversion from ‘void*’ to ‘std::ostreambuf_iterator::streambuf_type* {aka std::basic_streambuf >*}’ [-fpermissive]

std::ostreambuf_iterator takes as template parameter the character type of the stream, NOT the type you want to convert to. Try:

std::ostreambuf_iterator<char> out_it(FILE);

Ditto for #4.


EDIT: Let's solve your big problem instead of your small ones:

Don't bother with iterators, just write the vector data out all in one go:

void Write_File_Matrix(const char *Path)
{
float myWidth = 0;
float myHeight = 0;
vector<float> v;
v[0] = 1;
v[1] = 2;
v[2] = 3;
ofstream outFILE(Path, ios::out | ofstream::binary);
outFILE.write(reinterpret_cast<const char *>(&myWidth), sizeof(float));
outFILE.write(reinterpret_cast<const char *>(&myHeight), sizeof(float));
outFile.write(reinterpret_cast<const char *>(&v[0]), v.size()*sizeof(float));
}

Reading, however, still needs to be one-piece-at-a-time.

void Read_File_Matrix(const char *Path)
{
float myWidth = 0;
float myHeight = 0;
vector<float> v;

ifstream inFILE(Path, ios::in | ifstream::binary);

if(!inFILE)
{
cerr << "Cannot open the file" << endl;
exit(1);
}
inFILE.read(reinterpret_cast<char *>(&myWidth), sizeof(myWidth));
inFILE.read(reinterpret_cast<char *>(&myHeight), sizeof(myHeight));
float f;
while( inFILE.read(reinterpret_cast<char *>(&f), sizeof(f)))
v.push_back(f);
}

Efficient way of reading a file into an std::vectorchar?

The canonical form is this:

#include<iterator>
// ...

std::ifstream testFile("testfile", std::ios::binary);
std::vector<char> fileContents((std::istreambuf_iterator<char>(testFile)),
std::istreambuf_iterator<char>());

If you are worried about reallocations then reserve space in the vector:

#include<iterator>
// ...

std::ifstream testFile("testfile", std::ios::binary);
std::vector<char> fileContents;
fileContents.reserve(fileSize);
fileContents.assign(std::istreambuf_iterator<char>(testFile),
std::istreambuf_iterator<char>());

Vector iterator is not dereferencable, while try to read from file

You cannot simply overwrite the memory of a vector. That is pretty much guaranteed to corrupt your process.

Furthermore, you never assign anything to sit and yet expect it to contain something sensible.

You need to parse the data in Student.txt and use vector's member functions to fill it with sensible data. The assignment will probably tell you what the file looks like so that you can parse it.

How to read a file into vector in C++?

Your loop is wrong:

for (int i=0; i=((Main.size())-1); i++) {

Try this:

for (int i=0; i < Main.size(); i++) {

Also, a more idiomatic way of reading numbers into a vector and writing them to stdout is something along these lines:

#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
#include <algorithm> // for std::copy

int main()
{
std::ifstream is("numbers.txt");
std::istream_iterator<double> start(is), end;
std::vector<double> numbers(start, end);
std::cout << "Read " << numbers.size() << " numbers" << std::endl;

// print the numbers to stdout
std::cout << "numbers read in:\n";
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<double>(std::cout, " "));
std::cout << std::endl;

}

although you should check the status of the ifstream for read errors.



Related Topics



Leave a reply



Submit