C++ program to find and replace a string in file - c++

This is a beginner question. I am trying to find a string in text file and replace it back to the same file. Following code works fine collecting contents of file into buffer and replace the string . But when i try to keep the data back to same file, it is filled with some junk character. Please let me know what I am doing wrong ?
#include <iostream>
#include <fstream>
using namespace std;
const char *fileName = "Test.dat";
int main () {
// This is where we'll put the stuff we read from file
char buffer[ 100 ];
ifstream finout(fileName, ios_base::in | ios_base::out | ios_base::binary);
if(!finout.is_open())
{
cout << "Can not open file " << endl;
return(1);
}
while (finout.getline(buffer, sizeof(buffer))
{
string g( buffer );
string search = "am";
string replace = "was";
long j;
if ( (j = g.find(str2)) != string::npos)
{
g.replace(g.find(str2), str2.length(), "str");
finout.write((char *) &g, sizeof(g)); //This won't work
}
cout << g << "\n";
finout.close();
return 0;
}
My Test.dat file contain following information:
Hello, How are you?
I am fine.

When you are read/write as a text file, do not open it by ios_base::binary
You put finout.close(); inside your reading loop, so it just work for one line.
When you are reading/writing a file as a text, use text stream methods and operators.

You are trying to read the size of your string with the sizeof() operator.
This wont work, because it is a keyword, that gives you the non-dynamic size of the object or type.
You should use g.size() to access the string size!
But on the first place, you can handle the stream handle your bug:
finout << g;
will do the job.

First, you want to both read and write a file, so use fstream not ifstream.
Second, you have a text file, so don't use ios_base::binary
Third (char*) &g where g is std::string doesn't work, use g.c_str() instead. (simply write
finout << g;
Now you can start thinking of the implmentation...

Related

How to read a .txt file using c-strings?

I'm working on a project for school and I need to read in text from a file.
Sounds easy peasy, except my professor put a restriction on the project: NO STRINGS
("No string data types or the string library are allowed.")
I've been getting around this problem by using char arrays; however, I'm not sure how to use char arrays to read in from a file.
This is an example from another website on how to read in a file with strings.
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << line << '\n';
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
The important line here is while ( getline (myfile,line) );
getline accepts an ifstream and a string (not char array).
Any help is appreciated!
Use cin.getline. Refer to this site for the format: cin.getline.
You can write something like this:
ifstream x("example.txt");
char arr[105];
while (x.getline(arr,100,'\n')){
cout << arr << '\n';
}
ifstream has a method named get() that reads the contents of the file into a char array. get() takes, as parameters, a pointer to the array, and the size of the array; then fills the array up to the given size, if possible.
After get() returns, use the gcount() method to determine how many characters have been read.
You can use then, and a simple logical loop, to repeatedly read the contents of the file, in size-chunks, into an array, and collect all the chunks read into a single array, or a std::vector.
You can use the int i = 0; while (scanf("%c", &str[i ++]) != EOF) to judge the end of text input. str is the char array include newline which you wanted, and i is the input size.
You can also use while(cin.getline()) to read per line every loop in C++ style:
istream& getline (char* s, streamsize n, char delim ); just like below:
const int SIZE = 100;
const int MSIZE = 100;
int main() {
freopen("in.txt", "r", stdin);
char str[SIZE][MSIZE];
int i = -1;
while (cin.getline(str[++ i], MSIZE)) {
printf("input string is [%s]\n", str[i]);
}
}

fstream using formatted data

i am new to this site , and this my first question !
i have a question about fstream function .
fstream f("new.dat",ios::out|ios::in);
fstream is for both input and output , so when we use it like this , and there is a new.dat file before it will output and input both . but it is strange , when i do that , it will output data correctly , but it is unable to input .
i found out if you close it , and reopen it , it will input . why it is like that??
int main()
{
fstream writeFile("newFile.dat", ios::out|ios::in);
char i[3];
char u[3]="HI";
if (!writeFile)
{
cerr << "error" << endl;
}
writeFile << u <<endl;
writeFile >> i;
cout << i << endl;
}
this is my full code , and result is an empty line.
The fstream object has a position in its output file, and since you opened it just for output and input without any position or writing modifiers, that position is at the end of the file. When you output i to the file, writeFile writes i to the file, and then moves its position past i so when you ask it to write more, you don't overwrite i.
You can reset the position to the start of the file with a call to writeFile.seekg(0), which places that internal position at the 0 position in the file (at the start).
If you're curious about stream manipulation, I'd suggest a look at cppreference.com and specifically its documentation on c++'s input and output libraries here.
Couple things going on here:
You can't open a file for reading if it doesn't exist, this includes a file you want to read and write. No file, no open.
Once you manage to open a file, the stream keeps track of where it is in the file. As you read or write, obviously the location moves.
There is only one location marker in the stream, so you can read to where you want to write, then write. Unfortunately this means any further reading will pick up after the write. If that's not what you want, get and store the current location (with tellg) before writing, and seek (with seekg) to the stored location after writing.
This has some problems such as what if the block of data you wish to insert is longer or shorter than the block of data you want to overwrite? The simple solution to this problem is read into buffer, edit buffer, write buffer back to file.
When you open a file and start writing into it, you overwrite whatever was in the file. If you want to add to a file, open with ios::app. This sets the stream's location to the end of the file. I am unaware of any sort of insert that pushes existing data along as you write in new data.
Some simple file handling example code
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
fstream f1("filename", ios::out);
if (f1.is_open())
{
if (f1 << "Hi")
{
cout << "wrote"<<endl;
}
f1.close();
}
fstream f2("filename", ios::out|ios::app);
if (f2.is_open())
{
if (f2 << " there!")
{
cout << "appended"<<endl;
}
f2.close();
}
fstream f3("filename", ios::in);
if (f3.is_open())
{
cout << f3.rdbuf()<< endl;
f3.close();
}
fstream f4("filename", ios::in|ios::out);
if (f4.is_open())
{
f4.seekg(3);
if (f4 << "Fred!")
{
cout << "overwrote"<<endl;
}
f4.close();
}
fstream f5("filename", ios::in);
if (f5.is_open())
{
cout << f5.rdbuf()<< endl;
f5.close();
}
// note the extra ! on the end left over from Hi there! I do not know how
// to get rid of this. I have always just done stuff like this to get around it.
fstream f6("filename", ios::in);
stringstream s1;
string token;
f6 >> token;
s1 << token << " Tim!";
f6.close();
fstream f7("filename", ios::out);
f7 << s1.rdbuf();
f7.close();
// and then moved temp over filename.
fstream f8("filename", ios::in);
cout << f8.rdbuf()<< endl;
f8.close();
}

How to replace value in CSV file

I have CSV file build like this:
1;name;2;5;
2;diff_name;3;5;
And I would like to be able to replace the 5 with 2 before reading the next line.
So I am reading the file:
file>>number1;
file.ignore( numeric_limits < streamsize >::max(), ';' );
file>>data;
and so on. And I was trying to write it this way:
long pos = plik.tellp();
plik.seekp (pos-2);
plik<<other_number;
But it breaks the file. I don't know how but it's not reliable. the pos somehow depends on the file lenght and I can't make it work every time (with different valuse in file) this way. Is there some other way to replace the value here? Is there an easy way?
As said by Joachim Pileborg in a comment, you can't really (and simply) directly replace in the file. The solution is to write in an other file. If your first file is enough small, you can use your memory in place of a second file, and write the result in the first file.
My code :
#include <fstream>
#include <iostream>
using namespace std;
int main(){
ifstream ifile("file.csv"); //First file
ofstream ofile("filenew.csv"); //File with replaced fields
char s[100];
string temp;//useful for the replacement
int count=0;//fields counter (useful for replacement)
while(ifile.good()){
ifile.getline(s, 100, ';'); //We read the file field by field
count++;
if(ifile.good()){
if(count==3){ //The third field is stored in a temp variable
temp = s;
}
else if(count==4){//And we put the fourth field before the third
ofile << s;
ofile << ';';
ofile << temp;
ofile << ';';
count=0;
}
else{
if(count==5)count=0;
ofile << s;
ofile << ';';
}
}
}
}

C++ Read and modify a line in a txt file

I'm facing some difficulties with the searching of the position of the first occurrence of a word.
The software have to search into a determined txt file a specified word. So I've used the fstream lib to open and after all write something. But I have no clue how I will make the software to get the exactly position of the that word. All I got is this:
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
int main() {
fstream myfile; // fstream to read and write the myfile
string cText = "\n--something--!\n"; // what it will write
string line; // will assign the getline() value;
unsigned int pos = 0; //will be assigned to "seekp" - where it will start to write
myfile.open( "example.html", ios::binary | ios::in | ios::out );
if( !myfile ) {
cout << "File does not exist!" << endl;
cin.get();
return false;
}
do {
size_t found = line.find("<head>");
cout << string::npos << endl;
if (found != string::npos) {
cout << line << endl;
}
}while( getline(myfile, line));
myfile.seekp( pos+1, ios::beg );
//myfile.write( cText, strlen( cText ) ); //write cText
myfile.close();
cin.get();
return 0;
}
Any suggestions?
Don't try to change the bytes in your file. Make a new file, copy the lines over until you find the one you want to replace, output your new line, then output the rest of your lines. Because unless you're replacing one string, with another string with exactly the same number of characters, you're going to be overriding the next line in your file - and there's no good way to avoid that.
If you want to, you can then delete the original file, and rename your new file to that name.

Read a binary file (jpg) to a string using c++

I need to read a jpg file to a string. I want to upload this file to our server, I just find out that the API requires a string as the data of this pic. I followed the suggestions in a former question I've asked Upload pics to a server using c++ .
int main() {
ifstream fin("cloud.jpg");
ofstream fout("test.jpg");//for testing purpose, to see if the string is a right copy
ostringstream ostrm;
unsigned char tmp;
int count = 0;
while ( fin >> tmp ) {
++count;//for testing purpose
ostrm << tmp;
}
string data( ostrm.str() );
cout << count << endl;//ouput 60! Definitely not the right size
fout << string;//only 60 bytes
return 0;
}
Why it stops at 60? It's a strange character at 60, and what should I do to read the jpg to a string?
UPDATE
Almost there, but after using the suggested method, when I rewrite the string to the output file, it distorted. Find out that I should also specify that the ofstream is in binary mode by ofstream::binary. Done!
By the way what's the difference between ifstream::binary & ios::binary, is there any abbreviation for ofstream::binary?
Open the file in binary mode, otherwise it will have funny behavior, and it will handle certain non-text characters in inappropriate ways, at least on Windows.
ifstream fin("cloud.jpg", ios::binary);
Also, instead of a while loop, you can just read the whole file in one shot:
ostrm << fin.rdbuf();
You shouldn't read the file to a string because it is legal for a jpg to contain values that are 0. However in a string, the value 0 has a special meaning (it's the end of string indicator aka \0). You should instead read the file into a vector. You can do this easily like so:
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
int main(int argc, char* argv[])
{
std::ifstream ifs("C:\\Users\\Borgleader\\Documents\\Rapptz.h");
if(!ifs)
{
return -1;
}
std::vector<char> data = std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
//If you really need it in a string you can initialize it the same way as the vector
std::string data2 = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
std::for_each(data.begin(), data.end(), [](char c) { std::cout << c; });
std::cin.get();
return 0;
}
Try opening the file in binary mode:
ifstream fin("cloud.jpg", std::ios::binary);
At a guess, you were probably trying to read the file on Windows and the 61st character was probably 0x26 -- a control-Z, which (on Windows) will be treated as marking the end of the file.
As far as how to best do the reading, you end up with a choice between simplicity and speed, as demonstrated in a previous answer.