Deleting the contents of the file not working - c++

I'm writing, reading and deleting the content of a file. Eeverything works fine except the delete part, as when I press y it says deleted but doesn't display any records.
typedef struct ch
{
char str[10];
};
void disp(ch d)
{
cout<<"\n"<<d.str<<"\n";
}
//delete part
cout<<"\nwant to delete??";
char c;
cin>>c;
if(c=='y')
{
char s[10];
cout<<"nter - ";
cin>>s;
file.seekg(0);
int found=0;
fstream temp("temp.dat",ios::in|ios::out|ios::app);
while(file.read((char *)&dta,sizeof(dta)))
{
if(strcmp(dta.str,s)==0)
{
found=1;
cout<<"deleted";
}
else
temp.write((char *)&dta,sizeof(dta));
}
if(!found)
cout<<"not found";
remove("new.dat");
rename("temp.dat","new.dat");
temp.close();
file.open("new.dat",ios::in|ios::out|ios::app);
}

EDIT: Looking over your code again, I see the problem is that you are using the ios::app although you have also passed ios::in.
ios::app -- All output operations are performed at the end of the file, appending
the content to the current content of the file. This flag can only be
used in streams open for output-only operations.
http://www.cplusplus.com/doc/tutorial/files/
Old Post:
Take a look at the following code example:
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
using namespace std;
const char g_szTestData[] = "This is some test da$$$$######ta and some more"
" tes$$$$######ting";
int main(int argc, char** argv)
{
fstream file("new.dat", ios::in|ios::out);
file << g_szTestData << flush;
cout << "Do you want to delete all $$$$######?";
if (cin.get() == 'y')
{
char szBuffer[10]; //< File read buffer
char szString[11] = "$$$$######"; //< 10 characters + '\0'
bool bFound = false;
fstream temp("temp.dat", ios::out);
file.seekg(0, file.beg);
while (file.read(szBuffer, sizeof(szBuffer)))
{
if (strncmp(szBuffer,szString,10) == 0) bFound = true;
else temp.write(szBuffer, sizeof(szBuffer));
}
temp.flush();
temp.close();
if (bFound)
{
file.close();
remove("new.dat");
rename("temp.dat", "new.dat");
file.open("new.dat",ios::in|ios::out);
}
else cout << "Pattern Not Found!" << endl;
}
/* Do something with the contents of file. */
// Lets clean up at the end
file.close();
return 0;
}
In this example, a file is created and the contents g_szTestData are added, you can verify this by opening the file (before pressing 'y').
The user is then asked if they would like to delete a string of 10 characters $$$$###### from the file. If the user wishes to proceed, a new file is opened temp.dat. The program gradually walks through the existing new.dat file (10 characters at a time). If the string the program reads from new.dat is not the target string, the string is written to the temp file.
If the target string is found, both files are closed, the old file is deleted and the new file is renamed to the name of the old file. The new file is then opened so the program can do additional work on its contents.
Instead of having a fixed 10 character string, it is possible to ask the user for the string they wish to remove using cin >> szString but the string would need to be 10 characters long.

Your code work as expected, it only display deleted because disp() isn't called anywhere.
#include <iostream>
#include <string.h>
#include <fstream>
#include <stdio.h>
using namespace std;
typedef struct {
char str[16];
} ch;
static void disp(ch d) {
cout<<d.str<<"\n";
}
int main(int argc, char **argv) {
fstream file;
ch dta;
file.open("new.dat",ios::in|ios::out|ios::trunc);
for (int i=0; i<3; i++) {
snprintf((char *)&dta.str, sizeof(dta.str)-1, "rec%d", i);
file.write((char *)&dta,sizeof(dta));
}
//delete part
{
char s[16] = "rec1";
file.seekg(0);
int found=0;
fstream temp("temp.dat",ios::out);
while(file.read((char *)&dta,sizeof(dta))) {
if(strcmp(dta.str, s)==0) {
found=1;
cout<<"deleted * ";
disp(dta);
} else {
temp.write((char *)&dta,sizeof(dta));
disp(dta);
}
}
if(!found)
cout<<"not found";
file.close();
remove("new.dat");
rename("temp.dat","new.dat");
temp.close();
}
}

Related

Input/Output operations on characters

I'm learning file handling in C++. I was implementing the exact same code in my Code::Blocks 20.03 as given in one of the programs of the book, but it's displaying no output after line 26, i.e.
cout<<"\nReading the file contents: ";
I've figured maybe these lines are erraneous, but I can't debug how:
while(file){
file.get(ch);
cout<<ch;
}
Here is the full code:
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
using namespace std;
int main()
{
char String[80];
cout<<"Enter a string: ";
cin>>String;
int len = strlen(String);
fstream file;
cout<<"Opening the 'TEXT' file and storing the string in it.\n\n";
file.open("TEXT",ios::in|ios::out);
for(int i=0;i<len;i++)
file.put(String[i]);
file.seekg(0);
char ch;
cout<<"\nReading the file contents: ";
while(file){
file.get(ch);
cout<<ch;
}
file.close();
return 0;
}
The openmode
ios::in | ios::out
will not create a new file if "TEXT" does not exist, but result in an error. Most likely this file does not exist, so you get an error and any subsequent input and output operations on the stream are ignored. You could use
ios::in | ios::out | ios::trunc
to destroy the contents of an existing file or create a new one if the file does not exist.
For further information please consult the table on https://en.cppreference.com/w/cpp/io/basic_filebuf/open where all the different combinations of openmode are detailed.
Lastly, it's always good practice to check if the file was opened:
if(!file) { /* error */ }
You can use is_open() to check if the file was successfully opened and then use an if else loop that will validate if the file can't be found. You don't need to use ios::in|ios::out.
Here's an example that should work:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
fstream filestr;
filestr.open ("test.txt");
if (filestr.is_open())
{
filestr << "File successfully open";
filestr.close();
}
else
{
cout << "Error opening file";
}
return 0;
}
You need to check for end of file inside the loop.
while(file) {
file.get(ch);
if(ch == -1) break;
cout << ch;
}
Also, try opening the file in write mode first and then close it and open it in read mode.
cout << "Opening the 'TEXT' file and storing the string in it.\n\n";
ofstream outfile("TEXT");
if(outfile.is_open()) {
for(int i = 0; i < len; i++)
outfile.put(String[i]);
outfile.close();
}
ifstream infile("TEXT");
char ch;
if(infile.is_open()) {
cout << "\nReading the file contents: ";
while(infile) {
file.get(ch);
if(ch == -1) break;
cout << ch;
}
infile.close();
}

C++ encrypt and decrypt secret messages using files

I have my prototypes in a header file, but I need some help. I am having some trouble getting the program to compile all the way through. It appears to be getting caught in a loop with the input. Possibly some issues with the functions. Thanks in advance for any input.
#include <iostream>
#include <conio.h>
#include "header.h"
#include <fstream>
class Caesar
{
public: void readText(char *input);
void encrypt(char *input,char *output,char *key);
void decrypt(char *input,char *output,char *key);
};
void main()
{
Caesar a;
char key[1000];
ifstream fin;
int choice;
char input[100],output[100];
cout<<"\n Enter input file: ";
cin>>input;
cout << input;
cout<<"\n Enter output file: ";
cin>>output;
cout <<output;
cout<<"\n Enter key: ";
cin>>key;
cout <<key;
cout<<"\n\n 1. Encrypt\n 2. Decrypt\n\n Select choice(1 or 2): "<< endl;
cin >> choice;
cout << choice;
a.readText(input);
if(choice==1)
{
a.encrypt(input,output,key);
}
if(choice==2)
{
a.decrypt(input,output,key);
}
else
{
cout<<"\n\n Unknown choice";
}
}
void Caesar::readText(char *input)
{
ifstream reader;
char buf;
reader.open(input);
cout<<"\n\n <--- "<<input<<" --->\n";
buf=reader.get();
while(!reader.eof())
{
cout<<buf;
buf=reader.get();
}
reader.close();
}
void Caesar::encrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='a'&&buf<='z')
{
buf-='a';
buf+=key[buf];
buf%=26;
buf+='A';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
void Caesar::decrypt(char *input,char *output,char *key)
{
ifstream reader;
ofstream writer;
char buf;
reader.open(input);
writer.open(output);
buf=reader.get();
while(!reader.eof())
{
if(buf>='A'&&buf<='Z')
{
buf-='A';
buf+=26-key[buf];
buf%=26;
buf+='a';
}
writer.put(buf);
buf=reader.get();
}
reader.close();
writer.close();
readText(input);
readText(output);
}
if(choice=1)
should be
if(choice==1)
and also in the other if
In your case, you are assigning the value 1 to choice, then test if choice is true, and it is, since any non-zero numeral type is implicitly casted to bool true.
I have just executed your code and tried debugging it and took a screen shot
you program gets into a loop after entering the choice.there is no problem with cin>>.
From your comments, it seems like you're just trying to debug main. Everything seems to work fine. What are you inputting for key? If it's a very large integer, that may be your problem as it might exceed the maximum integer range and cause overflow.
Your key is an integer variable. You are inputting a string for the file name that holds your key, so that should be changed to a C string array. Change all of the passed key parameters to char* instead of int.
You have an infinite loop when the readText() function is called.
Maybe try this:
void Caesar::readText(char *input)
{
ifstream reader(input);
if(reader.is_open())
{
char buf;
cout<<"\n\n <--- "<<input<<" --->\n";
while(reader.get(buf))
{
cout << buf;
}
}
reader.close();
}
Make sure that your text file is in the same folder as your code. See this for more details: ifstream not opening file

Why does std::ifstream does not update if defined globally

I'm trying to write a simple tail program in C++. I've tried the example from this solution and it works like a charm.
Then, I tried to make the ifstream as global. Now the code does not work anymore and nothing is showed if I edit the file.
Why this behaviour? I read the manual of ifstream::open and I don't see any kind of error but the code does not work:
Opens the file identified by argument filename, associating it with
the stream object, so that input/output operations are performed on
its content. Argument mode specifies the opening mode.
Here is the non-working code:
#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();
}
}
ifstream infile;
int main() {
int last_position=-1;
for(;;) {
infile.open("/Users/alberto/tmp/test");
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);
}
}
Here is the working code:
#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;
infile.open("/Users/alberto/tmp/test");
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);
}
}
Since you open inside the loop, the stream will enter an error state on the second iteration, and keep failing after that.
Move
infile.open("/Users/alberto/tmp/test");
outside the loop, or define infile like this and don't use open at all:
ifstream infile("/Users/alberto/tmp/test");
The best alternative is to not use a global variable at all, as there's no reason for it here.
Also, find_last_linefeed fails to return anything if the file doesn't contain a linefeed, which is undefined.
—-
Regarding ifstream::open, from the standard (27.9.1.9):
Calls rdbuf()->open(s, mode | ios_base::in). If that function does not
return a null pointer calls clear(), otherwise calls setstate(failbit)
and basic_filebuf::open (27.9.1.4):
If is_open() != false, returns a null pointer

Reading in a text file from a command line and storing the content of the file into a c-string

I am learning C++ in one of my classes and I am having difficulties storing the content of a .txt file into a c string.
I have figured out how to validate that the .txt file exists but when I try storing the characters into a c-string it crashes.
This is my most recent attempt:
char * fileContent[MAX_SIZE];
ifstream ifile(argv[1]);
while (int i = 0 < MAX_SIZE)
{
ifile >> fileContent[i];
cout << fileContent[i];
if (ifile.eof())
break;
i++;
}
ifile.close();
Every-time the console gets to the loop it crashes. Are there any suggestions to help make this work?
I need it to be a c-string so that I can run the c-string through other functions. I am still pretty new to C++.
The assignment states: "Reads a text file into memory, one byte at a time"
I hope what I am trying to do is this.
Thank you
You can use the following code to read from a text file and save the string as a C-string. The output file (output.txt) contains the c-string output.
#include <string>
#include <iostream>
#include <fstream>
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
char *out_c_string;
char ch;
int index=0;
while(cin >> ch)
out_c_string[index++] = ch;
for(int i=0; i<index; i++)
cout << out_c_string[i]; // the c string of the file :)
return 0;
}
There were few bugs in your code, try this:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int MAX_SIZE = 128;
int main(int argc, char* argv[])
{
char fileContent[MAX_SIZE]; //bad idea never do that!
// use an std::vector<char> instead!
// and reverse a minimum amount of chars
// using `reserve` if you are after performance
ifstream ifile(argv[1]);
int i = 0;
while (i < MAX_SIZE)
{
ifile >> fileContent[i];
cout << fileContent[i];
if (ifile.eof())
break;
i++;
}
ifile.close();
}
Combining everyones answers, I got this as my function:
void get_file_info(char * argv, char (&fileContent) [MAX_SIZE], int & filesize ){
freopen(argv, "r", stdin);
char ch;
int index = 0;
while (cin >> noskipws >> ch)
fileContent[index++] = ch;
cout << endl << index << endl;
#if SHOW_DEBUG_CODE
for (int count = 0; count < index; count++)
cout << fileContent[count];
#endif
fclose(stdin);
}
It seems to work just fine. I will look into vectors my next free time but for right now, I am going to continue with char array.
Thank you for your suggestions.
I would do this. It's more general to cope with any size file.
void ReadFile(char*file,char**buff,int*size){
// Open file as binary putting file position at the end
ifstream is(file,ios::binary|ios::ate);
// Get the current file position, which is the file end
*size=is.tellg();
// Put file pointer back at the start
is.seekg(0,ios::beg);
// errors
if (!*size){
cout<<"Unable to open input file or file empty\n";
exit(9);
}
// allocate a buffer one bigger to allow for zero terminator
*buff=new char[*size+1];
// read the whole file in one hit
is.read(*buff,*size);
// Done. So close and zero delimit data.
is.close();
*(*buff+*size)=0;
}

Program hangs because of some reason

The following code is supposed to read records from input and store them in a file called file.dat. Then it is supposed to arrange these records in ascending order, but for some reason the program hangs in the second while loop at line "file1.seekg(-(sizeof(r)),std::ios::cur);". Can someone please tell me what's wrong?
#include <iostream>
#include <fstream>
#include <strstream>
int main()
{
std::ofstream file;
file.open("file.dat",std::ios::trunc|std::ios::binary);
if(!file)
std::cout<<"unable to open for output";
struct record
{
char code[6];
char name[20];
int i;
};
record r;
int a = 0;
while(1)
{
std::cout<<"Record " << a + 1 << std::endl;
std::cout<<"Enter character code, name and an int \n";
std::cin.ignore();
std::cin.getline(r.code,6);
std::cin.getline(r.name,20);
std::cin>>r.i;
file.write((char *)&r,sizeof(r));
std::cout<<"\nAdd another (y\\n) : ";
char c;
std::cin>>c;
if(c == 'n')
break;
a++;
std::cout<<'\n'<<'\n';
}
file.close();
std::fstream file1("file.dat",std::ios::in|std::ios::out|std::ios::binary);
if(!file1)
std::cout<<"unable to open file1";
else
{
if(a>0)
{ while(a)
{
file1.seekp(0);
for(int i = a; i>0;i--)
{
record r1;
file1.read((char *)&r,sizeof(r));
file1.read((char *)&r1,sizeof(r1));
if(r1.i < r.i)
{
file1.seekp(-(sizeof(r)*2),std::ios::cur);
file1.write((char *)&r1,sizeof(r));
file1.write((char *)&r,sizeof(r));
file1.seekg(-(sizeof(r)),std::ios::cur);
}
}
a--;
}
}
file1.close();
}
std::ifstream file2("file.dat",std::ios::binary);
if(!file2)
std::cout<<"unable to open file2";
else
while(1)
{
std::cout<<"\n\n";
file2.read((char *)&r,sizeof(r));
if(file2.eof())
break;
std::cout<<r.code<<'\t'<<r.name<<'\t'<<r.i;
}
}
first
change std::get.ignore -> std::cin.ignore()
if you want to discard one character.
it compiled well and created file.dat file..
you might check the record inside file.dat though
If you are trying to ignore the new line character entered after the actual dat, then you have to use:
std::cin.ignore();
If you want more reference on use of ignore go to this LINK