We can read a whole file into a string:
std::ifstream ifs(path);
assert(ifs.good());
std::string text(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>())
Once this code returned an empty string. How can I check that there were no errors during the reading?
UPD:
I've learned that if a file is being written (or just have been overwritten), then when I read the file, std::filesystem::file_size may return 0, and ifstream returns true from operator bool (on Windows). So the file is not available for some time, but I get no errors and I can't distinguish this case from a case of real empty file. So I have to read a file in a loop while its size is 0 for some time.
The easiest way to check whether the stream has errors is to use operator bool after every operation on streams.
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::string file_name{"data.txt"};
std::ifstream ifs(file_name);
if ( !ifs) // <---
std::cout << "Error: unable to open " << file_name << ".\n";
std::string text{ std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>() };
// ^ ^
if ( ifs ) // <--
std::cout << text << '\n';
else
std::cout << "An error occured while reading the file.\n";
}
Note that OP's snippet suffers from the Most Vexing Parse, which can be fixed using the list-initialization of the string.
Related
I've made a simple program. I'm reading a text file in the same folder as the program. The file only has one line: " v 1.0 2.0 3.0".
Problem:
When I initialize a stringstream instance ss with a string line, and I use the erase() function to try to remove the character 'v' from the string, it is not working. The MSVC consoles shows the same line of string:
If I remove the .erase(0,1) function, the output is the same.
How could this happen? It should remove the character v. I learn this through the OpenGL's obj loader tutorial, and they can remove it.
Code
#include <sstream>
#include <fstream>
#include <iostream>
int main()
{
std::ifstream filestream("textfile.txt", std::ios::in);
std::string line = "";
while (!filestream.eof())
{
std::getline(filestream, line);
std::cout <<"getline std::string "<< line.c_str()<<std::endl;
std::stringstream ss(line.erase(0,1));
std::cout << "stringstream: " << ss.str() << std::endl;
}
}
After some testing, I found the reason. I made a low level mistake.
I should use a text editor that can show all the hiden blank spaces.
It looks like that there is an empty character since the initializtion of stringstream ss.
And if I remove one more characters, then it is okay.
int main()
{
std::ifstream filestream("textfile.txt", std::ios::in);
std::string line;
while (!filestream.eof())
{
std::getline(filestream, line);
std::cout <<"getline std::string"<< line.c_str()<<std::endl;
std::stringstream ss(line.erase(0,2));
std::cout << "stringstream:" << ss.str() << std::endl;
}
}
Is it possible that book writer of the opengl book made a typo? They use
erase(0,1) for "v" for vertices data, and then use erase(0,2) for "f" for the face data
That is the mistake for not using a good text editor
Please can anybody help me? I'm a beginner and I have a hard assignment.
I need to write a c++ program that does the following :
Ask the user to enter two text file , the the first one contains a list of words in one column Regardless of their number , second one contains the text file ,like this:
//output
Enter the keywords file: keywords_file.txt
Enter the text file: text_file.txt
2.Search for the keywords from the keywords file in the text file
3.if the keyword exist the output =1 "true", if the keyword doesn't exist output =0 "false" ,like this :
system : 1 //its exist
book : 0 //its doesn't exist
Then output in new text file (ofstream)
I put the words in file each one on its own line because some of them are phrases I don't want to sprit them ,search them as one word , also the test file I want it to stay as complete text not separate words from each other so possibly I cant use "map" & "vector". I already tried them...so possibly I can consider that each word in the words file just a line and read them all , then search for them in the text file
i found this code here in the site but its need modifications , could any body help me ?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool CheckWord(char* filename, char* search)
{
int offset;
string line;
ifstream Myfile;
Myfile.open (filename);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile,line);
if ((offset = line.find(search, 0)) != string::npos)
{
cout << "found '" << search << "' in '" << line << "'" << endl;
Myfile.close();
return true;
}
else
{
cout << "Not found" << endl;
}
}
Myfile.close();
}
else
cout << "Unable to open this file." << endl;
return false;
}
int main ()
{
CheckWord("dictionary.txt", "need");
return 0;
}
The code that you found somewhere is really bad. You should not use it. Let me explain you why.
Most important, it does not fulfill any of your requirments. So, it is completely wrong for your purpose
There are design-, syntax- and semantic errors. It does not even compile on my machine
Examples: Do not use using namespace std; always use fully qualified names like std::string
Type of vearibe offset should be size_t. You compare it later to string::npos. So, type is wrong
The constructor of std::ifstream can open the file for you. So the call to open is not necessary
MyFile is not a class name. it should start with a lowercase character
Using is_open is not necessary. The bool operator for the iostreams is overloaded. So, you can simply write if (myFile)
while (!Myfile.eof()) is a semantic bug. It will not work as you think. Please find many many examples here on SO. Please write instead while (std::getline(myFile, line))
Explicit call to close is not necessary. The destructor of the stream will automatically close the file for you
Function should haveonly one exit point. There are 2 return statements.
cout << "Not found" << endl; can be replaced by std::cout << "Not found\n". But better would be to mention, what has been "not found"
Do not use char* for strings. Always use std::string instead.
Write many many comments and use meaningful variable names
You see. You should not use this code. It is really bad.
Then, next step, before you start any coding, you should anaylyse the requirements and then design a solution
So, obviously, you need to open 2 input files and one output files. If any of this open activities fail, then no need to open any other file. So, Let us do this sequentially. Open, check, if ok, then open next.
Then, because you want to compare words from a list to the contents of a complete text file, we should first and only once read the comlete text file. Then, we will read keyword by keyword and check, if it is in the text file data.
The we seacrh for the keyword and will show the result in the output file and, for debug purposes, also on std::cout.
Since you are new and have maybe restrictions regarding the usage of modern C++ and espcially the usage of the C++ STL, I will use simple C++ code.
Please see the following simple example.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
int main() {
// Give instructions to the user to enter the file name for the keywords file
std::cout << "Please enter the file name for the keywords file:\t ";
// Read the filename for the keywords file
std::string keywordFileNname;
std::cin >> keywordFileNname;
// Open the keywords file for reading
std::ifstream keyWordFileStream(keywordFileNname);
// Check, if that worked and continue only if OK
if (keyWordFileStream) {
// Next, we ant to have the text file name. Instruct use to give the filename for the text file
std::cout << "Please enter the file name for the text file: \t ";
// Read the file name of the text file
std::string textFileName;
std::cin >> textFileName;
// Open the text file for reading
std::ifstream textFileStream(textFileName);
// Check, if the text file could be opened and continue only, of OK
if (textFileStream) {
// Now, give instructions to the user to open the output file name
std::cout << "Please enter the file name for the output file: \t ";
// Read the filename for the output file
std::string outputFileName;
std::cin >> outputFileName;
// Open the output file stream
std::ofstream outputFileStream(outputFileName);
// Check, if the output file could be opened, If OK, continue
if (outputFileStream) {
// So, all files are open, we can start to work
// We will read the complete text file in one string
// This solution is not very good, but avoids more complex features
std::string textFileData;
char oneCHaracter;
while (textFileStream.get(oneCHaracter)) {
textFileData += oneCHaracter;
}
// So, now all text file has been read to one string.
// Next we will read keyword by keyowrd and search it in the text file
std::string keyWord;
while (keyWordFileStream >> keyWord) {
int exists = 0;
// Check, if the keyword is in the text file data
if (textFileData.find(keyWord) != std::string::npos) {
// Keyword found
exists = 1;
}
// Write result to output file
outputFileStream << std::right << std::setw(50) << keyWord << std::left << " --> " << exists << '\n';
// And write some debug output. You may delete this line if not needed
std::cout << std::right << std::setw(50) << keyWord << std::left << " --> " << exists << '\n';
}
}
else {
// output file could not be opened. Show error message
std::cerr << "\nError: Could not open output file '" << outputFileName << "'\n\n";
}
}
else {
// text file could not be opened. Show error message
std::cerr << "\nError: Could not open text file '" << textFileName << "'\n\n";
}
}
else {
// Keyword file could not be opened. Show error message
std::cerr << "\nError: Could not open key word file '" << keywordFileNname << "'\n\n";
}
return 0;
}
You can see that I always check the result of IO operations. That is very important.
There is of course also a more advanced and more modern C++ solution. To concentrate more on the essential task, I put all the file handling stuff in a separate function.
This example code uses C++17. So you must enable C++17 for your compiler. Please see (one of many possible solutions)
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <iterator>
#include <algorithm>
// In order to concentrate on the essential task, we put the file stream stuff in a separate function
bool getValidStream(std::ifstream& keyFileStream, std::ifstream& textFileStream, std::ofstream& outFileStream) {
// We are pessimistic and assume an error
bool result{ false };
// Give instructions to the user to enter the file name for the keywords file
if (std::cout << "Please enter the file name for the keywords file:\t ")
// Read keyword text filename
if (std::string keywordFileNname{}; std::cin >> keywordFileNname)
// Open key word file
if (keyFileStream.open(keywordFileNname); keyFileStream)
// Give instructions to the user to enter the file name for the text file
if (std::cout << "Please enter the file name for the text file: \t ")
// Read text filename
if (std::string textFileName{}; std::cin >> textFileName)
// Open text file
if (textFileStream.open(textFileName); textFileStream)
// Give instructions to the user to enter the file name for the output file
if (std::cout << "Please enter the file name for the output file: \t ")
// Read output filename
if (std::string outFileName{}; std::cin >> outFileName)
// Open output file
if (outFileStream.open(outFileName); outFileStream)
result = true;
if (not result)
std::cerr << "\nError: Problems with files\n\n";
return result;
}
int main() {
// Define streams to use in our software
std::ifstream keyWordFileStream{}, textFileStream{};
std::ofstream outputFileStream{};
// Get valid streams
if (getValidStream(keyWordFileStream, textFileStream, outputFileStream)) {
// Read all keywords into a vector
std::vector keywords(std::istream_iterator<std::string>(keyWordFileStream),{});
// Read complete textfile into a string variable
std::string textData(std::istreambuf_iterator<char>(textFileStream), {});
// Output result
std::transform(keywords.begin(), keywords.end(), std::ostream_iterator<std::string>(outputFileStream, "\n"),
[&](const std::string& key) {return (textData.find(key) != std::string::npos) ? key + ": 1" : key + ": 0"; });
}
return 0;
}
The code you have shown is almost workable. The core logic of finding the search string in the line read from the file using find is what you would want to do. If you find it, return true. That's certainly one way of going about the problem you describe.
Read on why !Myfile.eof() is bad, fix it.
Remove close() calls since the destructor of std::basic_ifstream release the underlying file resource
You're passing in character literals but your function signature is bool CheckWord(char* , char* ). Fix that source of warning.
Once, you've fixed all this, you should be fine. You have the core logic of finding words in a file. I still don't get why you asked the question when you've got a near working solution. If you're looking for complexity gains etc. you need to explore the data structure to be used, but then that's probably not your intention for this assignment.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
//reading the text file
ifstream inputFile("testfile1.txt");
inputFile.open("testfile1.txt");
while(!inputFile.eof())
//eof till end of file, reads the txt till end of file
{
string str;
getline(inputFile,str);
cout <<str<< endl;
}
inputFile.close();
return 0;
}
// The problem that i am having is that it doesn not read the file or anything in it. Doing nothing it says Program ended with exit code: 0. Could anyone check the mistake in the code
First Bug: You are opening the input file twice. Per the C++ standard, regarding the behavior of your second open request (the direct call to the open member):
C++11 § 27.9.1.9 [ifstream.members/3]
void open(const char* s, ios_base::openmode mode = ios_base::in);
Effects: Calls rdbuf()->open(s, mode | ios_base::in). If that function
does not return a null pointer calls clear(), otherwise calls
setstate(failbit) (which may throw ios_base::failure (27.5.5.4)).
which therefore asks the question, what does rdbuf()->open(...) do ? Well, a std::ifstream uses a filebuf for it's buffering, and once again, per the standard:
C++11 §27.9.1.4 [filebuf.members/2]
basic_filebuf<charT,traits>* open(const char* s, ios_base::openmode mode);
Effects: If is_open() != false, returns a null pointer. Otherwise, initializes the filebuf as required. ...
In short, your double-open is putting your stream into a fail-state, which means all data-related operations with it are going to fail outright from that point on.
Second Bug: Improper use of .eof in a loop conditional expression. you'll run into this once you fix the first bug. The reasons this is not being done correctly are explained in the following question far better than I can explain it here.
Why is iostream::eof inside a loop condition considered wrong?
Suffice it to say, check your IO operations, not just the eof-state of the stream. Get into that habit and stick with it.
Fixing both, your code can literally be reduced to simply this:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream inputFile("testfile1.txt");
std::string str;
while (std::getline(inputFile, str))
std::cout << str << std::endl;
}
Obviously if you're shooting for more robust code, you probably want to perform some error handling in there, something like:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
int main()
{
std::ifstream inputFile("testfile1.txt");
if (!inputFile)
{
std::cerr << "Failed to open file\n";
return EXIT_FAILURE;
}
std::string str;
while (std::getline(inputFile, str))
std::cout << str << std::endl;
}
This is the correct way to read a file according to this article!
The problem in your code it seems that you are using an IDE and it cannot find the path you are giving to ifstream so try to give a full path to the file. Hope it can help u.
string line;
ifstream f("/YOUPARTH/testfile1.txt");
if (!f.is_open())
perror("error while opening file");
while(getline(f, line)) {
cout << line << endl;
}
if (f.bad())
perror("error while reading file");
return 0;
Translate the while statement: "While inputFile is at End Of File" .. you want the negation of that.
I'm reading a file through a function like this:
#include <iostream>
#include <fstream>
#include <string>
...
void readfile(string name){
string line;
int p = 0;
ifstream f(name.c_str());
while(getline(f,line)){
p++;
}
f.seekg(0);
cout << p << endl;
getline(f,line);
cout << line << endl;
}
Mi file has 3 lines:
first
second
third
I expected the output:
3
first
Instead I get:
3
(nothing)
why is my seekg not working?
Because seekg() fails if the stream has reached the end of the file (eofbit is set), which occurs due to your getline looping. As sftrabbit implies, calling clear() will reset that bit and should allow you to seek properly. (Or you could just use C++11, in which seekg will clear eofbit itself.)
Use iterators for read from the file
std::fstream file( "myfile.txt", std::ios::out );
std::string data = std::string(
std::istreambuf_iterator<char>( file ),
std::istreambuf_iterator<char>() );
I'm very new to the world of C++ error handling, but I was told here:
Checking for file existence in C++
...that the best way to checks for file existence was with a try-catch block. From my limited knowledge on the topic, this sounds like sound advice. I located this snippet of code:
http://www.java2s.com/Tutorial/Cpp/0240__File-Stream/Readafileintrycatchblock.htm
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
try{
char buffer[256];
ifstream myfile ("test.txt");
while (! myfile.eof() )
{
myfile.getline (buffer,100);
cout << buffer << endl;
}
}catch(...){
cout << "There was an error !\n";
}
return 0;
}
...but when I compile it using
g++ -Wall -pedantic -o test_prog main.cc
And run the program in a directory where test.txt does not exist, the prog keeps spitting out empty lines to the terminal. Can anyone figure out why?
Also is this a good way to check for file existence for a file you actually want to open and read from (versus just something where your indexing a bunch of files and checking them over)?
Thanks!
In C++ iostreams do not throw exeptions by default. What you need is
ifstream myfile("test.txt");
if(myfile) {
// We have one
}
else {
// we dont
}
By default the fstream objects do not throw. You need to use void exceptions ( iostate except ); to set the exception behavior. You can fetch the current settings using iostate exceptions ( ) const;. Change your code just a bit:
#include <fstream>
#include <iostream>
#include <stdexcept>
using namespace std;
int main ()
{
try{
char buffer[256];
ifstream myfile ("test.txt");
myfile.exceptions ( ifstream::eofbit | ifstream::failbit | ifstream::badbit );
while (myfile)
{
myfile.getline (buffer,100);
cout << buffer << endl;
}
myfile.close();
}catch(std::exception const& e){
cout << "There was an error: " << e.what() << endl;
}
return 0;
}
First of all, for the try block to do any good, you need to enable exceptions for the stream.
Second, a loop like:
while (! myfile.eof() )
Will lead to nothing but trouble, and you're seeing that here. The problem (in this case) is that when the file failed to open, eof will never be signaled -- you can't/don't reach the end of the file because there is no file. Therefore, your loop runs forever, on an existentialist search for the end of a nonexistent file. Fix the loop, and things get better in a hurry:
char buffer[256];
ifstream myfile ("test.txt");
while (myfile.getline(buffer,100))
{
cout << buffer << endl;
}
While you're at it, a bit more fixing wouldn't hurt (unless you really meant to use less than half of the space you allocated for your buffer):
char buffer[256];
ifstream myfile ("test.txt");
while (myfile.getline(buffer,sizeof(buffer)))
{
cout << buffer << endl;
}
Or, of course, eliminate the problem entirely:
std::string buffer;
ifstream myfile("test.txt");
while (getline(myfile, buffer))
cout << buffer << "\n";
Edit: note that none of these (at least currently) depends on exceptions at all. They're all set up to write a line to the output if we succeeded in our attempt at reading a line from the input. If the file didn't open, the body of the loop simply won't execute, because we won't be able to read from a file that didn't open. If we want to print an error message telling the user that the file didn't open, we'd have to handle that separately from what's above. For example:
ifstream myfile("test.txt");
if (!myfile) {
std::cerr << "File failed to open";
return FAIL;
}
while (std::getline(myfile // ...