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
The Fastest Way to Retrieve 16K Key-Value Pairs
Is Lambdification of a Concept an Improvement or Bad Practice
How to Implement Interfaces in C++
Compiling Code Containing Dynamic Parallelism Fails
Opencv Imshow Not Displaying Image in Osx
Create 2D Array Using Size from Parameters in C++
How to Profile Multi-Threaded C++ Application on Linux
Size of the Classes in Case of Virtual Inheritance
What Are Consequences of Forcing Qobject as a Parent of Qwidget
Is There Any Danger in Calling Free() or Delete Instead of Delete[]
What Changes Introduced in C++14 Can Potentially Break a Program Written in C++11
Why Does Rand() Return the Same Value Using Srand(Time(Null)) in This for Loop
Windows Media Foundation Recording Audio
How to Force the Use of Cmov in Gcc and VS