ifstream - monitor updates to file - c++

I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.

Related

How to avoid this nested if statement?

I want to check if one file exists in two different paths. If the first one doesn't, check the second.
filepath1 = "/path1/file.txt"
filepath2 = "/path2/file.txt"
file_descriptor = open(filepath1)
if ( !file_descriptor.open() )
{
print("file 1 did not work");
//try file 2
file_descriptor = open(filepath2);
if( !file_descriptor.open() )
{
print("could not open file 2. exiting.");
return false;
}
}
//we get here and file_descriptor should point to a valid file
read_file(file_descriptor);
return true;
How can I avoid the nested if statement? Preferably, I'd like to not nest the if statements for readability.
The problem here is that if the first one does work, I don't want it to check the second if statement.
I thought about using:
goto (I want to avoid this)
boolean to check if one works (but now I'm introducing extra variables)
I guess this pattern is pretty general: you can try as many paths as you wish:
auto filepath1 = "/path1/file.txt";
auto filepath2 = "/path2/file.txt";
// We assume file_descriptor has been declared earlier
for (const auto fpath: {filepath1, filepath2})
{
file_descriptor = open(fpath)
if (file_descriptor.open())
break;
else
printf("file %s did not work\n", fpath);
}
if (!file_descriptor.open()) return false; // or throw
read_file(file_descriptor);
return true;
if you don't care about which file is open you can do
filepath1 = "/path1/file.txt"
filepath2 = "/path2/file.txt"
if (!(file_descriptor = open(filepath1)).open() &&
!(file_descriptor = open(filepath2)).open())
{
print("could not open file 1 nor 2. exiting.");
return false;
}
...
else if you really want only one if you can do
filepath1 = "/path1/file.txt"
filepath2 = "/path2/file.txt"
if (!(file_descriptor = open(filepath1)).open() &&
(print("file 1 did not work"),
!(file_descriptor = open(filepath2)).open()))
{
print("could not open file 2. exiting.");
return false;
}
...
but this makes the code less clear than with the two ifs
P.S. do not think about using goto

How to delete a contact from a phonebook program

I made a phonebook program which includes Add and search a contact.
But when I made the delete function, it deleted all the contacts instead of the one I entered.
I know it's a little bit complicated but any ideas?
This is the input in phonebook.txt from which I want to delete a contact:
Barney Hackett 0114543053
Luis Avery 01056633489
Hudson Ramsay 01576633982
Ihe code is:
void DeletePhoneNumber() {
FILE* search, * fp1;
//to receive the enter from system("cls")
char temp;
scanf("%c", &temp);
search = fopen("PHONEBOOK.txt", "r+");
fp1 = fopen("temp.txt", "w");
system("cls");
printf("\t*****DELETE CONTACT*****");
printf("\n\t Enter Name: ");
int length;
length = strlen(SearchName);
int i, y = 0;
//string comparison//
while (fgets(name, 50, search) != NULL) {
fputs(name, fp1);
}
fclose(search);
fclose(fp1);
search = fopen("PHONEBOOK.txt", "w");
fp1 = fopen("temp.txt", "r");
while (fgets(name, 50, search) != NULL) {
fputs(name, search);
}
fclose(search);
fclose(fp1);
remove("temp.txt");
printf("\n\tPRESS ANY KEY TO CONTINUE");
getch();
MainMenu();
}
}
I'll use this "answer" space to give you a partial analysis of your code. You can use it to improve your code.
Basically, your loop is all wrong:
search = fopen("PHONEBOOK.txt", "r+");
while (fgets(name, 50, search) != NULL) {
// ...
while (token != NULL) {
// ...
fclose(search);
search = fopen("PHONEBOOK.txt", "w");
You opened the file in append mode, read from it and now close the file, to open it in a different mode. What will it read on the next fgets in the while loop?
Opening the file in mode "w" for writing will destroy the file. So here is why there are no more entries in your file.
fclose(search);
MainMenu();
At the bottom of the loop you close the file. How can it still read something with fgets in the while loop.
Next you call MainMenu. But I assume this function calls this DeletePhoneNumber function, so you are in a strange loop/recursion. Of course, when you are done with deleting the phone number, you simply return to the main menu, not call it again.

Java Loop not exiting properly when using boolean expression (JAVA) - Newbie

Everytime I run the my function SearchByID it won't return the necessary boolean operators that I needed. The method reads to the Employee.txt files and read files one after another. What I did is I created a String array to store the splitted strings, and doing the String.equalsIgnorCase() method to check if the corresponding matches w/ the data on the file. Here is the code for the method
Code: SearchByID
public static boolean SearchByID(String ID){
boolean bool = false;
int idLoc = 3;
try(BufferedReader bufr = new BufferedReader(new FileReader(EMPLOYEE_TXT))){
String line = bufr.readLine();
/*Split the records into an array*/
String[] lines;
while(line !=null){
//do the macthing of data here
lines = line.split(";");
if(lines[idLoc].equalsIgnoreCase(ID)){
bool = true;
break;
}else{
bool = false;
break;
}
}
bufr.close();
}catch(Exception ex){
ex.printStackTrace();
}
return bool;
}
Here is the implementation of the method SearchByID();
System.out.print("Search user by ID:");
String strID = sID.nextLine();
if(IOLibraries.SearchByID(strID)){
System.out.println("A match has been found");
}else{
System.out.println("No match found");
}
Content of the Employee.txt
kadi,bens;male;baliwasan grande;88-11;99111;arg11#gmail.com;400.0
doe,john;male;11311 asdd;99811;9911331;asdf#.sdfcom;500.0
What I really need to do is I need to read all the data on the file after that it should return the correct boolean values in order search for all the users on the Employee.txt file.
I could not retrieve if I search the values below the first entries. For example if i search for id 88-11 I could retrieve the data properly, however if I search below the first entry such as 99811 it would return false or "No match found" even if it is in the Employee.txt files.
The problem is you will always break out from the loop after reading the first line.
while(line !=null){
//do the macthing of data here
lines = line.split(";");
if(lines[idLoc].equalsIgnoreCase(ID)){
bool = true;
break;
}else{
bool = false;
break;
}
}
Note the else block. If first line does not match the ID, it will go into the else block, which declare that it is not found, and breaking out.
What you should do is
initialize bool (or better call it found) as false before the loop (for which you have done already)
Only break out of loop if you found the matching line
i.e. change the loop to something like
while(line !=null){
lines = line.split(";");
if(lines[idLoc].equalsIgnoreCase(id)){
found = true;
break;
}
}

replace some value in text line in c++

Hi guys i use this code to find the line included seta r_fullscreen "0" and if the value for this line is 0 return MessageBox but my question is if the value of seta r_fullscreenis "0" so how i can replace this value to "1" in this line ?
ifstream cfgm2("players\\config_m2.cfg",ios::in);
string cfgLine;
Process32First(proc_Snap , &pe32);
do{
while (getline(cfgm2,cfgLine)) {
if (string::npos != cfgLine.find("seta r_fullscreen")){
if (cfgLine.at(19) == '0'){
MessageBox(NULL,"run in full Screen mod.","ERROR", MB_OK | MB_ICONERROR);
...
You can use std::string::find() and std::string::replace() to do this. After you have located the line containing the configuration specifier seta r_fullscreen you can do something like the following.
std::string::size_type pos = cfgLine.find("\"0\"");
if(pos != std::string::npos)
{
cfgLine.replace(pos, 3, "\"1\"");
}
You should not assume that the configuration value "0" is at a specific offset as there may be additional spaces between r_fullscreen and "0".
After seeing your additional comments you need to update the configuration file after the changes have been made. The changes you make to the string only apply to the copy in memory and are not automatically saved to the file. You will need to save each line after it has been loaded and changed and then save the updates out to the file. You should also move the process of updating the config file outside of do/while loop. If yo don't you will read/update the file for each process you check.
The example below should get you started.
#include <fstream>
#include <string>
#include <vector>
std::ifstream cfgm2("players\\config_m2.cfg", std::ios::in);
if(cfgm2.is_open())
{
std::string cfgLine;
bool changed = false;
std::vector<std::string> cfgContents;
while (std::getline(cfgm2,cfgLine))
{
// Check if this is a line that can be changed
if (std::string::npos != cfgLine.find("seta r_fullscreen"))
{
// Find the value we want to change
std::string::size_type pos = cfgLine.find("\"0\"");
if(pos != std::string::npos)
{
// We found it, not let's change it and set a flag indicating the
// configuration needs to be saved back out.
cfgLine.replace(pos, 3, "\"1\"");
changed = true;
}
}
// Save the line for later.
cfgContents.push_back(cfgLine);
}
cfgm2.close();
if(changed == true)
{
// In the real world this would be saved to a temporary and the
// original replaced once saving has successfully completed. That
// step is omitted for simplicity of example.
std::ofstream outCfg("players\\config_m2.cfg", std::ios::out);
if(outCfg.is_open())
{
// iterate through every line we have saved in the vector and save it
for(auto it = cfgContents.begin();
it != cfgContents.end();
++it)
{
outCfg << *it << std::endl;
}
}
}
}
// Rest of your code
Process32First(proc_Snap , &pe32);
do {
// some loop doing something I don't even want to know about
} while ( /*...*/ );

Partial line from cpp file ending up in output file - haunted code?

I'm sorry, it would be extremely difficult to make a fully reproducible version of the error --- so please bare with my schematic code.
This program retrieves information from a web page, processes it, and saves output to an ASCII file. I also have a 'log' file (FILE *theLog---contained within a Manager object) for reporting errors, etc.
Some background methods:
// Prints string to log file
void Manager::logEntry(const string lstr) {
if( theLog != NULL ) { fprintf(theLog, "%s", lstr.c_str()); }
}
// Checks if file with given name already exists
bool fileExists(const string fname) {
FILE *temp;
if( temp = fopen(fname.c_str(), "r") ) {
fclose(temp);
return true;
} else { return false; }
}
// Initialize file for writing (some components omitted)...
bool initFile(FILE *&oFile, const string fname) {
if(oFile = fopen(fname.c_str(), "w") ) { return true; }
else { return false; }
}
The stuff causing trouble:
// Gets data from URL, saves to file 'dataFileName', input control flag 'foreCon'
// stu is some object that has string which i want
bool saveData(Manager *man, Stuff *stu, string dataFileName, const int foreCon) {
char logStr[CHARLIMIT_LARGE]; // CHARLIMIT_LARGE = 2048
sprintf(logStr, "Saving Data...\n");
man->logEntry( string(logStr) ); // This appears fine in 'theLog' correctly
string data = stu->getDataPrefixStr() + getDataFromURL() + "\n"; // fills 'data' with stuff
data += stu->getDataSuffixStr();
if( fileExists(dataFileName) ) {
sprintf(logStr, "save file '%s' already exists.", dataFileName.c_str() );
man->logEntry( string(logStr) );
if( foreCon == -1 ) {
sprintf(logStr, "foreCon = %d, ... exiting.", foreCon); // LINE 'A' : THIS LINE ENDS UP IN OUTPUT FILE
tCase->logEntry( string(logStr) );
return false;
} else {
sprintf(logStr, "foreCon = %d, overwriting file.", foreCon); // LINE 'B' : THIS LINE ENDS UP IN LOG FILE
tCase->logEntry( string(logStr) );
}
}
// Initialize output file
FILE *outFile;
if( !initFile(outFile, dataFileName) ) {
sprintf(logStr, "couldn't initFile '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return false;
}
fprintf(outFile, "%s", data.c_str()); // print data to output file
if( fclose(outFile) != EOF) {
sprintf(logStr, "saved to '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return true;
}
return false;
}
If the file already exists, AND 'int foreCon = -1' then the code should print out line 'A' to the logFile. If the file exists and foreCon != -1, the old file is overwritten with data. If the file doesn't exist, it is created, and the data is written to it.
The result however, is that a broken up version of line 'A' appears in the data file AND line 'B' is printed in the log file!!!!
What the data file looks like:
.. exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
The second line and onward look correct, but there is an extra line that contains part of line 'A'.
Now, the REALLY WEIRD PART. If I comment out everything in the if( foreCon == -1) { ... } block, then the data file looks like:
%d, ... exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
There is still an extra line, but it is the LITERAL CODE copied into the data file.
I think there is a poltergeist in my code. I don't understand how any of this could happen.
Edit: I've tried printing to console the data string, and it gives the same messed up values: i.e. %d, ... exiting.20130127 161456 - so it must be something about the string instead of the FILE *
Answer based on your latest comment:
getDataPrefixStr() ends up returning a string which starts with
something like string retStr = COMCHAR + " file created on ..."; such
that const char COMCHAR = '#';. Could the COMCHAR be the problem??
You can't add characters and string literals (which are arrays of char, not strings) like that.
You're adding 35 (the ASCII for "#") to the address of " file created on ... ", i.e. getDataPrefixStr() is whatever starts 35 characters from the start of that string. Since all literal strings are stored together in the same data area, you'll get strings from the program in the output.
Instead, you cold do
const string COMCHAR = "*";
string retStr = COMCHAR + " file created on ...";
It could be that logStr is too short and that it is causing data to be overwritten in other buffers (did you double check CHARLIMIT_LARGE?). You can diagnose this by commenting all writes to logStr (sprintf) and see if data is still corrupted. In general, your code is vulnerable to this if a user can set dataFileName (to be a very long string); use snprintf or ostringstream instead.
Otherwise, I would guess that either stu->getDataPrefixStr() or getDataFromURL() are returning corrupted results or return type char* instead of string. Try printing these values to the console directly to see if they are corrupted or not. If they return a char*, then data = stu->getDataPrefixStr() + getDataFromURL() will have undefined behavior.
if( temp = fopen(fname.c_str(), 'r') ) {
should be
if( temp = fopen(fname.c_str(), "r") ) {