I'm not able to read and write to the same file - c++

I'm trying to have the code read and repeat the last line of text in an input file, and put an underscore line right below it. As the code is, it will cout the last line to the terminal but won't output anything to the file. If I remove the while(getline()), the underscore line will appear but then it can't find the line string.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string underscoreDiv (int lengthText){
string underscores;
for(int i{}; i<lengthText; i++)
{
underscores += "_";
}
return underscores + "\n";
}
int main(){
fstream fileApp("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt", ios::in | ios::app);
if(fileApp.is_open()){
string underscore;
string line;
underscore=underscoreDiv(80);
while(getline(fileApp, line)){} ///removing this line
cout<<line;
fileApp<<"\n"<<line<<endl;
fileApp<<underscore<<endl;
fileApp.close();
}
else{
cout<<"Text file not file";
}
system("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt");
return 0;
}
I wrote this modified code that reads the last line and prints it and then prints the underscore line but I'm having to open, close, then reopen the input file which makes it too slow.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string underscoreDiv (int lengthText){
string underscores;
for(int i{}; i<lengthText; i++)
{
underscores += "_";
}
return underscores + "\n";
}
int main(){
fstream fileApp("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt", ios::app | ios::in);
string underscore;
string line;
if(fileApp.is_open()){
underscore=underscoreDiv(80);
while(getline(fileApp, line)){}
cout<<line;
fileApp<<"\n"<<line<<endl; ///these 2 lines don't do anything
fileApp<<underscore<<endl;
fileApp.close();
}
else{
cout<<"Text file not file";
}
fileApp.open("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt", ios::app | ios::in);
fileApp<<"\n"<<line<<endl;
fileApp<<underscore<<endl;
///system("C:\\Users\\trist\\OneDrive\\Documents\\Notes_application\\Notes_app.txt"); ///too lazy to write a close statement here.
return 0;
}

The problem that you encounter has to do with the state of the stream. After each IO operation the result of that operation is stored in internhal state bits of the stream.
There is a very good overview in the CPP reference here. Please especially look at the table at the bottom of this page.
After the execution of the loop while(getline(fileApp, line)){} the eof bit of the stream is set. And only because of that, the while loop stops. Look in the table. If the eof bit is set, the bool function will return false. And since the while-loop excpects a boolean value, the bool function of the stream (that will be returned by std::getline) will be called.
So, now that we reached the end of the file, the stream is in fail state.
And then, no further IO operation on this stream will be executed.
Solution: Call the streams clear function after your while loop: fileApp.clear();
Recommendation: In general you should always check the state of a stream after IO operations.

Related

How to write to middle of a file in C++?

I think this should be quite simple, but my googling didn't help so far... I need to write to an existing file in C++, but not necessarily at the end of the file.
I know that when I just want to append text to my file, I can pass the flag ios:app when calling open on my stream object. However, this only let's me write to the very end of the file, but not into its middle.
I made a short program to illustrate the issue:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
string path = "../test.csv";
fstream file;
file.open(path); // ios::in and ios::out by default
const int rows = 100;
for (int i = 0; i < rows; i++) {
file << i << "\n";
}
string line;
while (getline(file, line)) {
cout << "line: " << line << endl; // here I would like to append more text to certain rows
}
file.close();
}
You cannot insert in the middle of the file. You have to copy the old file to a new file and insert whatever you want in the middle during copying to the new file.
Otherwise, if you intend to overwrite data/lines in the existing file, that is possible by using std::ostream::seekp() to identify the position within the file.
You could write to the end and swap lines until it ends up in the right position.
Here's what I had to do.
Here's the test.txt file before:
12345678
12345678
12345678
12345678
12345678
Here's a sample of my program
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
fstream& goToLine(fstream& file, int line){
int charInLine = 10; //number of characters in each line + 2
//this file has 8 characters per line
int pos = (line-1)*charInLine;
file.seekg(pos);
file.seekp(pos);
return file;
}
fstream& swapLines(fstream& file, int firstLine, int secondLine){
string firstStr, secondStr;
goToLine(file,firstLine);
getline(file,firstStr);
goToLine(file,secondLine);
getline(file,secondStr);
goToLine(file,firstLine);
file.write(secondStr.c_str(),8); //Make sure there are 8 chars per line
goToLine(file,secondLine);
file.write(firstStr.c_str(),8);
return file;
}
int main(){
fstream file;
int numLines = 5; //number of lines in the file
//open file once to write to the end
file.open("test.txt",ios::app);
if(file.is_open()){
file<<"someText\n"; //Write your line to the end of the file.
file.close();
}
//open file again without the ios::app flag
file.open("test.txt");
if(file.is_open()){
for(int i=numLines+1;i>3;i--){ //Move someText\n to line 3
swapLines(file,i-1,i);
}
file.close();
}
return 0;
}
Here's the test.txt file after:
12345678
12345678
someText
12345678
12345678
12345678
I hope this helps!
Based on my basic knowledge of Operating systems, I would say it is not possible.
I mean it is not impossible to make an OS that can allow such functionality with current storage technologies, but doing so would always lead to wastage of space in segments.
But I am not aware of any technology that can allow that. Although some cloud-based DataBases do use such kinds of functionally (like inserting content in middle of a file), but they are made specifically for that DBMS software, with very specifically targeted hardware, and they may also have some custom-built kernels to perform such tasks.

read word to file c++

I want get from user word and put into place in file where is certian word.
I have problem with getline.
In new file I don't have any new line.
When I add Newline to string which I write to file, this line is read two times and writeto file to times (I think that bcoz I saw this newfile)
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string contain_of_file,bufor,word,empty=" ",new_line="\n";
string conection;
string::size_type position;
cout<<"Give a word";
cin>>word;
ifstream NewFile;
ofstream Nowy1;
Nowy1.open("tekstpa.txt", ios::app);
NewFile.open("plik1.txt");
while(NewFile.good())
{
getline(NewFile, contain_of_file);
cout<<contain_of_file;
position=contain_of_file.find("Zuzia");
if(position!=string::npos)
{
conection=contain_of_file+empty+word+new_line;
Nowy1<<conection;
}
Nowy1<<contain_of_file;
}
Nowy1.close();
NewFile.close();
cin.get();
return 0;
}
The problem here is not your reading. directly, but about your loop.
Do not loop while (stream.good()) or while (!stream.eof()). This is because the eofbit flag is not set until after you try to read from beyond the file. This means that the loop will iterate one extra time, and you try to read from the file but the std::getline call will fails but you don't notice it and just continue as if nothing happened.
Instead do
while (std::getline(NewFile, contain_of_file)) { ... }
And an unrelated tip: The variable conection is not needed, you can instead do just
Nowy1 << contain_of_file << ' ' << word << '\n';

Write a C++ pgm to read from a file "input.txt" , whenever a period is encountered insert newline and write modified content to "output.txt"

Question: Write a program in C++ to read from a file "input.txt" and whenever a period is encountered in the file "input.txt" insert a newline character and then write the modified contents to a new file "output.txt" and save it. Finally print the number of periods encountered.
I wrote the following program however this program compiles fine but it doesn't execute so please help me out. Thanks and regards.
#include<iostream>
#include<fstream>
using namespace std;
int main(){
int count = 0;
ofstream myFile;
char ch;
myFile.open("D:\\Files\\input.txt");
myFile<<"Hi this is Yogish. I'm from Bengaluru, India. And you are ??"<<endl;
myFile.close();
ofstream myHandler;
myHandler.open("D:\\Files\\output.txt");
fstream handler;
handler.open("D:\\Files\\input.txt");
if(handler.is_open()){
while(!handler.eof()){
handler>>ch;
if(ch != '.'){
handler<<ch;
}
else{
myHandler<<ch<<'\n';
handler<<'.'<<'\n';
count++;
}
}
}
cout<<"The number of periods : "<<count++<<endl;
system("pause");
}
I assume the question means that you only have to write the modified contents to the new file output.txt. At present you are trying to write into input file as well.
You should read the entire line in one string and then use std::replace_if algorithm from the <algorithm> header.
Also, in general, you should avoid the check for termination condition as file.eof() since it is only set after the read operation. Hence, there is a possibility that the eof() bit is set after you read a character, which means that the last character read is invalid and you would output this invalid character to the file.
It will result in undefined behaviour.
Instead you should try something like:
bool isDot( const char& character ) {
return character == '.';
}
And in your main function:
std::string newLine;
// enter the loop only if the read operation is successful
while ( getline( handler, newLine ) ) {
count += std::count_if( newLine.begin(), newLine.end(), isDot );
std::replace_if( newLine.begin(), newLine.end(), isDot, '\n' );
myHandler << newLine;
}

Read File line by line to variable and loop

I have a phone.txt like:
09236235965
09236238566
09238434444
09202645965
09236284567
09236235965
..and so on..
How can I process this data line by line in C++ and add it to a variable.
string phonenum;
I know I have to open the file, but after doing so, what is done to access the next line of the file?
ofstream myfile;
myfile.open ("phone.txt");
and also about the variable, the process will be looped, it will make the phonenum variable the current line its processing from the phone.txt.
Like if the first line is read phonenum is the first line, process everything and loop; now the phonenum is the 2nd line, process everything and loop until the end of the last line of the file.
Please help. I'm really new to C++. Thanks.
Read the comments inline please. They will explain what is going on to assist you in learning how this works (hopefully):
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
int main(int argc, char *argv[])
{
// open the file if present, in read mode.
std::ifstream fs("phone.txt");
if (fs.is_open())
{
// variable used to extract strings one by one.
std::string phonenum;
// extract a string from the input, skipping whitespace
// including newlines, tabs, form-feeds, etc. when this
// no longer works (eof or bad file, take your pick) the
// expression will return false
while (fs >> phonenum)
{
// use your phonenum string here.
std::cout << phonenum << '\n';
}
// close the file.
fs.close();
}
return EXIT_SUCCESS;
}
Simple. First, note that you want an ifstream, not an ofstream. When you're reading from a file, you're using it as input - hence the i in ifstream. You then want to loop, using std::getline to fetch a line from the file and process it:
std::ifstream file("phone.txt");
std::string phonenum;
while (std::getline(file, phonenum)) {
// Process phonenum here
std::cout << phonenum << std::endl; // Print the phone number out, for example
}
The reason why std::getline is the while loop condition is because it checks the status of the stream. If std::getline fails in anyway (at the end of your file, for example), the loop will end.
You can do that :
#include <fstream>
using namespace std;
ifstream input("phone.txt");
for( string line; getline( input, line ); )
{
//code
}

How do I read a text file from the second line using fstream?

How can I make my std::fstream object start reading a text file from the second line?
Use getline() to read the first line, then begin reading the rest of the stream.
ifstream stream("filename.txt");
string dummyLine;
getline(stream, dummyLine);
// Begin reading your stream here
while (stream)
...
(Changed to std::getline (thanks dalle.myopenid.com))
You could use the ignore feature of the stream:
ifstream stream("filename.txt");
// Get and drop a line
stream.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
// Get and store a line for processing.
// std::getline() has a third parameter the defaults to '\n' as the line
// delimiter.
std::string line;
std::getline(stream,line);
std::string word;
stream >> word; // Reads one space separated word from the stream.
A common mistake for reading a file:
while( someStream.good() ) // !someStream.eof()
{
getline( someStream, line );
cout << line << endl;
}
This fails because: When reading the last line it does not read the EOF marker. So the stream is still good, but there is no more data left in the stream to read. So the loop is re-entered. std::getline() then attempts to read another line from someStream and fails, but still write a line to std::cout.
Simple solution:
while( someStream ) // Same as someStream.good()
{
getline( someStream, line );
if (someStream) // streams when used in a boolean context are converted to a type that is usable in that context. If the stream is in a good state the object returned can be used as true
{
// Only write to cout if the getline did not fail.
cout << line << endl;
}
}
Correct Solution:
while(getline( someStream, line ))
{
// Loop only entered if reading a line from somestream is OK.
// Note: getline() returns a stream reference. This is automatically cast
// to boolean for the test. streams have a cast to bool operator that checks
// good()
cout << line << endl;
}
The more efficient way is ignoring strings with std::istream::ignore
for (int currLineNumber = 0; currLineNumber < startLineNumber; ++currLineNumber){
if (addressesFile.ignore(numeric_limits<streamsize>::max(), addressesFile.widen('\n'))){
//just skipping the line
} else
return HandleReadingLineError(addressesFile, currLineNumber);
}
HandleReadingLineError is not standart but hand-made, of course.
The first parameter is maximum number of characters to extract. If this is exactly numeric_limits::max(), there is no limit:
Link at cplusplus.com: std::istream::ignore
If you are going to skip a lot of lines you definitely should use it instead of getline: when i needed to skip 100000 lines in my file it took about a second in opposite to 22 seconds with getline.
Call getline() once to throw away the first line
There are other methods, but the problem is this, you don't know how long the first line will be do you? So you can't skip it till you know where that first '\n' is. If however you did know how long the first line was going to be, you could simply seek past it, then begin reading, this would be faster.
So to do it the first way would look something like:
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
// Open your file
ifstream someStream( "textFile.txt" );
// Set up a place to store our data read from the file
string line;
// Read and throw away the first line simply by doing
// nothing with it and reading again
getline( someStream, line );
// Now begin your useful code
while( !someStream.eof() ) {
// This will just over write the first line read
getline( someStream, line );
cout << line << endl;
}
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string textString;
string anotherString;
ifstream textFile;
textFile.open("TextFile.txt");
if (textFile.is_open()) {
while (getline(textFile, textString)){
anotherString = anotherString + textString;
}
}
std::cout << anotherString;
textFile.close();
return 0;
}
this code can read file from your specified line from file but you have to make file in file explorer before hand my file name is "temp" code is given below
https://i.stack.imgur.com/OTrsj.png
hope this can help
You can use ignore function as follow:
fstream dataFile("file.txt");
dataFile.ignore(1, '\n'); // ignore one line
#include <fstream>
#include <iostream>
using namespace std;
int main ()
{
char buffer[256];
ifstream myfile ("test.txt");
// first line
myfile.getline (buffer,100);
// the rest
while (! myfile.eof() )
{
myfile.getline (buffer,100);
cout << buffer << endl;
}
return 0;
}