Program to read from file line by line - c++

I've been trying to write a code to read from a file line by line:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream jin("Story.txt");
// ins.open("Story.txt", ios::in);
if (!jin)
{
cout << "File not opened" << endl;
return 1;
}
else{
char a[100];
do
{
jin.getline(a, 100);
cout << a << endl;
}
while (!jin.eof());
jin.close();
return 0;
}
}
However, on executing this program on Visual Studio Code on Windows, it behaves as infinite loop.
Can someone tell what's wrong?
(I am sure that the file Story.txt exists, no doubt about that)

When std::istream::getline has read 100-1 characters (without finding a newline,\n), it will set the failbit on the stream. This prevents further reading on the stream (unless you reset that state). It does however not set eofbit so you are now in a bit of a pickle. The failbit prevents further reading, and eof() returns false, because eofbit is not set - it will therefore loop indefinitely.
If at least one of the lines in Story.txt is longer than 99 chars, the above is what will happen.
The easiest way out is to use a std::string and std::getline instead:
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream jin("Story.txt");
if(!jin) {
std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
return 1;
}
std::string a;
while(std::getline(jin, a)) {
std::cout << a << '\n';
}
return 0;
}
If you really do not want to use std::getline and std::string, you can, but it's much harder:
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
int main() {
std::ifstream jin("Story.txt");
if(!jin) {
std::cerr << "File not opened: " << std::strerror(errno) << std::endl;
return 1;
}
char a[100];
while(true) {
jin.getline(a, 100);
std::cout << a; // output what we got
if(jin) {
// got a complete line, add a newline to the output
std::cout << '\n';
} else {
// did not get a newline
if(jin.eof()) break; // oh, the end of the file, break out
// reset the failbit to continue reading the long line
jin.clear();
}
}
}

jin.eof() will only return true if a eof-token is found, and this will not happend unless the file is open. That is what causing your infinite loop.
Then you would probably want something like this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream jin{"Story.txt"};
if (!jin)
{
cout << "File not opened" << endl;
return 1;
}
for (std::string a; std::getline(jin, a);) { // Read every line
cout << a << "\n";
}
// jin is closed when going out of scope so no need for close();
return 0;
}

Related

Read multiple files with C++

I would like to edit the below code to look at and read several other files in the proc directory. May I get some guidance on how to improve this code to look at other proc files other than just the uptime. Thank you.
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib> // for exit()
int main()
{
using namespace std;
// ifstream is used for reading files
// We'll read from a file called Sample.dat
ifstream inf("/proc/uptime");
// If we couldn't open the input file stream for reading
if (!inf)
{
// Print an error and exit
cerr << "Uh oh, file could not be opened for reading!" << endl;
exit(1);
}
// While there's still stuff left to read
while (inf)
{
// read stuff from the file into a string and print it
std::string strInput;
getline(inf, strInput);
cout << strInput << endl;
}
return 0;
// When inf goes out of scope, the ifstream
// destructor will close the file
}
Here it is written with a function instead
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib> // for exit()
using namespace std;
void readfile(string file)
{
ifstream inf (file.c_str());
if (!inf)
{
// Print an error and exit
cerr << "Uh oh, file could not be opened for reading!" << endl;
exit(1);
}
while (inf)
{
std::string strInput;
getline(inf, strInput);
cout << strInput << endl;
}
}
int main()
{
cout << "-------------------obtaining Totaltime and Idletime----------------" << endl;
readfile("/proc/uptime");
return 0;
}

Store lines from a text file in a list of strings

I've been trying to store the lines of a text file in a list in C++. Better, I've been trying to store each word of each line of the text file in a string that is part of a list of strings, but it seems that I'm doing it in the wrong way.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <list>
using namespace std;
int main()
{
FILE *f= fopen("teste.txt", "r");
size_t len= 100; // valor arbitrário
char *line= (char*)malloc(len);
std::list<string> mylist;
if (!f)
{
perror("teste.txt");
exit(1);
}
while (getline(&line, &len, f) > 0)
{ //THE REAL PROBLEM
for (std::list<string>::iterator it = mylist.begin(); it != mylist.end(); it++){
*it=line;
cout << *it << '\n';
}
}
if (line)
free(line);
fclose(f);
return 0;
}
The exact problem is that this doesn't give any result. It compiles but nothing results from this.
Thanks in advance.
Change your while loop as follows:
while (getline(&line, &len, f) > 0)
{
mylist.push_back(line);
cout << mylist.back() << '\n';
}
You cannot access any non initialized items from a std::list<>.
Also NOTE you should make line a std::string, and omit the malloc() / free() calls from your code.
2nd NOTE: Use std::ifstream instead of FILE* for an input file stream.
Here's the fully fixed (no more errors/exceptions on ideone) code sample:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <exception>
#include <errno.h>
#include <stdlib.h>
int main()
{
try
{
std::ifstream f("teste.txt");
if(!f)
{
std::cerr << "ERROR: Cannot open 'teste.txt'!" << std::endl;
exit(1);
}
std::string line;
std::list<std::string> mylist;
while (std::getline(f,line))
{
mylist.push_back(line);
std::cout << mylist.back() << std::endl;
}
}
catch(const std::exception& ex)
{
std::cerr << "Exception: '" << ex.what() << "'!" << std::endl;
exit(1);
}
exit(0);
}
You can not assign a char* value to std::string by using '=' operator.
Change
*it=line to
it->assign(line,line+strlen(line);

How to write to and read from a file simultaneously in C++

I need to write two programs write.cpp & read.cpp to run simultaneously. One of them write(overwrite) to a file and the other one reads from it.
Basically, there is always only one line in the file.
write.cpp performs the operation successfully but read.cpp doesn't show anything. Using tail -f also shows incorrect result.
write.cpp:
#include <stdio.h>
#include <ctime>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
ofstream myfile;
int i = 70;
char c;
while(i <85)
{
myfile.open ("example.txt");
c = i++;
myfile << c << endl;
myfile.close();
sleep(1);
}
return 0;
}
read.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
sleep(1);
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
May I know which part of both programs causes the problem and how may I solve it?
You're doing the right thing in the writer, but once you've read to end of file, the input stream becomes unusable until the fail condition is set. The best solution is probably to do exactly what you're doing in the writer: open and close the file each time in the read loop.
Be aware that there will be a moment when the file is empty; when you open the file for writing in the writer, it will be truncated, and if the reader happens to try to read at precisely this moment, it will find an empty file. (It's no big problem; just be aware of it, maybe skipping the sleep if you find an empty line.)
To add some detail to my answer to your previous question, here is how you could use Boost's interprocess communication to achieve this if you insist on using a file for ipc.
A writer may look like this:
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <fstream>
#include <iostream>
int main()
{
using namespace boost::interprocess;
std::string line, shared_filename = "shared";
{
std::ofstream create_shared_file(shared_filename.c_str());
}
for (;;)
{
std::cout << "Enter some text: ";
std::cin >> line;
try
{
file_lock lock(shared_filename.c_str());
scoped_lock<file_lock> lock_the_file(lock);
std::ofstream shared_file(shared_filename.c_str(), std::ofstream::trunc);
shared_file << line << std::endl;
shared_file.flush();
}
catch (interprocess_exception const& e)
{
std::cerr << e.what() << std::endl;
}
}
}
The corresponding reader:
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <fstream>
#include <iostream>
#include <unistd.h>
int main()
{
using namespace boost::interprocess;
std::string line, shared_filename = "shared";
for (;;)
{
try
{
file_lock lock(shared_filename.c_str());
std::cout << "Waiting for file lock..." << std::endl;
sharable_lock<file_lock> lock_the_file(lock);
std::cout << "Acquired file lock..." << std::endl;
std::ifstream shared_file(shared_filename.c_str());
shared_file >> line;
if (line.empty())
{
std::cout << "Empty file" << line << std::endl;
}
else
{
std::cout << "Read: " << line << std::endl;
}
}
catch (interprocess_exception const& e)
{
std::cerr << "Could not lock " << shared_filename << ": " << e.what() << std::endl;
}
std::cout << "Sleeping..." << std::endl;
sleep(2);
}
}

Writing key inputs to a file

I'm compiling this code with GNU GCC Compiler in Code Blocks but for some reason the log file that it creates remains empty no matter what. Any ideas why this might be?
#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
using namespace std;
int i;
string s;
int main()
{
ofstream log;
log.open("log.txt");
while (!GetAsyncKeyState(VK_F8)) {
for (i=65; i<90; i++) {
if (GetAsyncKeyState(i)) {
s+=i;
}
Sleep(10);
}
if (GetAsyncKeyState(VK_SPACE)) {
s+=" ";
}
}
log << s;
log.close();
cin.get();
}
Consider following points:
Are you trying log << "TEST" in the condition?
Try this (right after the log.open call):
log.open("log.txt");
log << "TEST" << endl;
If TEST gets written to the file, your file is empty because the condition never gets true.
An other issue might be that the file contains non-displayable characters.
Dump your file to a hex-editor. Does the file have a size of 0 or is it containing data you might not be able to display on common text editors?
*EDIT: * This should do what you want:
Either write your i or " " directly to log or use a stringstream:
#include <sstream>
//...
ofstream log;
log.open("log.txt");
stringstream str;
while (!GetAsyncKeyState(VK_F8)) {
for (i=65; i<90; i++) {
if (GetAsyncKeyState(i)) {
str << i;
}
Sleep(10);
}
if (GetAsyncKeyState(VK_SPACE)) {
str << " ";
}
}
log << str.rdbuf();
log.close();
cin.get();
Try using if(GetKeyState(0x41)) instead for your if.
Most likely your are looking for log.txt in the wrong directory

Implement "tail -f" in C++

I want to create a small code in C++ with the same functionality as "tail-f": watch for new lines in a text file and show them in the standard output.
The idea is to have a thread that monitors the file
Is there an easy way to do it without opening and closing the file each time?
Have a look at inotify on Linux or kqueue on Mac OS.
Inotify is Linux kernel subsystem that allows you to subscribe for events on files and it will report to your application when the even happened on your file.
Just keep reading the file. If the read fails, do nothing. There's no need to repeatedly open and close it. However, you will find it much more efficient to use operating system specific features to monitor the file, should your OS provide them.
Same as in https://stackoverflow.com/a/7514051/44729 except that the code below uses getline instead of getc and doesn't skip new lines
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
static int last_position=0;
// read file untill new line
// save position
int find_new_text(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
// check if the new file started
if(filesize < last_position){
last_position=0;
}
// read file from last position untill new line is found
for(int n=last_position;n<filesize;n++) {
infile.seekg( last_position,ios::beg);
char test[256];
infile.getline(test, 256);
last_position = infile.tellg();
cout << "Char: " << test <<"Last position " << last_position<< endl;
// end of file
if(filesize == last_position){
return filesize;
}
}
return 0;
}
int main() {
for(;;) {
std::ifstream infile("filename");
int current_position = find_new_text(infile);
sleep(1);
}
}
I read this in one of Perl manuals, but it is easily translated into standard C, which, in turn, can be translated to istreams.
seek FILEHANDLE,POSITION,WHENCE
Sets FILEHANDLE's position, just like the "fseek" call of
"stdio".
<...>
A WHENCE of 1 ("SEEK_CUR") is useful for not moving the file
position:
seek(TEST,0,1);
This is also useful for applications emulating "tail -f". Once
you hit EOF on your read, and then sleep for a while, you might
have to stick in a seek() to reset things. The "seek" doesn't
change the current position, but it does clear the end-of-file
condition on the handle, so that the next "<FILE>" makes Perl
try again to read something. We hope.
As far as I remember, fseek is called iostream::seekg. So you should basically do the same: seek to the end of the file, then sleep and seek again with ios_base::cur flag to update end-of-file and read some more data.
Instead of sleeping, you may use inotify, as suggested in the other answer, to sleep (block while reading from an emulated file, actually) exactly until the file is updated/closed. But that's Linux-specific, and is not standard C++.
I needed to implement this too, I just wrote a quick hack in standard C++. The hack searches for the last 0x0A (linefeed character) in a file and outputs all data following that linefeed when the last linefeed value becomes a larger value. The code is here:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int find_last_linefeed(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
for(int n=1;n<filesize;n++) {
infile.seekg(filesize-n-1,ios::beg);
char c;
infile.get(c);
if(c == 0x0A) return infile.tellg();
}
}
int main() {
int last_position=-1;
for(;;) {
ifstream infile("testfile");
int position = find_last_linefeed(infile);
if(position > last_position) {
infile.seekg(position,ios::beg);
string in;
infile >> in;
cout << in << endl;
}
last_position=position;
sleep(1);
}
}
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <sys/stat.h>
#include <stdlib.h>
#define debug 0
class MyTail
{
private:
std::list<std::string> mLastNLine;
const int mNoOfLines;
std::ifstream mIn;
public:
explicit MyTail(int pNoOfLines):mNoOfLines(pNoOfLines) {}
const int getNoOfLines() {return mNoOfLines; }
void getLastNLines();
void printLastNLines();
void tailF(const char* filename);
};
void MyTail::getLastNLines()
{
if (debug) std::cout << "In: getLastNLines()" << std::endl;
mIn.seekg(-1,std::ios::end);
int pos=mIn.tellg();
int count = 1;
//Get file pointer to point to bottom up mNoOfLines.
for(int i=0;i<pos;i++)
{
if (mIn.get() == '\n')
if (count++ > mNoOfLines)
break;
mIn.seekg(-2,std::ios::cur);
}
//Start copying bottom mNoOfLines string into list to avoid I/O calls to print lines
std::string line;
while(getline(mIn,line)) {
int data_Size = mLastNLine.size();
if(data_Size >= mNoOfLines) {
mLastNLine.pop_front();
}
mLastNLine.push_back(line);
}
if (debug) std::cout << "Out: getLastNLines()" << std::endl;
}
void MyTail::printLastNLines()
{
for (std::list<std::string>::iterator i = mLastNLine.begin(); i != mLastNLine.end(); ++i)
std::cout << *i << std::endl;
}
void MyTail::tailF(const char* filename)
{
if (debug) std::cout << "In: TailF()" << std::endl;
int date = 0;
while (true) {
struct stat st;
stat (filename, &st);
int newdate = st.st_mtime;
if (newdate != date){
system("#cls||clear");
std::cout << "Print last " << getNoOfLines() << " Lines: \n";
mIn.open(filename);
date = newdate;
getLastNLines();
mIn.close();
printLastNLines();
}
}
if (debug) std::cout << "Out: TailF()" << std::endl;
}
int main(int argc, char **argv)
{
if(argc==1) {
std::cout << "No Extra Command Line Argument Passed Other Than Program Name\n";
return 0;
}
if(argc>=2) {
MyTail t1(10);
t1.tailF(argv[1]);
}
return 0;
}