c++ - Manual appending to files in loops - c++

I was writing a -kind of - server that works io thru files.
When I tried to append a string to the file, (I at the time did not know about ios::app, so I used a very unconventional way of doing it) it would not behave as I expected ( I tried the append function without the loop, and it worked every time):
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
ofstream* open(string fileName)
{ // opens a file and returns a pointer to the object ready for writing
vector<string> contents;
ifstream f(fileName.c_str());
if (!f)
{
cout << "No File Found";
exit(-1);
}
while (!f.eof())
{ //read
string temp;
getline(f, temp);
contents.push_back(temp);
}
f.close();
ofstream* out = new ofstream(fileName.c_str());
for (int i = 1; i < contents.size(); i++)
{ // write previous contents
*out << contents[i] << endl << flush;
}
return out;
}
void apend(string text, string fileName)
{
ofstream* file = open(fileName);
*file << text << endl << flush; // insert text
file->close();
}
string stringify(int in)
{ // converts an integer to a string
stringstream x;
x << in;
string out;
x >> out;
return out;
}
int main()
{
cout << "Welcome to the cgs v1.0 ... loading files ... " << endl;
for (int i = 0; i < 10; i++)
apend(stringify(i), "server1.txt");
return 0;
}
Upon running this I got :
server1.txt :
5
6
7
8
9
And if I ran the program again :
server1.txt:
0
1
2
3
4
5
6
7
8
9
My question is, if I used std::flush why did it somehow not write the whole file, and then when it was re-run, write the rest of the first cycle
and none of the second? - This is just curiosity.
I will now move to ios::app.
Thanks for any explanations.

Related

File reading and Manipulation

I have a text file:
1
2
3
stop
4
The code has to add each number to the previous number to get a new value and it needs to stop when it reads the "stop" in the file.
For example output would be:
1
3
5
Reading has stopped
How can I break the code for my output to be like this?
The "reading has stopped", only has to appear when there is a 'stop' in the file. otherwise the output should just be numbers.
You can read each piece of the file into a string and end if the input is "stop". If the input isn't "stop" you can convert it to an int using std::stoi
#include <string>
#include <iostream>
#include <fstream>
int main() {
std::string numberString;
std::ifstream file{ "filename.txt" };
int previousNumber = 0;
while (file >> numberString)
{
if(numberString == "stop")
{
break;
}
try {
int number = std::stoi(numberString);
std::cout << (number + previousNumber) << " ";
previousNumber = number;
} catch(...) {
std::cout << "invalid number" << std::endl;
}
}
file.close();
std::cout << "Reading has stopped" << std::endl;
}
If your text file has only one string "stop", then there's a very easy solution: you just keep reading integers until the reading fails
int main() {
ifstream ifs("test.txt");
int first = 0;
int second;
while (ifs >> second) {
cout << first + second << ' ';
first = second;
}
cout << "Reading has stopped" << endl;
return 0;
}
The problem with this solution is that if you have other strings in the text file and you want to handle them in a different way, this solution will fail.
Hope it helps.

I/O program stuck in loop C++

I'm working on a code that reads in a C++ source file and converts all ‘<’ symbols to “<” and all ‘>’ symbols to “>”. I wrote out the main method and everything compiled nicely but now that I'm actually writing out my convert function at the top of the program, I'm stuck in an infinite loop and I'm hitting a wall on what the culprit is. Could someone help me out?
I included the whole program in case the problem lies in my I/O coding but I surrounded the function with slashes. Hopefully I won't get flamed.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
//FUNCTION GOES THROUGH EACH CHARACTER OF FILE
//AND CONVERTS ALL < & > TO < or > RESPECTIVELY
//////////////THIS IS THE FUNCTION IN QUESTION//////////
void convert (ifstream& inStream, ofstream& outStream){
cout << "start" << endl;
char x;
inStream.get(x);
while (!inStream.eof()){
if (x == '<')
outStream << "<";
else if (x == '>')
outStream << ">";
else
outStream << x;
}
cout << "end" << endl;
};
///////////////////////////////////////////////////////////////////////////
int main(){
//FILE OBJECTS
ifstream inputStream;
ofstream outputStream;
string fileName;
//string outFile;
//USER PROMPT FOR NAME OF FILE
cout << "Please enter the name of the file to be converted: " << endl;
cin >> fileName;
//outFile = fileName + ".html";
//ASSOCIATES FILE OBJECTS WITH FILES
inputStream.open(fileName.c_str());
outputStream.open(fileName + ".html");
//CREATES A CONVERTED OUTPUT WITH <PRE> AT START AND </PRE> AT END
outputStream << " <PRE>" << endl;
convert(inputStream, outputStream);
outputStream << " </PRE>" << endl;
inputStream.close();
outputStream.close();
cout << "Conversion complete." << endl;
return 0;
}
It isn't a good approach to manipulate a file while you're reading it. The right way is, first read the whole file, store the data, manipulate the stored data, and then update the file. Hope this code will help you :)
void convert()
{
int countLines = 0; // To count total lines in file
string *lines; // To store all lines
string temp;
ifstream in;
ofstream out;
// Opening file to count Lines
in.open("filename.txt");
while (!in.eof())
{
getline(in, temp);
countLines++;
}
in.close();
// Allocating Memory
lines = new string[countLines];
// Open it again to stroe data
in.open("filename.txt");
int i = 0;
while (!in.eof())
{
getline(in, lines[i]);
// To check if there is '<' symbol in the following line
for (int j = 0; lines[i][j] != '\0'; j++)
{
// Checking the conditon
if (lines[i][j] == '<')
lines[i][j] = '>';
}
i++;
}
in.close();
// Now mainuplating the file
out.open("filename.txt");
for (int i = 0; i < countLines; i++)
{
out << lines[i];
if (i < countLines - 1)
out << endl;
}
out.close();
}

C++ read from file failing - g++11 - Ubuntu14

sorry for having to ask such a trivial question here, but I have to admit I can't think the reason that's causing my program to behave this way.
Here's the problem;
I'm trying to read from a file which has 32 lines with each line containing a 32-bit long binary number.
I've got a string array of size 32 and I'm trying to store each number from the file in it. It seems straight forward to me but then when I get to the line that tests getline() it jumps to the else bit and ouputs my error message. Initially it was working fine on eclipse but not from the terminal, I thought it had something to do with the permissions so I changed them all to rwx to no avail. I even tried changing the name but that caused the program to not work even in eclipse and now even going back to the original name doesn't work !!
I would appreciate if anyone can shed a light on the problem for me.
Ta!
Edit: Thank you guys for helping me investigate the problem, so far the file seems to be read just fine, I've got a cout statement in my main function to print the second element of the vector in which data is stored (after being read from the file) and it prints fine, in eclipse that is!! .When I compile the same code from the terminal and then run a.out it simply doesn't output anything.
I decided I would include my entire code and hope this will be more helpful.
Here's a quick recap to the questions I was asked:
-The file is just a simple text file that contains lines of 1's and 0's here's what it looks like
00000000000000000000000000000000
11100000000000100000000000000000
00010000000000010000000000000000
10010000000001100000000000000000
10010000000000100000000000000000
10010000000001100000000000000000
00000000000001110000000000000000
10000000001000000000000000000000
10110110010000000000000000000000
00000000000000000000000000000000
I've got a cpp file with it's corresponding header like this:
#ifndef MANCHESTER_H_
#define MANCHESTER_H_
#include <string>
#include <iostream>
#include <fstream>
#include <cmath>
#include <vector>
using namespace std;
class Manchester {
private:
struct Processor
{
enum operation { JMP,JRP,LDN,STO,SUB,CMP,STP };
char accumulator[32]; // holds results of arithmetic operations.
char controlInstruction[32]; // program counter.holds the address of an instruction.
char presentInstruction[32]; //contains the actual instruction fetched and being executed.
};
Processor processor;
public:
vector<string> store;
int static const size = 32;
Manchester();
~Manchester();
void copyFromFileToStore();
string decToBinary(int );
int binToDecimal(string s);
string getInstruction(int lineNumber);
string getOperand(int lineNumber);
};
#endif /* MANCHESTER_H_ */
Here's the .cpp file
#include "Manchester.h"
Manchester::Manchester()
{
copyFromFileToStore(); // load the program in the store.
}
Manchester::~Manchester() {}
void Manchester::copyFromFileToStore()
{
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
while( i < 10)
{
string line;
if (getline(myfile,line))
{
store.push_back(line);
i++;
}
else
{
cout << "Error while reading file!" << endl; // always outputs when running the code.
return;
}
}
myfile.close();
}
}
string Manchester::decToBinary(int number)
{
string converted="";
char holder;
do
{
holder = number % 2 + '0';
converted = holder + converted;
number = number /2;
}while (number != 0);
string filler = "";
int stringsize = converted.size();
int diff = (8 - stringsize);
if (diff > 0)
{
for (int i = 0; i < diff; i++)
filler = filler + '0';
}
converted = filler + converted;
return converted;
}
int Manchester::binToDecimal(string s)
{
int converted =0;
int power = 0;
for (int i = s.size()-1; i >= 0; --i)
{
converted += (s[i] - '0') * pow(2, power);
power++;
}
return converted;
}
And finally the file containing the main():
#include "Manchester.h"
int main()
{
Manchester baby;
cout << baby.store.at(1);
return 0;
}
These the original parts that I posted that I didn't want to delete:
string store[32];
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
while( i < 32)
{
if (getline(myfile,store[i]))
{
i++;
}
else
{
cout << "Error while reading file!" << endl; // always outputs when running the code.
return;
}
}
myfile.close();
}
Sorry I'm editing to show you what works on eclipse but not from the terminal!!!
I simply don't understand the behaviour !!!
string store[32];
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
while( i < 32)
{
getline(myfile,store[i]);
i++;
}
myfile.close();
}
Why don't you use a std::vector<std::string>, and push_back() to populate it?
std::vector<std::string> store;
// ...
while(i < 32) {
std::string line;
if (getline(myfile,line)) {
store.push_back(line);
i++;
}
// ...
}
What about:
string store[32];
ifstream myfile;
int i;
myfile.open("filename.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
for (i = 0; i < 32; i++)
{
if (!getline(myfile, store[i]))
{
cout << "Error while reading file!" << endl; // always outputs when running the code.
return 0;
}
}
myfile.close();
}
Tested it and it was working for me.
This way the for loop automatically increment you variable and if for some strange reason the program reaches the end of the file, it will display your error message.
I got some help from one of the guys at university and we figured what the problem was !!
It was to do with the endline characters. I'm working on linux which uses \n as the endline character but the file I'm trying to read was built on Windows which of course has \r\n as the endline character! Eclipse seems to be accepting both versions of end of line but not bash!
I edited my code to get rid of those characters altogether before storing them in the vector and it now works fine.
Sorry for the trouble caused in here and hope this will at least remind beginners that there is a difference between files built on windows, mac and linux !! and that attention needs to be made when working with different files !!
void Manchester::copyFromFileToStore()
{
ifstream myfile;
myfile.open("BabyTest1-MC.txt");
if (!myfile.is_open())
{
cout << "Cannot read file!" << endl;
}
else
{
int i =0;
string line;
while(getline(myfile,line))
{
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
store.push_back(line);
i++;
}
myfile.close();
}
}

Storing a variable in C++

The problem is that file won't be read...Apparently there's a problem with an array but I don't really know how fix this issue...I'm a beginner to C++ 'arrays' and 'strings'...
My file should read the code, then translate the file, then output the text into a new file..
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <fstream>
#include <math.h>
#include <stdio.h>
#include <string>
#include <string.h>
using namespace std;
int main()
{
// Declarations
string reply;
string inputFileName;
ifstream inputFile;
ofstream outFile;
char character;
cout << "Input file name: ";
getline(cin, inputFileName);
// Open the input file.
inputFile.open(inputFileName.c_str());
// Check the file opened successfully.
if ( ! inputFile.is_open()) {
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
return 1;
}
// This section reads and echo's the file one character (byte) at a time.
while (inputFile.peek() != EOF) {
inputFile.get(character);
//cout << character;
//Don't display the file...
char cipher[sizeof(character)];
//Caesar Cipher code...
int shift;
do {
cout << "enter a value between 1-26 to encrypt the text: ";
cin >> shift;
}
while ((shift <1) || (shift >26));
int size = strlen(character);
int i=0;
for(i=0; i<size; i++)
{
cipher[i] = character[i];
if (islower(cipher[i])) {
cipher[i] = (cipher[i]-'a'+shift)%26+'a';
}
else if (isupper(cipher[i])) {
cipher[i] = (cipher[i]-'A'+shift)%26+'A';
}
}
cipher[size] = '\0';
cout << cipher << endl;
}
cout << "\nEnd of file reached\n" << endl;
// Close the input file stream
inputFile.close();
cout << "Press enter to continue...";
getline(cin, reply);
return 0;
}
To make it short: You're on c++ so just don't use the whole C stuff.
Don't use character arrays, use std::string
Don't use islower(char) but use std::islower(char,locale)
Don't use C-style arrays but std::array (compile time constant size) or std::vector (dynamic size)
You'll want to have it more like this:
#include <string>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <locale>
int main (void)
{
std::string input_filename;
std::cout << "Input file name: ";
std::getline(std::cin, input_filename);
unsigned int shift;
do
{
std::cout << "Enter a value between 1-26 to encrypt the text: ";
std::cin >> shift;
}
while ((shift == 0) || (shift > 26));
try
{
std::string filestring;
std::ifstream input(input_filename, std::ios_base::in);
if (input)
{
input.seekg(0, std::ios::end);
filestring.reserve(input.tellg());
input.seekg(0, std::ios::beg);
filestring.assign
(std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>());
}
else
{
std::string error_string("Reading failed for: \"");
error_string.append(input_filename);
error_string.append("\"");
throw std::runtime_error(error_string);
}
std::string result;
result.reserve(filestring.size());
std::locale const loc;
for (auto character : filestring)
{
char const shifter(std::islower(character, loc) ? 'a' : 'A');
result.push_back((character-shifter+shift)%26+shifter);
}
std::cout << result << std::endl;
}
catch (std::exception & e)
{
std::cout << "Execution failed with an exception: " << std::endl;
std::cout << e.what() << std::endl;
}
}
This solution requires C++11 support. If you do not have C++11 you can replace the loop with:
size_t const N(filestring.length());
for (size_t i(0u); i<N; ++i)
{
char const shifter(std::islower(filestring[i], loc) ? 'a' : 'A');
result.push_back((filestring[i]-shifter+shift)%26+shifter);
}
From looking at your code, "character" is declared as a char which means it can only store one byte of information. Yet later on you start using it as if it was an array of characters.
You are also declare "cipher" as a char array that you manual manage like a string which is error prone. The real issue however is that you're mixing C-like code in C++. In other words, the way your code is written isn't considered idiomatic C++.
Pixelchemist already went over the important points so I'll just present a minimal refactored working example of your above code:
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
using namespace std;
int main()
{
string filename;
cout << "enter input file: ";
cin >> filename;
ifstream inputFile( filename.c_str() );
string plaintext;
do
{
plaintext += inputFile.get();
}while(inputFile);
cout << plaintext << endl;
string &ciphertext = plaintext;
//Caesar Cipher code...
int shift = rand() % 26 + 1;
for(size_t i = 0; i < ciphertext.size(); ++i)
{
if (islower(ciphertext[i])) {
ciphertext[i] = (ciphertext[i] - 'a' + shift) % 26 + 'a';
}
else if (isupper(ciphertext[i])) {
ciphertext[i] = (ciphertext[i] - 'A' + shift) % 26 + 'A';
}
}
cout << ciphertext << endl;
}
You'll notice in the refactor that I've done away with char and char[] arrays altogether and replaced it with std::string. I'm also performing the cipher operation inplace on the plaintext input. This is done by making a reference alias to plaintext called ciphertext for readability. Also in my example, the shift is done randomly for prototyping but you should change it to take it as a user input instead.
You are working with a single char, thats e.g. just one letter or a number. So the whole thing with size handling is useless, because the size is always 1. You probably should use const char*. But then you can't use filestream.get() at all, because it only returns a single char (not and cstring aka const char*).
And you can use fstream.get() as condition for the loop, so you don't need to ask for the eof flag.
char my_char;
std::ifstream infstream("filename.txt");
if(!infstream.isopen())
return -1;
while(infstream.get(my_char) {
//do some stuff
}
or
std::string my_string;
std::ifstream infstream("filename.txt");
if(!infstream.isopen())
return -1;
while(infstream >> my_string) {
//do some stuff
}
for dynamic arrays in C++ use std::vector or std::list or ... one of the other STL containers, so you don't have to waste your time on memory management and using static sized arrays.
And std::string is the way to go for strings in C++. It is something similar to the STL containers, but just for char's.

C++ program to read a txt file and sort data

I'm a physics PhD student with some experience coding in java, but I'm trying to learn C++.
The problem I'm trying to solve is to read in data from a .txt file and then output all the numbers > 1000 in one file and all those <1000 in another.
What I need help with is writing the part of the code which actually reads in the data and saves it to an array. The data itself is only separated by a space, not all on a new line, which is confusing me a bit as I don't know how to get c++ to recognise each new word as an int. I have canabalised some code I have got from various sources online-
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include<cmath>
using namespace std;
int hmlines(ifstream &a) {
int i=0;
string line;
while (getline(a,line)) {
cout << line << endl;
i++;
}
return i;
}
int hmwords(ifstream &a) {
int i=0;
char c;
a >> noskipws >> c;
while ((c=a.get()) && (c!=EOF)){
if (c==' ') {
i++;
}
}
return i;
}
int main()
{
int l=0;
int w=0;
string filename;
ifstream matos;
start:
cout << "Input filename- ";
cin >> filename;
matos.open(filename.c_str());
if (matos.fail()) {
goto start;
}
matos.seekg(0, ios::beg);
w = hmwords(matos);
cout << w;
/*c = hmchars(matos);*/
int RawData[w];
int n;
// Loop through the input file
while ( !matos.eof() )
{
matos>> n;
for(int i = 0; i <= w; i++)
{
RawData[n];
cout<< RawData[n];
}
}
//2nd Copied code ends here
int On = 0;
for(int j =0; j< w; j++) {
if(RawData[j] > 1000) {
On = On +1;
}
}
int OnArray [On];
int OffArray [w-On];
for(int j =0; j< w; j++) {
if(RawData[j]> 1000) {
OnArray[j] = RawData[j];
}
else {
OffArray[j] = RawData[j];
}
}
cout << "The # of lines are :" << l
<< ". The # of words are : " << w
<< "Number of T on elements is" << On;
matos.close();
}
But if it would be easier, i'm open to starting the whole thing again, as I don't understand exactly what all the copied code is doing. So to summarise, what I need is it to-
Ask for a filepath in the console
Open the file, and store each number (separated by a space) as an element in a 1D array
I can manage the actual operations myself I think, if I could just get it to read the file the way I need.
Thanks very much
Using C++11 and the Standard Library makes your task fairly simple. This uses Standard Library containers, algorithms, and one simple lambda function.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
int main()
{
std::string filename;
std::cout << "Input filename- ";
std::cin >> filename;
std::ifstream infile(filename);
if (!infile)
{
std::cerr << "can't open " << filename << '\n';
return 1;
}
std::istream_iterator<int> input(infile), eof; // stream iterators
std::vector<int> onvec, offvec; // standard containers
std::partition_copy(
input, eof, // source (begin, end]
back_inserter(onvec), // first destination
back_inserter(offvec), // second destination
[](int n){ return n > 1000; } // true == dest1, false == dest2
);
// the data is now in the two containers
return 0;
}
Just switch the type of variable fed to your fistream, created from new std:ifstream("path to file") into a int and c++ will do the work for you
#include <fstream> //input/output filestream
#include <iostream>//input/output (for console)
void LoadFile(const char* file)
{
int less[100]; //stores integers less than 1000(max 100)
int more[100]; //stores integers more than 1000(max 100)
int numless = 0;//initialization not automatic in c++
int nummore = 0; //these store number of more/less numbers
std::ifstream File(file); //loads file
while(!file.eof()) //while not reached end of file
{
int number; //first we load the number
File >> number; //load the number
if( number > 1000 )
{
more[nummore] = number;
nummore++;//increase counter
}
else
{
less[numless] = number;
numless++;//increase counter
}
}
std::cout << "number of numbers less:" << numless << std::endl; //inform user about
std::cout << "number of numbers more:" << nummore << std::endl; //how much found...
}
This should give you an idea how should it look like(you shoudnt use static-sized arrays tough) If you got any probs, comment back
Also, please try to make nice readable code, and use tabs/ 4 spaces.
even though its pure C, this might give you some hints.
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#define MAX_LINE_CHARS 1024
void read_numbers_from_file(const char* file_path)
{
//holder for the characters in the line
char contents[MAX_LINE_CHARS];
int size_contents = 0;
FILE *fp = fopen(file_path, "r");
char c;
//reads the file
while(!feof(fp))
{
c = fgetc(fp);
contents[size_contents] = c;
size_contents++;
}
char *token;
token = strtok(contents, " ");
//cycles through every number
while(token != NULL)
{
int number_to_add = atoi(token);
//handle your number!
printf("%d \n", number_to_add);
token = strtok(NULL, " ");
}
fclose(fp);
}
int main()
{
read_numbers_from_file("path_to_file");
return 0;
}
reads a file with numbers separated by white space and prints them.
Hope it helps.
Cheers