I am learning how to read and write from file . There is a problem that when I try to write (--something in the file letter for example--) after reading or read after writing in the file
using fstream
something wrong is happening. I tried to just write or read and it worked. what is the problem?
the file content is :
abcdefgh
ijklmnopqr
stuvw
xyz
and the code is :
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
fstream ioFile;
char ch;
ioFile.open("search.txt", ios::in | ios::out);
if (!ioFile)
{
cout << "problem opening the file";
goto k270;
}
while (ioFile>>ch)
{
if (ch == 'z')
{
ioFile.seekp(((int)ioFile.tellg()));
ioFile << "x";
}
}
//cout<<ioFile.rdbuf();
ioFile.close();
k270:
system("pause");
return 0;
}
Look at this answer: https://stackoverflow.com/a/17567454/11829247 it explains the error you are experiencing.
Short version: Input and output is buffered and interleaving reads and writes only work if you force buffer updates in between.
This works for me:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::fstream ioFile;
char ch;
ioFile.open("search.txt", std::ios::in | std::ios::out);
if (!ioFile)
{
std::cout << "problem opening the file";
return 1;
}
while (ioFile >> ch)
{
if (ch == 'z')
{
ioFile.seekp(-1, std::ios_base::cur);
ioFile << "x";
ioFile.flush();
}
}
ioFile.close();
return 0;
}
The difference is that I use ioFile.seekp(-1, std::ios_base::cur); to move one step back from the current position. You could also use ioFile.seekp((int)ioFile.tellg() -1); - note the -1.
Then after stepping back and overwriting the z, use ioFile.flush(); to force the write to be pushed to file. This also means that the read buffer is updated, without this the read operation just steps back in its buffer and keeps reading the same buffered z.
Related
I just started working with binary files in C++, and i have successfully written and read a (.bin) file. Here is the code:
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main()
{
char input[100];
strcpy(input, "This is a string");
fstream file("example.bin", ios::binary | ios::in | ios::out |
ios::trunc);
if(!file.is_open())
{
cerr << "Error opening file.\n";
} else {
for(int i = 0; i<= strlen(input); i++)
{
file.put(input[i]);
}
}
file.seekg(0);
char ch;
while(file.good())
{
file.get(ch);
cout<<ch;
}
}
And this worked. After that, i tried to redesign the code to just read a binary file. The major changes were: changed fstream to be an ifstream(to read), deleted the part with writing into a file. Once the code was ready, i found a file i want to read (eof0.bin). When i used the code, the only thing i got was an empty string. I noticed that the initial size of the file was 37 kilobytes, while after using my program it became 0. I want to know, how my program cleared the data in the binary file?
This is the code that i used to read the file.
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main()
{
ifstream file("eof0.bin", ios::binary | ios::in | ios::out | ios::trunc);
if(!file.is_open())
{
cerr << "Error opening file.\n";
} else {
// Nothing.
}
file.seekg(0);
char ch;
while(file.good())
{
file.get(ch);
cout<<ch;
}
}
Everything compiles, but using it on a file 37 kilobytes in size gives me a 0 kilobyte file.
You open with an openmode std::ios_base::trunc. From http://en.cppreference.com/w/cpp/io/ios_base/openmode we can see that it
discard[s] the contents of the stream when opening
So just use:
// also dropped ios::out since you only want to read, not write
ifstream file("eof0.bin", ios::binary | ios::in);
Further, this
char ch;
while(file.good())
{
file.get(ch);
cout<<ch;
}
is not an appropriate way to read the file. Think about what happens with an empty file: After opening it, it's "good" (remember, the eofbit is only set when some input operation encounters eof). Then the get fails, leaving ch as it is, thus invoking undefined behavior. Better test on the stream state directly after the input operation:
char ch;
while (file.get(ch)) {
// use ch
}
// optionally distinguish eof and fail cases
For more background on reading files, see Why is iostream::eof inside a loop condition considered wrong?
first i want to apologize for my english. I want to create a program that reads each line from a .txt file and adds for each line #" in front and " at the end. Example: #" i like apples". This is my code so far that replaces ".", "?" and ":" but i don't want that.
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <values.h>
int main()
{ ifstream f;
f.open("lala.txt");
if(!f)
{
cout<<"Eroare la deschiderea fisierului!"<<endl;
}
char s[100],x;
int i,n=0, k=0;
ofstream g("adinarez.txt");
f.seekg(0,ios::beg); //ne pozitionam la inceputul fisierului
while(f)
{
f.get(x);
s[k]=x;
n++; k++;
}
f.close();
for (i=2; i<n-1; i++)
if((s[i]>=65) && (s[i]<=90))
{ s[i-1]='\"';
s[i-2]='#';}
for(i=0;i<n;i++)
if(s[i]=='.' || s[i]=='?' || s[i]==':' || s[i]=='\0')
s[i+1]='\"';
for(i=0;i<n;i++)
g<<s[i];
g.close();
return 0;
}
For starters, if you're processing line oriented input, use
std::getline to read line by line; don't use std::istream::get.
Also, you need to check the status of the stream after the read, not
before. Something like while ( std::getline( f, line ). And line
should be an std::string, so you don't have to worry about overflow.
(Sort of. If a line contains more memory than the program can allocate,
you'll crash with an uncaught std::bad_alloc. But that will be a lot
more than a hundred characters.) Once you've got the line, you can use
the << operator on the output stream to output it. Along with
anything else you want to output.
If I correctly you understand offer this way:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::string line;
std::ifstream myfile("1.txt");
std::ofstream outfile("2.txt");
if(myfile.is_open())
{
while (getline(myfile,line))
outfile<<"#"<<line<<std::endl;
myfile.close();
}
else
std::cout << "Woops, couldn't open file!" << std::endl;
return 0;
}
I am trying to bind input stream with a file stream , I hope that input something from input stream and then automatic flush to the file stream
It does not work...I enter something from keyboard , outfile is still empty
#include <iostream>
#include <fstream>
#include <stdexcept>
using namespace std;
int main(int argc, char const *argv[])
{
ofstream outfile("outfile" , ofstream::app | ofstream::out);
if(!outfile)
throw runtime_error("Open the file error");
ostream * old_tie = cin.tie();//get old tie
cin.tie(0);//unbind from old tie
cin.tie(&outfile);//bind new ostream
string temp;
while(cin >> temp)
{
if(temp == ".")//stop input
break;
}
cin.tie(0);
cin.tie(old_tie);// recovery old tie
return 0;
}
Your program is too complicated and is misusing tie(). Try the following:
#include <iostream>
#include <fstream>
int main() {
using namespace std;
ofstream outfile("outfile" , ofstream::app | ofstream::out);
if(!outfile) {
cerr << "Open the file error";
return 1;
}
char data(0);
while(data != '.') {
cin.get(data);
cin.clear(); // Prevents EOF errors;
outfile << data;
}
return 0;
}
It reads char by char until it finds a .
Errors:
why make throw exception if you don't catch it...
close file please
do you put data from file to temp and go through it to find "." and
end program?
Why do you use pointer for old_tie use it for the first ofstream file
like this ofstream * file.
fix if statement and break
include string library -- //This might solve your problem
what is filename??
is tie(0) function to unbind?
//EDIT
Explanation:
once you find first period with find_first_of function you create a substr and copy it into outfile. The Solution is so efficent and works every time. The logic is as simple as it can get. Don't use unnecessary functions and initialize unnecessary variables because it is more complex and more prone to errors when you have too many variables.
Solution: - No need for cin.tie()
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
ofstream outfile("outfile" , ofstream::app | ofstream::out);
string s;
getline(cin, s);
int i = s.find_first_of(".");
if(i!=std::string::npos)
{
s = s.substr(0, i);
outfile << s;
}
else
{
cout << "No periods found" << endl;
}
}
Compiled code - http://ideone.com/ooj1ej
If this needs explanation please ask questions in comments below.
I would like my program to read from stdin until EOF, print all input, and repeat. I tried clearing the EOF state of stdin as follows:
#include <string>
#include <iostream>
#include <iterator>
using namespace std;
int main() {
cin >> noskipws;
while (1) {
printf("Begin");
istream_iterator<char> iterator(cin);
istream_iterator<char> end;
string input(iterator, end);
cout << input << endl;
cin.clear();
}
}
After the first input is received and printed, however, the program just infinitely prints "Begin" without waiting for further input.
The approach you're taking there won't work - when 'cin' gives you end-of-file in the context you're using, then cin is closed.
For your stated purpose of "reading text until eof, then doing it again", sorry for missing the nuance of this previously, but if you clone the stdin file descriptor and then use the clone, you can continue reading from these additional file descriptors.
Cloning iostreams isn't easy. See How to construct a c++ fstream from a POSIX file descriptor?
It's a little c-like, but this code will drain one copy of stdin until that stdin closes, then it'll make a new copy and drain that, and on.
#include <iostream>
#include <string>
void getInput(std::string& input)
{
char buffer[4096];
int newIn = dup(STDIN_FILENO);
int result = EAGAIN;
input = "";
do {
buffer[0] = 0;
result = read(newIn, buffer, sizeof(buffer));
if (result > 0)
input += buffer;
} while (result >= sizeof(buffer));
close(newIn);
return input;
}
int main(int argc, const char* argv[])
{
std::string input;
for (;;) {
getInput(input);
if (input.empty())
break;
std::cout << "8x --- start --- x8\n" << input.c_str() << "\n8x --- end --- x8\n\n";
}
}
That is because you have printf("begin"); inside your loop so you are going to get it printed again each time round the loop.
The loop will not wait for input so each time it reads data from stdin - if there is nothing there it immediately gets EOF and so continues looping until some data is present.
Let me know if this doesn't make sense - or if I got it totally wrong.
eg:
#include <string>
#include <iostream>
#include <iterator>
using namespace std;
int main() {
cin >> noskipws;
printf("Begin");
while (1) {
istream_iterator<char> iterator(cin);
istream_iterator<char> end;
string input(iterator, end);
cout << input << endl;
cin.clear();
}
}
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
ifstream is;
is.open(argv[1]);
ofstream outfile;
outfile.open(argv[2]);
char ch;
while (1)
{
ch = is.get(); // this is where test.txt is supposed
outfile.put(ch); // to be copied to test2.txt
if (is.eof())
break;
cout << ch; //this shows
}
is.close();
outfile.close();
ifstream outfile2;
outfile2.open(argv[2]);
char ch2;
while (1)
{
ch2 = outfile2.get();
if (outfile2.eof())
break;
cout << ch2; //this doesnt
}
outfile2.close();
system("PAUSE");
return 0;
}
I run it through cmd giving it 2 arguments test.txt test2.txt and it outputs what i have written in test.txt in cmd but test2.txt remains empty for some reason?
Please check the streamstate not just for eof() but also for failure. Also, after reading the last character, it wouldn't be uncommon if the streamstate was EOF even though the character was successfully read. Therefore, always try to read an element and if it succeeded, and only then, use the element:
ifstream in(argv[1]);
ofstream out(argv[2]);
char c;
while(in.get(c))
out.put(c);
To make this really efficient, use this though:
out << in.rdbuf();
In any case, check the streamstate for success:
if(!in.eof())
throw std::runtime_error("failed to read input file");
if(!out.flush())
throw std::runtime_error("failed to write output file");
for me its not coming blank but with some extra appended characters. this is because you are writing the character which you got from the old file to the new one before checking eof().
the code for writing from one file to another should be changed as
while (1)
{
ch = is.get();
if (is.eof())
break;
outfile.put(ch);
cout << ch; //this shows
}