Counting characters in txt file giving wrong count - c++

I am learning C++ and right now I have made a file that does some encrypting/decrypting. After I am done with everything, I want to find out how much a file was compressed/decompressed. So I decided to count the characters in the input and output file, but here's where it starts going wrong.
int get_compression(string file1, string file2){
string line = "";
ifstream stream1(file1.c_str());
double counter1 = 0.0;
while(getline(stream1, line)){
counter1 += line.length();
}
stream1.close();
cout << counter1 << "\n";
ifstream stream2(file2.c_str());
double counter2 = 0.0;
while(getline(stream2, line)){
counter2 += line.length();
}
stream2.close();
cout << counter2 << "\n";
return (counter2/counter1)*100;
}
I have added the two cout statements to see what it has counted, but it is telling me it has counted 496 characters in the input txt file that really has 528 characters, and 481 characters in the txt file that has 785 characters. Did I make some rookie mistake somewhere?

I believe you are not counting the new line characters. On Windows it may occur 2 characters per line error. So I suggest that you have a look at how many lines does each file has and added to what your code has counted.

The other answers and comments are perfectly accurate, but you might want to try using Boost Filesystem because it makes things like this so much easier.
This is an example taken from the boost documentation at http://www.boost.org/doc/libs/1_49_0/libs/filesystem/v3/doc/tutorial.html#Reporting-size
#include <iostream>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cout << "Usage: tut1 path\n";
return 1;
}
std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
return 0;
}

Related

My C++ Loop is not working properly, and I can't figure out why

I'm trying to write a program that copies (from an input.txt file) 30 lines to one file, then loops and copies the next 30 lines to a second file, then the next 30 to a 3rd file, etc. etc.
This is what I wrote to try and make that happen:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// initialize
ifstream input("input.txt");
string line;
int i = 0;
int fileNum = 0;
cout << "Initialized";
// Loop through text file and write to new files
while (getline(input, line) && i < 30)
{
// Write to File
ofstream outFile("frames/frame" + to_string(fileNum) + ".mcfunction");
// Write Lines
outFile << "data modify block " << (i + 1) << " -48 20 HeldItem.Item.tag.display.Name set value '{\"text\":\"" << line << "\"}'" << endl;
// Increment Counters
i++;
if (i == 30)
{
// Add Schedule and Scoreboard Commands to Bottom of Each File
outFile << "scoreboard players set Frame: BadApple " + to_string(fileNum) << endl;
outFile << "schedule frame" + to_string(fileNum + 1) + ".mcfunction 5s" << endl;
// Reset Counter & File Number
i = 0;
fileNum++;
cout << i << " ";
}
}
return 0;
}
But it only ends up copying one line from the input file to each document. Everything seems to be working aside from that.
Any help would be much appreciated, I've been trying to debug this for a while now but as a naive beginner, I haven't gotten very far. Thank you all in advance.
The problem is that you are opening and closing the output file once per line, instead of once every 30 lines.
I suggest that you restructure your program to use a nested loop. The outer loop should handle one output file (i.e. 30 lines) per loop iteration, and the inner loop should handle a single line per loop iteration.
Here is an example:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream input( "input.txt" );
std::string line;
int fileNum = 0;
bool finished = false;
std::cout << "Initialized\n";
//process one file per loop iteration
for ( int fileNum = 0; !finished; fileNum++ )
{
//open new output file
std::ofstream outFile("frames/frame" + std::to_string(fileNum) + ".mcfunction");
//process one line per loop iteration
for ( int i = 0; i < 30; i++ )
{
if ( !std::getline(input, line) )
{
finished = true;
break;
}
//write lines
outFile << "data modify block " << (i + 1) << " -48 20 HeldItem.Item.tag.display.Name set value '{\"text\":\"" << line << "\"}'\n";
}
//add schedule and scoreboard commands to bottom of each file
outFile << "scoreboard players set Frame: BadApple " + std::to_string(fileNum) << '\n';
outFile << "schedule frame" + std::to_string(fileNum + 1) + ".mcfunction 5s\n";
}
return 0;
}
Note that in my code above, I have removed using namespace std;, for the reason described here:
Why is "using namespace std;" considered bad practice?
Also, you should generally only use std::endl if you want to actually flush the buffer. Otherwise, you can simply print "\n", which is better for performance. See the following question for further information:
"std::endl" vs "\n"
I have therefore removed std::endl from the program.
You keep reopening the file on every iteration of the loop. So then it keeps overwriting the first line.

Looping over file, only get one line

Say we have a text file with this contents:
dogs
cats
bears
trees
fish
rocks
sharks
these are just words separated by newline chars. I am trying to create a Node.js addon. The Addon will read through a file and replacing matching lines with a blank line. Say I pass my program a regex that matches /trees/. If I pass the file to my C++ program it will read + write to the file, and result in:
dogs
cats
bears
fish
rocks
sharks
Right now, the problem is it's not looping through all the lines in the file. I get the feeling that's opening the file in append mode and therefore just starting at the end of the file? I can't tell. Anyway, I want to edit the file in place, not truncate and re-write or replace the whole file, because this will interrupt processes which are tailing the file.
Here's the code:
#include <nan.h>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
void Method(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(Nan::New("world").ToLocalChecked());
}
void Init(v8::Local<v8::Object> exports) {
fstream infile("/home/oleg/dogs.txt");
if(infile.fail()){
cerr << " infile fail" << endl;
exit(1);
}
int pos = 0;
string line;
int count = 0;
while (getline(infile, line)){
// we only seem to loop once, even though the file has 7 or 8 items
count++;
long position = infile.tellp();
cout << "tellp position is " << position << endl;
string str(line);
int len = str.length();
cout << " => line contains => " << line << endl;
cout << " line length is " << len << endl;
std::string s(len, ' '); // create blank string of certain length
infile << s; // write the string to the current position
pos = pos + len;
cout << "pos is " << pos << endl;
}
cout << " => count => " << count << endl;
infile.close();
exports->Set(Nan::New("hello").ToLocalChecked(),
Nan::New<v8::FunctionTemplate>(Method)->GetFunction());
}
NODE_MODULE(hello, Init)
to compile the code you might need to use Node.js tooling, which is
node-gyp rebuild
If you want to help and want to try to compile the code, then let me know, because you may need more info. But I am a new C++ newb and I think someone can help me figure it out without compiling/running the code. Thanks.
To answer your question on why you only read one line of the input file:
Your first write to the file likely sets the eofbit on the stream, so the second getline() attempt will think it has no more to read.
The comment from #RSahu describes the simplest way to do this for text files.

Counting same string/word in a text file in C++

I'm trying to count same string/words from a text file in C++.
This is my text file
one two three two
test testing 123
1 2 3
This is my main program
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, const char** argv)
{
int counter = 0;
int ncounter = 0;
string str;
ifstream input(argv[1]);
while (getline(input, str))
{
if(str.find("two") != string::npos){counter++;}
if(str.find('\n') != string::npos){ncounter++;}
cout << str << endl; //To show the content of the file
}
cout << endl;
cout << "String Counter: " << counter << endl;
cout << "'\\n' Counter: " << ncounter << endl;
return 0;
}
I'm using the .find() function to find the string.
When I insert an non-existant word, it doesn't count.
When I insert the word "two", it counts, but only once.
How come it didn't count 2 times?
And for the carriage return (or return line; \n), it can't count any. Why is that?
Because the two twos are on the same line and you are searching the line only for one substring.
You can't find the '\n' because the getline function reads the line up to and without the '\n'.
Why not use a std::multiset to store the words? It would do the counting for you, and reading the file into it can be done in one line:
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <iterator>
int main(int argc, const char** argv)
{
// Open the file
std::ifstream input(argv[1]);
// Read all the words into a set
std::multiset<std::string> wordsList =
std::multiset<std::string>( std::istream_iterator<std::string>(input),
std::istream_iterator<std::string>());
// Iterate over every word
for(auto word = wordsList.begin(); word != wordsList.end(); word=wordsList.upper_bound(*word))
std::cout << *word << ": " << wordsList.count(*word) << std::endl;
// Done
system("pause");
return 0;
}
Note the last for part - word=wordsList.upper_bound(*word). Technically you can switch it to simply word++ (then actually it would be better to shorten it to simply for(auto word: wordList). It ensures each value from the set will only be output once.
It will also list the words themselves without you needing to do it like now inside your current while loop.
Your best bet is going to be to read each line, then tokenize along the white space so you can examine each word individually.
I suspect we're talking about a homework assignment here, so my best answer is to direct you to the c++ reference for std::strtok: http://en.cppreference.com/w/cpp/string/byte/strtok

Why does my countlines function always return 0?

So I am making a program for a simple calendar app which reads in inputs from a file input.csv (its a text file with two columns which are seperated using commas and new lines for each command).
The first thing i want to do is count the number of lines from the input file, which is passed as the third argument in the command line, so I can make an array to hold each line separately but the function countLines always returns 0!
Project code:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
//Prototypes
int countLines (ifstream& countfiles);
int countLines(ifstream& countfile)
//counts number of lines in file passed to function
{
string line;
int numberOfLines;
numberOfLines = 0;
//reads through each line until end of file
while(getline(countfile, line))
{
numberOfLines++;
}
return numberOfLines;
}
int main (int argc, char* argv[])
{
if(argc != 3) cout << "Usage: calendar.out datafile inputfile";
//Create input streams to both files
ifstream apptsfp;
ifstream inputfp;
//Open streams to both files
apptsfp.open(argv[2]);
inputfp.open(argv[3]);
int numberOfInputs=0;
numberOfInputs = countLines(inputfp)-1;
cout << "number of input commands: " << numberOfInputs << endl;
return 0;
}
Almost certainly because you are failing to open your input file.
inputfp.open(argv[3]);
if (!inputfp.is_open())
{
cerr << "failed to open input file " << argv[3] << '\n';
return 1;
}
Files can fail to open for all sorts of reasons, you should always check for this.
BTW don't use an array to hold the input lines, use std::vector<std::string>. Then you can use push_back to add the lines to the vector. This will be easier and more efficient because you won't have to read the file twice. What more could you ask for!
std::vector<std::string> lines;
std::string line;
while (getline(inputfp, line))
lines.push_back(line);
It seems you only want two arguments, not three as you say in the question (the "first" argument is the program name). This means that the input file is in argc[2] instead, and argv[3] is a NULL pointer.
This means that your open call will fail, but you do not check for that.
Your access to argv[3] is incorrect. The second file name (third arg, including the program name in arg[0]) is in slot 2 (the array is zero-based).
Try:
apptsfp.open(argv[1]);
inputfp.open(argv[2])
You are trying to access argv[3] which is null. Try this :-
int main (int argc, char* argv[])
{
if(argc != 3)
cout << "Usage: calendar.out datafile inputfile";
//Create input streams to both files
ifstream apptsfp;
ifstream inputfp;
//Open streams to both files
apptsfp.open(argv[1]);
inputfp.open(argv[2]);
int numberOfInputs=0;
numberOfInputs = countLines(inputfp)-1;
cout << "number of input commands: " << numberOfInputs << endl;
return 0;
}

HW Help: get char instead of get line C++

I wrote the code below that successfully gets a random line from a file; however, I need to be able to modify one of the lines, so I need to be able to get the line character by character.
How can I change my code to do this?
Use std::istream::get instead of std::getline. Just read your string character by character until you reach \n, EOF or other errors. I also recommend you read the full std::istream reference.
Good luck with your homework!
UPDATE:
OK, I don't think an example will hurt. Here is how I'd do it if I were you:
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
static std::string
answer (const string & question)
{
std::string answer;
const string filename = "answerfile.txt";
ifstream file (filename.c_str ());
if (!file)
{
cerr << "Can't open '" << filename << "' file.\n";
exit (1);
}
for (int i = 0, r = rand () % 5; i <= r; ++i)
{
answer.clear ();
char c;
while (file.get (c).good () && c != '\n')
{
if (c == 'i') c = 'I'; // Replace character? :)
answer.append (1, c);
}
}
return answer;
}
int
main ()
{
srand (time (NULL));
string question;
cout << "Please enter a question: " << flush;
cin >> question;
cout << answer (question) << endl;
}
... the only thing is that I have no idea why do you need to read string char by char in order to modify it. You can modify std::string object, which is even easier. Let's say you want to replace "I think" with "what if"? You might be better off reading more about
std::string and using find, erase, replace etc.
UPDATE 2:
What happens with your latest code is simply this - you open a file, then you get its content character by character until you reach newline (\n). So in either case you will end up reading the first line and then your do-while loop will terminate. If you look into my example, I did while loop that reads line until \n inside a for loop. So that is basically what you should do - repeat your do-while loop for as many times as many lines you want/can get from that file. For example, something like this will read you two lines:
for (int i = 1; i <= 2; ++i)
{
do
{
answerfile.get (answer);
cout << answer << " (from line " << i << ")\n";
}
while (answer != '\n');
}