C++ Reading Files - c++

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];

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;
}

How to read an array of complex numbers from a text file in C++

As a learner in c++, I decided to play with complex numbers, using the standard library. Now I need to read and write an array of complex from/to text files. This works simply for writing, without supplemental tricks :
void dump(const char *filename){
ofstream result;
result.open (filename);
for(int k=0;k<15;k++){
result<< outputs[k] <<endl;
}
result.close();
}
The data are parenthesized and written line by line looking like : (real,im)...
Now, I guess reading (and loading an array of complex) should be as trivial as reading. However, despite my research, I have not found the right way to do that.
My first attempt was naive :
void readfile(const char *filename){
string line;
ifstream myfile (filename);
if (myfile.is_open())
{
int k=0;
while ( getline (myfile,line) ){
k++;
cout << line << endl;
inputs[k]= (complex<float>) line; //naive !
}
myfile.close();
}
else cout << "Unable to open file";
}
Is there a way to do that simply (without a string parser ) ?
Assuming you have an operator<< for your_complex_type (as has been mentioned, std::complex provides one), you can use an istream_iterator:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream input( "numbers.txt" );
std::vector<your_complex_type> buffer{
std::istream_iterator<your_complex_type>(input),
std::istream_iterator<your_complex_type>() };
}
This will read all numbers in the file and store them in an std::vector<your_complex_type>.
Edit about your comment
If you know the number of elements you will read up-front, you can optimize this as follows:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream input( "numbers.txt" );
std::vector<your_complex_type> buffer;
buffer.reserve(expected_number_of_entries);
std::copy(std::istream_iterator<your_complex_type>(input),
std::istream_iterator<your_complex_type>(),
std::back_inserter(buffer));
}
std::vector::reserve will make the vector reserve enough memory to store the specified number of elements. This will remove unnecessary reallocations.
You can also use similar code to write your numbers to a file:
std::vector<your_complex_type> numbers; // assume this is filled
std::ofstream output{ "numbers.txt" };
std::copy(std::begin(numbers), std::end(numbers),
std::ostream_iterator<your_complex_type>(output, '\n') );
C++ version:
std::complex<int> c;
std::ifstream fin("filename");
fin>>c;
C version:
int a,b;
FILE *fin=fopen("filename","r");
fscanf(fin,"(%d,%d)\n",&a,&b);
C++ read multiple lines with multiple complex values on each line
#include <stdio.h>
#include <fstream>
#include <complex>
#include <iostream>
#include <sstream>
int main ()
{
std::complex<int> c;
std::ifstream fin("test.in");
std::string line;
std::vector<std::complex<int> > vec;
vec.reserve(10000000);
while(std::getline(fin,line))
{
std::stringstream stream(line);
while(stream>>c)
{
vec.push_back(c);
}
}
return 0;
}

C++: Grab every character of a file ignoring newlines and whitespace

So this seems like such a simple problem but i am struggling with it. I have a big file that i want to just go through and put every char in the file into a char array. My problem is i dont know how to deal with the newlines and any whitespace. is there a way to just go through the file and grab all of the chars, skip over newlines, and put them in an array?
Yes, i have searched around on google but with no luck.
Here is how it would be trivially done in C. I am sure it can be done using the C++ interface as well, but the C library is part of C++ too.
#include <stdio.h>
#include <ctype.h>
FILE *f = fopen ("filename", "r");
if (!f)
error ...
char array [BIGENOUGH];
int index = 0;
while (!feof (f))
{
char c = fgetc (f);
if (!isspace (c))
array [index++] = c;
}
fclose (f):
The preferred method would be to use the standard library string. Example of removing whitespace from a string here. How to read from a file line-by-line here.
Example code:
fstream file;
file.open("test.txt",ios::in);
while ( !file.eof() ) {
string str;
file >> str;
remove_if(str.begin(), str.end(), isspace);
str.erase(remove_if(str.begin(), str.end(), isspace), str.end());
//save str here
}
file.close();
remove_if sample implementation:
template<typename T, typename P>
T remove_if(T beg, T end, P pred)
{
T dest = beg;
for (T itr = beg;itr != end; ++itr)
if (!pred(*itr))
*(dest++) = *itr;
return dest;
}
This code is untested.
The key to doing what you want in C++ is to take advantage of the formatted input operations. You want to ignore whitespace; the formatted input methods do exactly that.
Here is one way, using the canonical C++ input loop:
#include <fstream>
#include <iostream>
int main () {
std::ifstream inFile("input.txt");
char c;
std::string result;
while(inFile >> c)
result.push_back(c);
std::cout << result;
}
I prefer standard algorithms to hand-crafted loops. Here is one way to do it in C++, using std::copy. Note that this way and the first way are nearly identical.
#include <vector>
#include <fstream>
#include <iostream>
#include <iterator>
#include <algorithm>
int main () {
std::ifstream inFile("input.txt");
std::string result;
std::copy(std::istream_iterator<char>(inFile),
std::istream_iterator<char>(),
std::back_inserter(result));
std::cout << result;
}
Another way, this time with std::accumulate. std::accumulate uses operator+ instead of push_back, so we can read the file in a string at a time.
#include <vector>
#include <fstream>
#include <numeric>
#include <iostream>
#include <iterator>
#include <algorithm>
int main () {
std::ifstream inFile("input.txt");
std::string result =
std::accumulate(
std::istream_iterator<std::string>(inFile),
std::istream_iterator<std::string>(),
std::string());
std::cout << result;
}
fgets allows you to read until a newline (notice that the newline still exists in the destination buffer, so make sure to overwrite it with '\0').
Read the file line by line, and each time concatenate your output with the previous output.

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?

Is there a one-liner to read in a file to a string in C++?

I need a quick easy way to get a string from a file in standard C++. I can write my own, but just want to know if there is already a standard way, in C++.
Equivalent of this if you know Cocoa:
NSString *string = [NSString stringWithContentsOfFile:file];
We can do it but it's a long line :
#include<fstream>
#include<iostream>
#include<iterator>
#include<string>
using namespace std;
int main()
{
// The one-liner
string fileContents(istreambuf_iterator<char>(ifstream("filename.txt")), istreambuf_iterator<char>());
// Check result
cout << fileContents;
}
Edited : use "istreambuf_iterator" instead of "istream_iterator"
Its almost possible with an istream_iterator (3 lines!)
#include <iostream>
#include <fstream>
#include <iterator>
#include <string>
#include <sstream>
using namespace std;
int main()
{
ifstream file("filename.txt");
string fileContents;
copy(istreambuf_iterator<char>(file),
istreambuf_iterator<char>(),
back_inserter(fileContents));
}
Edited - got rid of intermediate string stream, now copies straight into the string, and now using istreambuf_iterator, which ignores whitespace (thanks Martin York for your comment).
The standard C++ library doesn't provide a function to do this.
Best I can do is 5 lines:
#include <fstream>
#include <vector>
using namespace std;
ifstream f("filename.txt");
f.seekg(0, ios::end);
vector<char> buffer(f.tellg());
f.seekg(0, ios::beg);
f.read(&buffer[0], buffer.size());
How about:
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
int main( void )
{
stringstream os(stringstream::out);
os << ifstream("filename.txt").rdbuf();
string s(os.str());
cout << s << endl;
}
If you do it like the following (but properly wrapped up nicely unlike below), you can read in the file without worrying about a 0x1A byte in the file (for example) cutting the reading of the file short. The previously suggested methods will choke on a 0x1A (for example) in a file.
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstdlib>
using namespace std;
int main() {
FILE* in = fopen("filename.txt", "rb");
if (in == NULL) {
return EXIT_FAILURE;
}
if (fseek(in, 0, SEEK_END) != 0) {
fclose(in);
return EXIT_FAILURE;
}
const long filesize = ftell(in);
if (filesize == -1) {
fclose(in);
return EXIT_FAILURE;
}
vector<unsigned char> buffer(filesize);
if (fseek(in, 0, SEEK_SET) != 0 || fread(&buffer[0], sizeof(buffer[0]), buffer.size(), in) != buffer.size() || ferror(in) != 0) {
fclose(in);
return EXIT_FAILURE;
}
fclose(in);
}
But, yeh, it's not an already-implemented 1-liner though.
Edit: 0x1A wasn't a good example as ios_base::binary will cover that. However, even then C++ streams often give me trouble when reading in png files all at once with .read(). Using the C way works better. Just can't remember a good example to show why. It was probably with .read()ing a binary file in blocks in a loop instead that can be a problem with C++ streams. So, disregard this post.
std::string temp, file; std::ifstream if(filename); while(getline(if, temp)) file += temp;
It's not a short or single-statement line, but it is one line and it's really not that bad.