This small bit of code is designed to look through a text file and identify account numbers that have already been written so that later on in my program, you can find the correct account without the error of two accounts with the same account number(id). But no matter what i do, whether its using double backslashes, forward slashes, or double forward slashes in the location for the ifstream object; i always get "cannot find file" as the output.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream accountsread("G:/Coding/Test/test/test/accounts.txt");
if (accountsread.is_open()) {
int tempAccno;
std::string tempname;
char tempchar;
int accountsfound = 0;
int input;
std::cout << "Enter the ID of the account \n";
cin >> x;
while (!accountsread.eof()) {
accountsread >> tempAccno;
if (tempAccno == input) {
accountsfound++;
}
else {}
}
if (accountsfound > 0) {
cout << "number found";
}
else {
cout << "number not found";
}
}
else {
cout << "cannot find file";
}
}
in windows, the location of the text file is G:\Coding\Test\test\test\accounts.txt
std::ifstream can use relative paths as well as absolute ones. For your problem, I'd recommend looking into the <filesystem> header from the STL if you really need an absolute path to your file. However, if it's in the same directory as your working directory, you don't need to use absolute paths. Here's how I'd accomplish your task
#include <iostream>
#include <fstream>
#include <string> // Should include since you're using std::string
// Note that I am NOT "using namespace std;"
int main()
{
std::ifstream accountsRead("accounts.txt");
if (accountsRead.is_open())
{
int account_id;
bool account_found = false;
std::cout << "Enter the ID of the account: ";
while (!(std::cin >> account_id))
{ // This loop handles if the user inputs non-number
std::cout << "Please enter a NUMBER below!\n";
std::cout << "Enter: ";
std::cin.ignore(10000, '\n');
std::cin.clear();
}
int tmpAccNum;
while (accountsRead >> tmpAccNum)
{ // This loop reads the file, line by line, into tmpAccNum
if (tmpAccNum == account_id)
{
account_found = true;
break;
}
}
if (account_found)
{
std::cout << "Number found!" << std::endl;
}
else
{
std::cout << "Number not found..." << std::endl;
}
}
else
{ // Error opening file
std::cout << "File not found or is corrupted" << std::endl;
}
}
A few things about your code stylistically speaking. First, you should never be using namespace std, and (if you are for some reason) there isn't a reason to mix and match specifying the std namespace on only some std members. Second, you don't need to specify an else for every if-statement, and you probably shouldn't unless there actually are commands to execute if the else case is reached.
Edit
If you still need an absolute path, here is how you can do that:
#include <filesystem>
int main()
{
// Create path object for the file path
std::filesystem::path file_path("G:\Coding\Test\test\test\accounts.txt");
// The '.string()' method for a 'std::path' object returns the string
// version of the path, so you can use it with an 'std::ifstream'
std::ifstream accounts(file_path.string()); // Opens file via 'ifstream'
/* And so on... */
}
Related
I tried programming a file writer, but when i try to write to a file with something that has multiple words it will suddenly create files.
My code
#include <fstream>
#include <iostream>
#include <unistd.h>
int main(int argc, char *argv[]) {
char cwd[256];
while (true) {
getcwd(cwd, 256);
std::string cwd_s = (std::string)cwd;
std::string Input;
std::cout << cwd_s << "> ";
std::cin >> Input;
std::ofstream file(Input);
std::cout << "cmd /";
std::cin >> Input;
file << Input;
};
for (int i; i < argc; i++) {
std::cout << argv[i] << '\n';
};
return 0;
}
I expected to get this:
C:\Users\code> File.txt
cmd /hello world!
File.txt
hello world!
But it only had "hello", it created another file named world!
I have tried changing the code, but to no avail.
So I have wrote this code that I think does what you expect. The behavior you were seing is because you used the same string to store the filename and the user input. Also you redefined a new file every loop (without closing the previous one). I added a signal handler since if you press Ctrl+C the program would quit without saving/closing the file.
I added comments about how you can make a better CLI interface (if you're interested)
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
std::ofstream outfile;
void signalHandler(int signum) {
outfile.close();
exit(signum);
}
int main() {
char cwd[256];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
std::cout << cwd << "> ";
} else {
std::cerr << "Error: Could not get current working directory." << std::endl;
return 1;
}
std::string filename;
std::getline(std::cin, filename);
outfile.open(filename);
// We intercept the Ctrl+C signal to close the file before exiting. Else nothing will be written to it.
// You can also use Ctrl+D (EOF: End Of File) to exit the program.
// The best praticte would be to implement a command line interface with a "quit" command. (like a map<string, function> for example)
signal(SIGINT, signalHandler);
// Another good practice is to check if the file did open correctly.
if (!outfile.is_open()) {
std::cerr << "Error: Could not open file for writing." << std::endl;
return 1;
}
std::cout << "cmd / ";
char ch;
while (std::cin.get(ch)) {
outfile.put(ch);
if (ch == '\n') {
std::cout << "cmd / ";
}
}
outfile.close();
return 0;
}
Hope it will help you ! And if you have any question about the code feel free to ask I'll explain !
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;
}
I'm trying to open a file using ifstream, but no matter what solutions I find that I've tried, nothing seems to work; my program always outputs "unable to open". Below is my code in its entirety. Any help at all is appreciated!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char ** argv)
{
string junk;
ifstream fin;
fin.open("somefile.txt");
if(fin.is_open())
{
fin >> junk;
cout << junk;
}
else
{
cout << "unable to open" << endl;
}
fin.close();
return 0;
}
Also, the contents of somefile.txt, which is in the same directory as the created executable is the following:
SOME
FILE
As some commenters have suggested, it could easily be that the file truly doesn't exist, because you're looking for it in the wrong place. Try using an absolute path to the file rather than just assuming it's looking where you expect.
And output a more helpful error message using strerror(errno).
// ...
fin.open("C:\\path\\to\\somefile.txt");
// ...
else
{
cout << "unable to open: " << strerror(errno) << endl;
}
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
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;
}