How can I test if either of two files exist? - c++

I am new to C++,
I am using a while true to find a Pass.txt file.
Once it finds it the while loop breaks and prints "Pass.txt file FOUND"
This works fine
I then would like to see if it can find Pass.txt OR Fail.txt with a while true
something like this ifstream ifile("Pass.txt || Fail.txt");
This does not work:
cout << " ------------------------------------------\n";
cout << " Searching for Pass or Fail file \n";
cout << " ------------------------------------------\n";
cout << "\n\n";
while (true)
{
ifstream ifile("Pass.txt");
//ifstream ifile("Pass.txt ||Fail.txt");
if (ifile)
{
// The file exists, and is open for input
break;
}
}
cout << "\n\n";
cout << " ------------------------------------------\n";
cout << " Pass.txt FOUND \n";
cout << " ------------------------------------------\n";
cout << " ------------------------------------------\n";

Your code fails because you’re not testing for the existence of two files. You are testing whether the one file with the weird name Pass.txt || Fail.txt exists. You need two make two separate existence checks, one for each separate file.
To do this, don’t open the file — use std::filesystem::exists:
#include <filesystem>
#include <thread>
// …
int main() {
using namespace std::chrono_literals;
namespace fs = std::filesystem;
while (not fs::exists("Pass.txt")) {
std::this_thread::sleep_for(500ms); // Be gentle to the system.
}
while (not (fs::exists("Pass.txt") or fs::exists("Fail.txt"))) {
std::this_thread::sleep_for(500ms); // Be gentle to the system.
}
}
(You can also write ! instead of not, and || instead of or; but I prefer using these descriptive terms in my own code.)
We use std::this_thread::sleep to avoid hammering the system with a busy loop, which will spin up your CPU like crazy even though your code isn’t doing any real work.
However, note that merely testing for a file’s existence isn’t very useful. And your second loop will immediately terminate, since "Pass.txt" exists after the first loop (unless, by a freak coincidence, it was deleted in the nanoseconds between the two loops).

Related

strange thing in sequential file access

Recently, I am trying to write codes to get trained in sequential file access. I learned it well, but the issue is kinda stressing me out. I have a code that work 100%, and its task is "make a code that prints array elements inside a file", the text file name is "numric".
#include <iostream>
#include <fstream>
using namespace std;
int main(){
int a[3]={5000,6000,7000};
ofstream outfile("numric.txt");
if (outfile.is_open()){
outfile << "employee payroll:" << endl;
for (int i=0;i<3;i++)
outfile << a[i] << endl;
outfile.close();
} else
cout << "failed!" << endl;
return 0;
}
I implemented the code in two different program (VS Code, dev++) and it works fine. It found the file, but when I open the text file, there isn't any text inside it. The code should do its work by finding some text inside it if I opened it.
Note:sometimes when the code works, the antivirus pops a message saying it found an item that doesn't look safe in the program and deletes it.

How to compare column from a file c++

I have a file that has 3 columns with many rows. I want to compare the value either increase or decrease for 2 columns. But when I compare, the value always increases even it should be decreased. Any idea how to solve this? This is my coding to compare the value in the file. But I didn't get the desired output. anyone can help me?
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream fromFile;
fromFile.open("data.txt");
{
cout << "There was an error" << endl;
exit(1);
}
else
cout << "No error, file opened successfully" << endl;
fromFile.clear();
fromFile.seekg(0);
for(int i=1; i<=20; i++)
{
int a{}, b {}, c {};
fromFile >> a >> b >> c ;
cout<<" Year : " <<a<<" population : "<<b<<" car : "<<c<< endl;
if ( b < b && c < c )
cout << " population decrease and car production decrease " << endl;
if ( b > b && c > c );
cout << " population increase and car production increase " << endl;
if ( b > b && c < c )
cout << " population increase but car production decrease " << endl;
if ( b < b && c > c );
cout << " population decrease but car production increase " << endl;
}
//CLOSES FILES
fromFile.close();
return 0;
}
There are several problems with your code. I will first mention those and then show a corrected solution (one of many possible variants).
Some issues:
You should not use using namespace std. There are many expanations on stackoverflow with the explanation. Use full qualified names instead
The std::ifstream has a constructor that automatically opens the stream. No need for function open
The stream has an overloaded bool operator. You can simply test the state with if (fromFile)
You forgot the if statement, but have an else statement. So, your program will not compile. And is logically wrong
Because of the missing if the program will always exit immidiately
clear and seekg are not necessary. The filepointer is at the beginning after opening the stream.
You use a loop with fixed hardcoded magic number 20. What if the file has more or less rows? You need to use the condition end-of-file to end the loop
You compare always the variables with itself. Even the compiler will warn you. This cannot work. You need to read a variable, store it somewhere in a different variable, read again from the file and compare the current variable with the previous value. This is your main problem
No need to call the close-function of the stream. The destructor will call it implicitely for you, when the stream variable leaves its scope
You have not enough comparision if statements. Many cases, especially, if values are same than before, will not be handled
So, what do we need to do? I will explain with only one variable now. Let's take the year. We define a variable year and a second varibale previousValueYear. In a loop, we read the value from the file into year. Then, we compare the year variable with the previousValueYear, do the evaluation and show the output. And then, before reading the next value from the file, we copy the current value from year to previousValueYear. Then we can do the correct comparison in the next loop run.
The first comparision is a little bit tricky, because we do not have a previousValueYear. We will add an additional if statement with a boolean flag, to check for this condition.
Please see here the corrected version:
#include <iostream>
#include <fstream>
int main() {
// Open the source file
std::ifstream fromFile("data.txt");
// Check, if we could open the file
if (fromFile) { // bool operator of stream will be called
// OK, file could be opened. Defineour variables
int year{}, population{}, car{};
int previousValueYear{}, previousValuePopulation{}, previousValueCar{};
bool thisIsTheNotFirstLoopRun{};
// Read values in a loop and check, if the input worked
while (fromFile >> year >> population >> car) {
// Show read data
std::cout << "Year: " << year << " \tPopulation: " << population << " \tCar: " << car << '\n';
// In the first loop run, we will not do a comparision (There is only one value and nothing to compare
if (thisIsTheNotFirstLoopRun) {
// Do the comparisons
if ((population < previousValuePopulation) and (car < previousValueCar))
std::cout << "Population decrease and car production decrease\n";
if ((population > previousValuePopulation) and (car > previousValueCar))
std::cout << "Population increase and car production increase\n";
if ((population > previousValuePopulation) and (car < previousValueCar))
std::cout << "Population increase and car production decrease\n";
if ((population < previousValuePopulation) and (car > previousValueCar))
std::cout << "Population decrease and car production increase\n";
}
// Remember current values for next loop run
previousValueYear = year;
previousValuePopulation = population;
previousValueCar = car;
// Now, we will not have any longer the first loop run
thisIsTheNotFirstLoopRun = true;
}
}
else {
// Error, file could not be opened. Show message
std::cerr << "\nError: SourceFile could not be opened\n";
}
return 0;
}
Advanced C++ porgrammers would change a lot. But for now it is OK

Problem with ASCII Rotating Cursor (TUI) Animation

I'm trying to create the rotating cursor animation thing.
Each time I compile this I always get a slash (or two) left at the end, and the backspace character does not work. I used two ways to do this: the sleep function and the chrono timer and they worked very similarly and left a slash after spinning, ignoring the backspace character.
This works differently and as expected if I leave out any newline character or manipulator.
void spinningCursor() {
for (int i = 1; i <= 100; ++i)
{
cout << "-" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "\\" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "|" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "/" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
}
}
Or...
void spinningCursor2() {
for (int i = 0; i < 100; i++) {
cout << "-";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "\\";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "|";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "/";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
}
}
main function...
int main()
{
spinningCursor();
cout <<"\nHello, World!"<< endl;
spinningCursor2();
cout <<"\nHello, World, Again!"<< endl;
return 0;
}
The output effect is not guaranteed but dividing it into sections might help.
Idea:
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iostream>
#include <string>
#include <thread>
using namespace std::chrono_literals; // a cumbersome way to be able to write 100ms
// unformatted output of one char, a backspace, flushing and Zzz...
void slow_put(char ch) {
static const auto delay = 100ms;
static const char bs = '\b';
std::cout.write(&ch, 1);
std::cout.write(&bs, 1);
std::cout.flush();
std::this_thread::sleep_for(delay);
}
// newline, but erase the char under it first
void nl() {
std::cout.write(" \n", 2);
}
// proxy ... decorate stuff here (for debugging etc)
void display(char ch) {
slow_put(ch);
}
// enabler to repeat a bunch of sequences
void spinner(const std::string& sequence) {
// execute the display function for one char at a time
std::for_each(sequence.begin(), sequence.end(), display);
}
// example use of the helpers above
void spinningCursorSchema(size_t times) {
static const std::string seq = R"raw(|/-\)raw"; // the pattern to display
while(times--) spinner(seq);
// add more patterns to this schema if wanted
}
int main() {
std::cout << "Spinner: [ ]\b\b";
spinningCursorSchema(100); // run the spinningCursor 100 times
nl(); // erasing newline
}
Edit: A brief explanation:
For every group of functions you called that I felt could be named, "do_this()" or "do_that()" I put them in a function and named them accordingly.
The purpose of this exercice was not primarily for me to find the error in your code but to provide a frame of reference. It's easier to identify/talk about/fix problems when one can say "your do_this() function needs this or that..." or similar. When everything is in one big code block everyone reading it needs to start from zero. A function with a clear name (or a comment to compensate for the poor naming as I did above, "proxy") and only a few lines of code can be reviewed by everyone without much background knowledge about the bigger problem.
In short, I took your code that was specifically created to do one thing and broke it down into a few functions that I used to rebuild something similar to your original idea. By doing that I made it easier to see flaws, talk about design decisions. If a function of 2-4 lines can be reviewed by 10000 people and they don't see a problem, it's very unlikely that that function is the problem (in itself). By building blocks of small functions with a clear purpose, bughunting becomes a lot more available for everyone, not only people deeply involved in the particular problem you're solving.
I now see that I used a function template from <algorithm> that may be unfamiliar: std::for_each. In this case, it could be replaced by:
for(char ch : sequence) display(ch);
Come to think of it, that's even clearer.
If this wasn't the overview you sought, just comment and point out the parts you want to get explained and I'll try again
The backspace character doesn't actually delete the previous character, all it does is move the cursor itself back one "space". It's the combination of backspace followed by writing another character that does the overwrite or "delete" the character.
Also, the backspace only goes as far as the beginning of the current line. Once you have printed a newline you can't go back "up" a line with a backspace.
On Windows you might be able to get better results by using the Windows console functions, and on POSIX systems (like Linux or macOS) maybe VT100 escape codes.

Opening/Writing to multiple files

I am trying to write some code that is going to output a speed and time values to multiple files, specifically 4 different files which represents 4 different objects moving.
I know that to open and write to 1 file I can do the following:
#include <iostream>
#include <fstream>
std::ofstream outfile ("test.txt");
outfile << "my text here!" << std::endl;
outfile.close();
However I need to adapt this such that it would work in a switch statement as follows:
for (int i = 0; i < numRobots; i++){
switch (i){
case 0:
if (r1_stop == 1) r1Speed = 0;
else //Update speed
r1File << r1Speed << " " << time << endl;
case 1:
if (r2_stop == 1) r2Speed = 0;
else //Update speed
r2File << r2Speed << " " << time << endl;
case 2:
if (r3_stop == 1) r3Speed = 0;
else //Update speed
r3File << r3Speed << " " << time << endl;
case 3:
if (r4_stop == 1) r4Speed = 0;
else //Update speed
r4File << r4Speed << " " << time << endl;
}
}
Where r1File, r2File, r3File, and r4File are the files containing the speed and time for the respective objects. Im not quite sure how to implement this type where I have multiple files open or do i have to keep opening and closing the files? Im worried about overwriting existing data in the file if that is the case unless it knows to not start from the beginning of the file when opening it again.
Any help is appreciated, thanks
By default std::ofstream overwrites instead of appends, so from the moment you open the file it will be streaming bytes in that overwrite whatever was there before it was opened.
*fstream variants keep a file open until the stream object is destroyed. In other words a file being open is tied to the lifetime of the *fstream object representing it. Once destroyed, the file is immediately closed. This concept is known as RAII. In your case the stream objects are global, and thus are destroyed after main() ends, right before the application terminates.
If writing to the files isn't time critical, your implementation is good enough. On the other hand if you need more accurate measurements, consider writing each of your outputs to an intermediate buffer such as std::stringstream, then stream that data to your files after you're done taking measurements.
However, if you don't need the data from previous application runs, don't bother using files and instead just write to memory using a std::stringstream.

count specific things within a code in c++

can anyone help me make this more generalised and more pro?
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
// open text file for input:
string file_name;
cout << "please enter file name: ";
cin >> file_name;
// associate the input file stream with a text file
ifstream infile(file_name.c_str());
// error checking for a valid filename
if ( !infile )
{
cerr << "Unable to open file "
<< file_name << " -- quitting!\n";
return( -1 );
}
else cout << "\n";
// some data structures to perform the function
vector<string> lines_of_text;
string textline;
// read in text file, line by
while (getline( infile, textline, '\n' ))
{
// add the new element to the vector
lines_of_text.push_back( textline );
// print the 'back' vector element - see the STL documentation
cout << lines_of_text.back() << "\n";
}
cout<<"OUTPUT BEGINS HERE: "<<endl<<endl;
cout<<"the total capacity of vector: lines_of_text is: "<<lines_of_text.capacity()<<endl;
int PLOC = (lines_of_text.size()+1);
int numbComments =0;
int numbClasses =0;
cout<<"\nThe total number of physical lines of code is: "<<PLOC<<endl;
for (int i=0; i<(PLOC-1); i++)
//reads through each part of the vector string line-by-line and triggers if the
//it registers the "//" which will output a number lower than 100 (since no line is 100 char long and if the function does not
//register that character within the string, it outputs a public status constant that is found in the class string and has a huge value
//alot more than 100.
{
string temp(lines_of_text [i]);
if (temp.find("//")<100)
numbComments +=1;
}
cout<<"The total number of comment lines is: "<<numbComments<<endl;
for (int j=0; j<(PLOC-1); j++)
{
string temp(lines_of_text [j]);
if (temp.find("};")<100)
numbClasses +=1;
}
cout<<"The total number of classes is: "<<numbClasses<<endl;
Format the code properly, use consistent style and nomenclature and throw out the utterly redundant comments and empty lines. The resulting code should be fine. Or “pro”.
Here, I’ve taken the efford (along with some stylistic things that are purely subjective):
Notice that the output is actually wrong (just run it on the program code itself to see that …).
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string file_name;
cout << "please enter file name: ";
cin >> file_name;
ifstream infile(file_name.c_str());
if (not infile) {
cerr << "Unable to open file " << file_name << " -- quitting!" << endl;
return -1;
}
else cout << endl;
vector<string> lines_of_text;
string textline;
while (getline(infile, textline)) {
lines_of_text.push_back(textline);
cout << lines_of_text.back() << endl;
}
cout << "OUTPUT BEGINS HERE: " << endl << endl;
cout << "the total capacity of vector: lines_of_text is: "
<< lines_of_text.capacity() << endl << endl;
int ploc = lines_of_text.size() + 1;
cout << "The total number of physical lines of code is: " << ploc << endl;
// Look for comments `//` and count them.
int num_comments = 0;
for (vector<string>::iterator i = lines_of_text.begin();
i != lines_of_text.end();
++i) {
if (i->find("//") != string::npos)
++num_comments;
}
cout << "The total number of comment lines is: " << num_comments << endl;
// Same for number of classes ...
}
I'm not really sure what you're asking, but I can point out some things that can be improved in this code. I'll focus on the actual statements and leave stylistic comments to others.
cin >> file_name;
To handle file names with spaces, better write
getline(cin, file_name);
int PLOC = (lines_of_text.size()+1);
Why do you claim that there's one more line than there actually is?
if (temp.find("//")<100)
with some complicated comment explaining this. Better write
if (temp.find("//")<temp.npos)
to work correctly on all line lengths.
cout<<"The total number of comment lines is: "<<numbComments<<endl;
Actually, you counted the number of end-of-line comments. I wouldn't call a comment at the end of a statement a "comment line".
You don't count /* */ style comments.
Counting the number of classes as };? Really? How about structs, enums, and plain superfluous semicolons? Simply count the number of occurences of the class keyword. It should have no alphanumeric character or underscore on either side.
Use proper indentation, your code is very difficult to read in its current form. Here is a list of styles.
Prefer ++variable instead of variable += 1 when possible; the ++ operator exists for a reason.
Be consistent in your coding style. If you're going to leave spaces between things like cout and <<, function arguments and the function parantheses do it, otherwise don't, but be consistent. Pick one naming convention for your variables and stick to it. There is a lot about styles you can find on google, for example here and here.
Don't use the entire std namespace, only what you need. User either using std::cout; or prefix all of your cout statements with std::
Avoid needless comments. Everyone knows what ifstream infile(file_name.c_str()); does for example, what I don't know is what your program does as a whole, because I don't really care to understand what it does due to the indentation. It's a short program, so rather than explaning every statement on its own, why not explain what the program's purpose is, and how to use it?
These are all stylistic points. Your program doesn't work in its current form, assuming your goal is to count comments and classes. Doing that is a lot more difficult than you are considering. What if I have a "};" as part of a string for example? What if I have comments in strings?
Don't import the whole std namespace, only things you need from it:
using std::string;
Use a consistent naming convention: decide whether you prefer name_for_a_variable or nameforavariable or nameForAVariable. And use meaningful names: numbComments makes me associate to very different things than would numberOfComments, numComments or commentCount.
If your original code looks like this, I strongly recommend to select a single consistent indentation style: either
if ( ... )
{
...
}
or
if ( ... )
{
...
}
bot not both in the same source file.
Also remove the useless comments like
// add the new element to the vector
This is "only" about the readability of your code, not even touching its functionality... (which, as others have already pointed out, is incorrect). Note that any piece of code is likely to be read many more times than edited. I am fairly sure that you will have trouble reading (and understanding) your own code in this shape, if you need to read it even a couple of months after.
"More professional" would be not doing it at all. Use an existing SLOC counter, so you don't reinvent the wheel.
This discussion lists a few:
http://discuss.techinterview.org/default.asp?joel.3.207012.14
Another tip: Don't use "temp.find("};}) < 100)", use "temp.find("};") != temp.npos;"
Edit: s/end()/npos. Ugh.