Copying a file with streams in C++ - c++

I wrote this in an attempt to copy the contents of one text file into another based on command-line arguments:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
if(argc != 3) {
cout << "invalid args!";
return 0;
}
fstream op(argv[1], ios::in);
vector<string> list;
string line;
while(!op.end)
op >> line;
list.push_back(line);
op.close();
op.open(argv[2], ios::out);
for(unsigned int i = 0; i < list.size(); i++)
op << list[i];
op.close();
return 0;
}
It does not produce any syntax errors, but a logic error is evident: there is no output.
So apart from the lack of error-checking and the fact that there are more efficient ways to do this, what is wrong with my code? That is, why will it not copy file with name argv[1] to a file named argv[2]?

You have a bug: your while loop's body is not enclosed in {}, so only op >> line is executed until the file is read completely, and the last value of line is then pushed onto the vector.
EDIT: By the way, that's a very good illustration for why you should let your editor do your code indentation; the way your while loop looked, it was hard to spot this mistake.

There are several issues in your code:
With streams you shall not loop on end or eof (have a look at the many SO questions/answers about this).
The enclosing {} issue that Marcus revealed
You are not reading lines but words (operator>> uses spaces as separators) and squizing the whitespaces in the output.
Here how to tackle all this:
while(getline(op, line))
list.push_back(line);
and of course for the output: op << list[i]<<endl;

For one-to-one copy, you may also consider the following code - handles binary data, uses less memory and is shorter:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
if (argc < 3)
return 1;
fstream s(argv[1], ios::in);
fstream d(argv[2], ios::out);
copy(
istreambuf_iterator<char>(s)
, istreambuf_iterator<char>()
, ostreambuf_iterator<char>(d));
return 0;
}

Related

How to write words from a file to an array [duplicate]

This question already has answers here:
Read file line by line using ifstream in C++
(8 answers)
Closed 3 years ago.
I cant write a words from a file to an array.
I have tried to use char and strings, but i have problem with both of them.
FILE *file = fopen("films.txt", "r");
string FILMS[500];
while (!feof(file))
{
fscanf(file, "%s", FILMS);
//fgets(FILMS, 500, file);
}
I expect that in each cell there will be a word.
Use the C++ classes and functions to make it easier. Instead of a fixed C style array of exactly 500 films, use a std::vector<std::string>> that will grow dynamically when you put film titles in it.
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> get_films() {
std::ifstream file("films.txt");
std::vector<std::string> FILMS;
if(file) { // check that the file was opened ok
std::string line;
// read until getline returns file in a failed/eof state
while(std::getline(file, line)) {
// move line into the FILMS vector
FILMS.emplace_back(std::move(line));
// make sure line is in a specified state again
line.clear();
}
}
return FILMS;
} // an fstream is automatically closed when it goes out of scope
int main() {
auto FILMS = get_films();
std::cout << "Read " << FILMS.size() << " film titles\n";
for(const std::string& film : FILMS) {
std::cout << film << "\n";
}
}
As I'm not sure why you tried using c style arrays and files, I posted a 'not too elegant' solution like that one, too, hoping it might help. You could always try to make it more dynamic with some malloc (or new), but I sticked with the easy solution for now.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
void readcpp(const char* fname, std::vector<std::string>& data)
{
std::ifstream file_in(fname, std::ios::in);
if (file_in.is_open())
{
std::string film;
while (std::getline(file_in, film))
{
data.push_back(film);
}
file_in.close();
}
else std::cerr << "file cant be opened" << std::endl;
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
void readc(const char* fname, char data[500][500])
{
FILE* file_in = fopen(fname, "r");
if (file_in)
{
char film[500];
for (unsigned int i = 0; fgets(film, 500, file_in) && i < 500; i++)
{
memcpy(data + i, film, 500);
}
fclose(file_in);
}
else fprintf(stderr, "file cant be opened\n");
}
int main()
{
const char* fname = "films.txt";
char cFilms[500][500];
std::vector<std::string> cppFilms;
readc(fname, cFilms);
readcpp(fname, cppFilms);
return 0;
}
And as the others mentioned before, do not use feof or for that matter, ifstream's eof member function either, for checking wheter you reached the end of file, as it may be unsafe.
Hm, I see a lot of code in answers.
The usage of algorithm will drastically reduce coding effort.
Additionally it is a "more modern" C++ approach.
The OP said, that he want to have words in some array. OK.
So we will use a std::vector<std::string> for storing those words. As you can see in cppreference, the std::vector has many different constructors. We will use number 4, the range constructor.
This will construct the vector with a range of similar data. The similar data in our case are words or std::string. And we would like to read the complete range of the file, beginning with the first word and ending with the last word in the file.
For iterating over ranges, we use iterators. And for iterating of data in files, we use the std::istream_iterator. We tell this function what we want to read as template parameter, in our case a std::string. Then we tell it, from which file to read.
Since we do not have files on SO, I use a std::istringstream. But that's the same reading from a std::ifstream. If you have na open file stream, then you can hand it over to the std::istream_iterator.
And the result of using this C++ algorithms is that we read the complete file into the vector by just defining the varaible with its constructer as a one-liner.
We do similar for the debug output.
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <sstream>
std::istringstream filmFile{ R"(Film1 Film2
Film3 Film4 Film5
Film6
)" };
int main()
{
// Define the variable films and use its range constructor
std::vector<std::string> films{ std::istream_iterator<std::string>(filmFile), std::istream_iterator<std::string>() };
// For debug pruposes, show result on console
std::copy(films.begin(), films.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}

C++ Parsing a CSV file into vector of vectors: Loosing string 1st character

I am reading a CSV file into vector of string vectors. I have written code below.
#include<iostream>
#include<fstream>
#include<string>
#include <vector>
#include <fstream>
#include <cmath>
#include <sstream>
using namespace std;
int main()
{
ifstream mesh;
mesh.open("mesh_reference.csv");
vector<vector<string> > point_coordinates;
string line, word;
while (getline(mesh,line))
{
stringstream ss(line);
vector<string> row;
while (getline(ss, word, ','))
{
row.push_back(word);
}
point_coordinates.push_back(row);
}
for(int i=0; i<point_coordinates.size(); i++)
{
for(int j=0; j<3; j++)
cout<<point_coordinates[i][j]<<" ";
cout<<endl;
}
return 0;
}
When I print out the vector of vectors, I see that I am loosing the first character of Element at 0 position in the vector row. Basically, point_coordinates[0][0] is displaying 0.0001 while the string is supposed to be -0.0001. I am not able to understand the reason for the same. Kindly help.
A typical output line is
.0131 -0.019430324 0.051801
Whereas the CSV data is
0.0131,-0.019430324,0.051801
SAMPLE CSV DATA FROM FILE
NODES__X,NODES__Y,NODES__Z
0.0131,-0.019430324,0.051801
0.0131,-0.019430324,0.06699588
0.0131,-0.018630324,0.06699588
0.0131,-0.018630324,0.051801
0.0131,-0.017630324,0.050801
0.0131,-0.017630324,0.050001
0.0149,-0.017630324,0.050001
0.0149,-0.019430324,0.051801
Although the problem is already solved, I would like to show you a solution using some modern C++ algorithms and eliminating minor issues.
Do not use using namespace std;. You should not do this
Ne need for a separate file.open. The std::ifstream constructor will open the file for you. And the destructor will close it
Check if the file could be opened. The ifstreams ! operator is overloaded. So you can do a boolean check
Do not use int in for loops where you compare against .size(). Use ````size_t instead
Always initialize all variables, even if there is an assignement in the next line
For tokenizing you should use std::sregex_token_iterator. It has exactly been designed for this purpose
In modern C++ you are encouraged to use algorithms
Please see an improved version of your code below:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <regex>
const std::regex comma(",");
int main()
{
// Open source file.
std::ifstream mesh("r:\\mesh_reference.csv");
// Here we will store the result
std::vector<std::vector<std::string>> point_coordinates;
// We want to read all lines of the file
std::string line{};
while (mesh && getline(mesh, line)) {
// Tokenize the line and store result in vector. Use range constructor of std::vector
std::vector<std::string> row{ std::sregex_token_iterator(line.begin(),line.end(),comma,-1), std::sregex_token_iterator() };
point_coordinates.push_back(row);
}
// Print result. Go through all lines and then copy line elements to std::cout
std::for_each(point_coordinates.begin(), point_coordinates.end(), [](std::vector<std::string> & vs) {
std::copy(vs.begin(), vs.end(), std::ostream_iterator<std::string>(std::cout, " ")); std::cout << "\n"; });
return 0;
}
Please consider, if you may want to use such an approach in the future

How to read from an input stream into a file stream?

I am trying to bind input stream with a file stream , I hope that input something from input stream and then automatic flush to the file stream
It does not work...I enter something from keyboard , outfile is still empty
#include <iostream>
#include <fstream>
#include <stdexcept>
using namespace std;
int main(int argc, char const *argv[])
{
ofstream outfile("outfile" , ofstream::app | ofstream::out);
if(!outfile)
throw runtime_error("Open the file error");
ostream * old_tie = cin.tie();//get old tie
cin.tie(0);//unbind from old tie
cin.tie(&outfile);//bind new ostream
string temp;
while(cin >> temp)
{
if(temp == ".")//stop input
break;
}
cin.tie(0);
cin.tie(old_tie);// recovery old tie
return 0;
}
Your program is too complicated and is misusing tie(). Try the following:
#include <iostream>
#include <fstream>
int main() {
using namespace std;
ofstream outfile("outfile" , ofstream::app | ofstream::out);
if(!outfile) {
cerr << "Open the file error";
return 1;
}
char data(0);
while(data != '.') {
cin.get(data);
cin.clear(); // Prevents EOF errors;
outfile << data;
}
return 0;
}
It reads char by char until it finds a .
Errors:
why make throw exception if you don't catch it...
close file please
do you put data from file to temp and go through it to find "." and
end program?
Why do you use pointer for old_tie use it for the first ofstream file
like this ofstream * file.
fix if statement and break
include string library -- //This might solve your problem
what is filename??
is tie(0) function to unbind?
//EDIT
Explanation:
once you find first period with find_first_of function you create a substr and copy it into outfile. The Solution is so efficent and works every time. The logic is as simple as it can get. Don't use unnecessary functions and initialize unnecessary variables because it is more complex and more prone to errors when you have too many variables.
Solution: - No need for cin.tie()
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
ofstream outfile("outfile" , ofstream::app | ofstream::out);
string s;
getline(cin, s);
int i = s.find_first_of(".");
if(i!=std::string::npos)
{
s = s.substr(0, i);
outfile << s;
}
else
{
cout << "No periods found" << endl;
}
}
Compiled code - http://ideone.com/ooj1ej
If this needs explanation please ask questions in comments below.

Most Compact Way to Count Number of Lines in a File in C++

What's the most compact way to compute the number of lines of a file?
I need this information to create/initialize a matrix data structure.
Later I have to go through the file again and store the information inside a matrix.
Update: Based on Dave Gamble's. But why this doesn't compile?
Note that the file could be very large. So I try to avoid using container
to save memory.
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
int main ( int arg_count, char *arg_vec[] ) {
if (arg_count !=2 ) {
cerr << "expected one argument" << endl;
return EXIT_FAILURE;
}
string line;
ifstream myfile (arg_vec[1]);
FILE *f=fopen(myfile,"rb");
int c=0,b;
while ((b=fgetc(f))!=EOF) c+=(b==10)?1:0;
fseek(f,0,SEEK_SET);
return 0;
}
I think this might do it...
std::ifstream file(f);
int n = std::count(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), '\n') + 1;
If the reason you need to "go back again" is because you cannot continue without the size, try re-ordering your setup.
That is, read through the file, storing each line in a std::vector<string> or something. Then you have the size, along with the lines in the file:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main(void)
{
std::fstream file("main.cpp");
std::vector<std::string> fileData;
// read in each line
std::string dummy;
while (getline(file, dummy))
{
fileData.push_back(dummy);
}
// and size is available, along with the file
// being in memory (faster than hard drive)
size_t fileLines = fileData.size();
std::cout << "Number of lines: " << fileLines << std::endl;
}
Here is a solution without the container:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main(void)
{
std::fstream file("main.cpp");
size_t fileLines = 0;
// read in each line
std::string dummy;
while (getline(file, dummy))
{
++fileLines;
}
std::cout << "Number of lines: " << fileLines << std::endl;
}
Though I doubt that's the most efficient way. The benefit of this method was the ability to store the lines in memory as you went.
FILE *f=fopen(filename,"rb");
int c=0,b;while ((b=fgetc(f))!=EOF) c+=(b==10)?1:0;fseek(f,0,SEEK_SET);
Answer in c.
That kind of compact?
#include <stdlib.h>
int main(void) { system("wc -l plainfile.txt"); }
Count the number of instances of '\n'. This works for *nix (\n) and DOS/Windows (\r\n) line endings, but not for old-skool Mac (System 9 or maybe before that), which used just \r. I've never seen a case come up with just \r as line endings, so I wouldn't worry about it unless you know it's going to be an issue.
Edit: If your input is not ASCII, then you could run into encoding problems as well. What's your input look like?

C++ Reading Files

What is the minimum code required to read a file and assign its contents to a string in c++?
I did read a lot of tutorials that worked but they were all different in a way so i am trying to see why, so if you could please include some explanatory comments that would be great.
Related: What is the best way to read an entire file into a std::string in C++?
#include <fstream>
#include <string>
int main()
{
std::ifstream file("myfile.txt"); // open the file
std::string line, whole_file;
// Read one line at a time from 'file' and store the result
// in the string called 'line'.
while (std::getline(file, line))
{
// Append each line together so the entire file will
// be in one string.
whole_file += line;
whole_file += '\n';
}
return 0;
// 'file' is closed automatically when the object goes out of scope.
}
A couple of things to note here. getline() returns a reference to the stream object, which fails the while-test if anything bad happens or if you reach the end of the file. Also, the trailing newline is not included in the string, so you have to append it manually.
The shortest code: (not effecient)
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <fstream>
int main()
{
std::ifstream f("plop");
std::string buffer;
std::copy(std::istreambuf_iterator<char>(f),
std::istreambuf_iterator<char>(),
std::back_inserter(buffer));
}
How I would probably do it:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <fstream>
int main()
{
// Find the size of the file
std::ifstream file("Plop");
file.seekg(0,std::ios_base::end);
std::streampos size = file.tellg();
// Read the file in one go.
file.seekg(0);
std::vector<char> buffer(size); // pre-szie the vector.
file.read(&buffer[0],size);
// or
// Until the next version of the standard I don't think string gurantees contigious storage.
// But all the current versions I know do use continious storage so it should workd.
file.seekg(0);
std::string buffer1(size);
file.read(&buffer1[0],size);
}
I'm not seeing as much:
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main() {
ifstream ifs("filename");
stringstream ss;
ss << ifs.rdbuf();
string s = ss.str();
}
... as I'd expect. You'd want some error-checking too.
Konrad Rudolph gave this as the answer to the "related question" linked above. I suppose this isn't a duplicate, since this asks for the shortest code, but the answer is the same either way. So I repost it here as wiki.
I am reading a word from each line.
#include<fstream>
#include<string>
using namespace std;
int main(int argc, char **argv)
{
fstream inFile;
string str;
while(!inFile.eof())
{
inFile.open("file.txt");
infile>>str;
}
inFile.close();
return 0;
}
This is longer than the short solutions, but is possibly slightly more efficient as it does a bit less copying - I haven't done any timing comparisons though:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;;
unsigned int FileRead( istream & is, vector <char> & buff ) {
is.read( &buff[0], buff.size() );
return is.gcount();
}
int main() {
ifstream ifs( "afile.dat", ios::binary );
const unsigned int BUFSIZE = 64 * 1024;
std::vector <char> buffer( BUFSIZE );
unsigned int n;
string s;
while( n = FileRead( ifs, buffer ) ) {
s.append( &buffer[0], n );
}
cout << s;
}
If you know that your file contains text, then you can use STLSoft's platformstl::memory_mapped_file:
platformstl::memory_mapped_file file("your-file-name");
std::string contents(static_cast<char const*>(file.memory()), file.size());
or
platformstl::memory_mapped_file file("your-file-name");
std::wstring contents(static_cast<wchar_t const*>(file.memory()),
file.size() / sizeof(wchar_t));
On WIndows, that will leave your string containing \r\n sequences, so you could instead use the winstl::load_text_file() function:
std::string contents;
winstl::load_text_file("your-file-name", contents);
If you want it loaded into a collection of lines, then use platformstl::read_lines():
platformstl::basic_file_lines<char> lines("your-file-name");
size_t n = lines.size();
std::string line3 = lines[3];