c++ text decoder decoding more than asked for - c++

Im working on a text file decoder along with an encoder, they work off of two different text files. The decoder prints the decoded message underneath the encoded message but it also prints a bunch of other stuff as well. How do i fix this
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ifstream fin; // input file
string line;
ofstream fout;
//open output file
fout.open("secret.txt", ios::app);
if (!fout.good()) throw "I/O error";
// open input file
fin.open("secret.txt");
if (!fin.good()) throw "I/O error";
// read input file, decode, display to console
while (fin.good()) {
getline(fin, line);
for (int i = 0; i < line.length(); i++) // for each char in the string...
line[i]--; // bump the ASCII code down by 1
fout << line << endl; // display on screen
}
// close file
fin.close();
return 0;
}
the text file from the encoder reads
Uftujoh234
Ifmmp!nz!obnf!jt!cpc
Dmptfe!
Uftujoh
which decodes to
Testing123
Hello my name is bob
Closed
Testing
this is all the extra stuff it also prints in the text file
Sdrshmf012
Gdkknlxm`ldhrana
Bknrdc
Sdrshmf
Rcqrgle/01
Fcjjmkwl_kcgq`m`
Ajmqcb
Rcqrgle
Qbpqfkd./0
Ebiiljvk^jbfp_l_
#ilpba
Qbpqfkd
Paopejc-./
Dahhkiuj]iaeo^k^
?hkoa`
Paopejc
O`nodib,-.
C`ggjhti\h`dn]j]
>gjn`_
O`nodib
N_mncha+,-
B_ffigsh[g_cm\i\
=fim_^
N_mncha
M^lmbg`*+,
A^eeh

The extra data you see is actually valid output from decoding the data in "secret.txt".
I'm not sure if this is what you want, but are you aware that you are reading and writing to the same file each time you run your application?
You'll append more and more "decoded" data to the file, and therefore you get the extra output you are referring to.
Also, there is an issue with your while-loop.
fin.good () will remain true until some of the error bits has been set inside of fin, though it will enter the loop one time too much since you should check to state of the stream immediately after your call to getline (fin, ...).
Currently the reading will fail but you will still process the "unread" data.
std::getline will return the stream object, and since a std::istream (as well as std::ostream) implicitly can be converted to a boolean to check it's current state you should use that as your loop-condition.
Change your loop into something as the below and see if that solves your problem.
while (getline (fin, line))
{
for (int i = 0; i < line.length(); i++) // for each char in the string...
line[i]--; // bump the ASCII code down by 1
fout << line << endl; // display on screen
}

The extra stuff isn't extra. You are writing data into the same file you are reading, so what you do is:
write line
read line
You are renencoding the data you already encoded.

Related

Set integer variable through file read

I know how to pass in strings from a text file. In a previous project I read in strings and then tested them on either being "t" or "f", which the result of would set a variable to true or false.
Now I am wondering if it is efficiently possible to read numbers from a text file and pass them into an int? All I can think of is checking for the string "1" and returning 1 in a function, but that would have to be done for every possible integer I could expect in my program, which is not an effective solution.
For context, I am trying to make a save system for a game, and ints/floats that are read in would be variables such as player health, how much of an item they have, etc.
If you already know how to read a string str from a text file, reading numbers is not that difficult: jsut read the string as you did and use stoi() to convert the string into an int, or stof() into float.
int i; double d;
i=stroi(str); d=strod(str2);
Another technique is to use file streams to read or write from a file exactly as you would do from cin and cout:
ifstream file("mytext.txt");
file>>i>>d;
The previous method doesn't care so much about lines. So still another technique is to read a string, convert it into a string stream and use the stringstream as you would with cin:
if (getline(file, str)){ // read a full line
stringstream sst(str);
sst>>i>>d;
}
Using std::fstream. You can open a file, and stream input or output based on how you opened the file.
Example:
#include <iostream>
#include <fstream>
int main(int argc, char** argv)
{
// Pretend we are passed the file location as a command-line argument to our program:
std::fstream file { argv[1], std::ios::in };
if (file.is_open())
{
int value;
file >> value;
std::cout << value << std::endl;
}
else
{
std::cout << "Could not open file " << argv[1] << std::endl;
}
}
Provided that the information is correctly formatted in the file, this should work.
I didn't run it, so there might be syntax errors, but the basics are there. Check out cppreference for some help, they will have further examples.

Recover ifstream from failed read

I currently have a piece of code that reads in text from a file using an ifstream. Each line of this file corresponds to a different piece of data that must be encoded into a struct. My "encodeLine" function takes care of this.
For safety, I want my system to be able to handle data that is too big to fit into its variable. For example, if the number 999999999 is read into a short, I want the program to be able to continue on reading the rest of the lines.
Currently, when I encounter data like this, I print out "ERROR" and clear the stream. However, when I perform more reads, the data that is read is corrupted. For example, on the next line the number "1" should be read, but instead something like 27021 is read.
How can the ifstream be reset to continue with valid reads?
Here is my code:
ifstream inputStream;
inputStream.open(foo.txt);
char token[64];
int totalSize = 0;
// Priming read
inputStream >> token;
while(inputStream.good())
{
// Read and encode line of data from file
totalSize = totalSize + encodeLine(inputStream, &recordPtr, header, filetypeChar)
if(!inputStream.eof() && !inputStream.good())
{
printf("ERROR");
inputStream.clear();
}
else if(inputStream.eof())
{
break;
}
inputStream >> token;
}

read and write a binary file in c++ with fstream

I'm trying to write simple c++ code to read and write a file.
The problem is my output file is smaller than the original file, and I'm stuck finding the cause.
I have a image with 6.6 kb and my output image is about 6.4 kb
#include <iostream>
#include <fstream>
using namespace std;
ofstream myOutpue;
ifstream mySource;
int main()
{
mySource.open("im1.jpg", ios_base::binary);
myOutpue.open("im2.jpg", ios_base::out);
char buffer;
if (mySource.is_open())
{
while (!mySource.eof())
{
mySource >> buffer;
myOutpue << buffer;
}
}
mySource.close();
myOutpue.close();
return 1;
}
Why not just:
#include <fstream>
int main()
{
std::ifstream mySource("im1.jpg", std::ios::binary);
std::ofstream myOutpue("im2.jpg", std::ios::binary);
myOutpue << mySource.rdbuf();
}
Or, less chattily:
int main()
{
std::ofstream("im2.jpg", std::ios::binary)
<< std::ifstream("im1.jpg", std::ios::binary).rdbuf();
}
Two things: You forget to open the output in binary mode, and you can't use the input/output operator >> and << for binary data, except if you use the output operator to write the input-streams basic_streambuf (which you can get using rdbuf).
For input use read and for output use write.
There are 3 problems in your code:
1- You have not opened your output file in Binary.
2- Your code return "1", normally you should return "0", if something went wrong then return an error code.
3- You should use "manipulators" and make c++ not to avoid whitespaces, so in order to read from file instead of:
mySource >> buffer;
you should use:
mySource >> std:noskipws >> buffer;
Well, its just because of padding at the end of the image. eof of any file do not include the padded bytes added at the end of file.
Try this
take img1.jpg contains 20 space charecter at the end not visible here (uegfuyregwfyugwrerycgerfcg6ygerbucykgeugcrgfrgeyf ) and run your program (do not include parenthesis in the file, these are used to show the data content)
you will see img2.jpg contains (uegfuyregwfyugwrerycgerfcg6ygerbucykgeugcrgfrgeyf)
So, its better option to read the file byte by byte using the filesize which you can get using stat, and run for loop till filesize. Hope this should resolve your problem you mentioned above

Decoding / Encloding Text File using Stack Library - Can't Encode Large Files C++

I am working on a program that can encode and then decode text in C++. I am using the stack library. The way the program works is that it first asks you for a cypher key, which you put in manually. It then asks for the file name, which is a text file. If it is a normal txt file, it encodes the message to a new file and adds a .iia files extension. If the text file already has a .iia file extension, then it decodes the message, as long as the cypher key is the same as the one used to encode it.
My program does encode and decode, but how many characters it decodes is determined by temp.size() % cypher.length() that is in the while loop in the readFileEncode() function. I think this is what is keeping the entire file from being encoded and then decoded correctly. Another words, the ending file after it has been decoded from say "example.txt.iia" back to "example.txt" is missing a large portion of the text from the original "example.txt" file. I tried just cypher.length() but of course that does not encode or decode anything then. The entire process is determined by that argument for the decoding and encoding.
I cannot seem to find out the exact logic for this to encode and decode all the characters in any size file. Here is the following code for the function that does the decoding and encoding:
EDIT: Using WhozCraig's code that he edited for me:
void readFileEncode(string fileName, stack<char> &text, string cypher)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
stack<char> temp;
char ch;
while (file.get(ch))
temp.push(ch ^ cypher[temp.size() % cypher.length()]);
while (!temp.empty())
{
text.push(temp.top());
temp.pop();
}
}
EDIT: A stack is required. I am going to implement my own stack class, but I am trying to get this to work first with the stack library. Also, if there is a better way of implementing this, please let me know. Otherwise, I believe that there is not much wrong with this except to get it to go through the loop to encode and decode the entire file. I am just unsure as to why it stops at, say 20 characters sometimes, or ten characters. I know it has to do with how long the cypher is too, so I believe it is in the % (mod). Just not sure how to rewrite.
EDIT: Ok, tried WhozCraig's solution and I don't get the desired output, so the error now must be in my main. Here is my code for the main:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cctype>
#include <stack>
using namespace std;
void readFileEncode(string fileName, stack<char> &text, string cypher);
int main()
{
stack<char> text; // allows me to use stack from standard library
string cypher;
string inputFileName;
string outputFileName;
int position;
cout << "Enter a cypher code" << endl;
cin >> cypher;
cout << "Enter the name of the input file" << endl;
cin >> inputFileName;
position = inputFileName.find(".iia");//checks to see if the input file has the iia extension
if (position > 1){
outputFileName = inputFileName;
outputFileName.erase(position, position + 3);// if input file has the .iia extension it is erased
}
else
//outputFileName.erase(position, position + 3);// remove the .txt extension and
outputFileName = inputFileName + ".iia";// add the .iia extension to file if it does not have it
cout << "Here is the new name of the inputfile " << outputFileName << endl; // shows you that it did actually put the .iia on or erase it depending on the situation
system("pause");
readFileEncode(inputFileName, text, cypher); //calls function
std::ofstream file(outputFileName); // calling function
while (text.size()){// goes through text file
file << text.top();
text.pop(); //clears pop
}
system("pause");
}
Basically, I am reading .txt file to encrypt and then put a .iia file extension on the filename. Then I go back through, enter the file back with the .iia extension to decode it back. When I decode it back it is gibberish after about the first ten words.
#WhozCraig Does it matter what white space, newlines, or punctuation is in the file? Maybe with the full solution here you can direct me at what is wrong.
just for information: never read file char by char it will take you hours to finish 100Mb.
read at least 512 byte(in my case i read directly 1 or 2Mb ==> store in char * and then process).
If I understand what you're trying to do correctly, you want the entire file rotationally XOR'd with the chars in the cipher key. If that is the case, you can probably address your immediate error by simply doing this:
void readFileEncode(string fileName, stack<char> &text, string cypher)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
stack<char> temp;
char ch;
while (file.get(ch))
temp.push(ch ^ cypher[temp.size() % cypher.length()]);
while (!temp.empty())
{
text.push(temp.top());
temp.pop();
}
}
The most notable changes are
Opening the file in binary-mode using std::ios::in|std::ios::binary for the open-mode. this will eliminate the need to invoke the noskipws manipulator (which is usually a function call) for every character extracted.
Using file.get(ch) to extract the next character. The member will pull the next char form the file buffer directly if one is available, otherwise load the next buffer and try again.
Alternative
A character by character approach is going to be expensive any way you slice it. That this is going through a stack<>, which will be backed by a vector or deque isn't going to do you any favors. That it is going through two of them just compounds the agony. You may as well load the whole file in one shot, compute all the XOR's directly, then push them on to you stack via a reverse iterator:
void readFileEncode
(
const std::string& fileName,
std::stack<char> &text,
const std::string& cypher
)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
// retrieve file size
file.seekg(0, std::ios::end);
std::istream::pos_type pos = file.tellg();
file.seekg(0, std::ios::beg);
// early exit on zero-length file.
if (pos == 0)
return;
// make space for a full read
std::vector<char> temp;
temp.resize(static_cast<size_t>(pos));
file.read(temp.data(), pos);
size_t c_len = cypher.length();
for (size_t i=0; i<pos; ++i)
temp[i] ^= cypher[i % c_len];
for (auto it=temp.rbegin(); it!=temp.rend(); ++it)
text.push(*it);
}
You still get your stack on the caller-side, but I think you'll be considerably happier with the performance.

How do you open a file in C++?

I want to open a file for reading, the C++ way. I need to be able to do it for:
text files, which would involve some sort of read line function.
binary files, which would provide a way to read raw data into a char* buffer.
You need to use an ifstream if you just want to read (use an ofstream to write, or an fstream for both).
To open a file in text mode, do the following:
ifstream in("filename.ext", ios_base::in); // the in flag is optional
To open a file in binary mode, you just need to add the "binary" flag.
ifstream in2("filename2.ext", ios_base::in | ios_base::binary );
Use the ifstream.read() function to read a block of characters (in binary or text mode). Use the getline() function (it's global) to read an entire line.
There are three ways to do this, depending on your needs. You could use the old-school C way and call fopen/fread/fclose, or you could use the C++ fstream facilities (ifstream/ofstream), or if you're using MFC, use the CFile class, which provides functions to accomplish actual file operations.
All of these are suitable for both text and binary, though none have a specific readline functionality. What you'd most likely do instead in that case is use the fstream classes (fstream.h) and use the stream operators (<< and >>) or the read function to read/write blocks of text:
int nsize = 10;
std::vector<char> somedata(nsize);
ifstream myfile;
myfile.open("<path to file>");
myfile.read(somedata.data(), nsize);
myfile.close();
Note that, if you're using Visual Studio 2005 or higher, traditional fstream may not be available (there's a new Microsoft implementation, which is slightly different, but accomplishes the same thing).
To open and read a text file line per line, you could use the following:
// define your file name
string file_name = "data.txt";
// attach an input stream to the wanted file
ifstream input_stream(file_name);
// check stream status
if (!input_stream) cerr << "Can't open input file!";
// file contents
vector<string> text;
// one line
string line;
// extract all the text from the input file
while (getline(input_stream, line)) {
// store each line in the vector
text.push_back(line);
}
To open and read a binary file you need to explicitly declare the reading format in your input stream to be binary, and read memory that has no explicit interpretation using stream member function read():
// define your file name
string file_name = "binary_data.bin";
// attach an input stream to the wanted file
ifstream input_stream(file_name, ios::binary);
// check stream status
if (!input_stream) cerr << "Can't open input file!";
// use function that explicitly specifies the amount of block memory read
int memory_size = 10;
// allocate 10 bytes of memory on heap
char* dynamic_buffer = new char[memory_size];
// read 10 bytes and store in dynamic_buffer
file_name.read(dynamic_buffer, memory_size);
When doing this you'll need to #include the header : <iostream>
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream file;
file.open ("codebind.txt");
file << "Please writr this text to a file.\n this text is written using C++\n";
file.close();
return 0;
}
#include <iostream>
#include <fstream>
using namespace std;
void main()
{
ifstream in_stream; // fstream command to initiate "in_stream" as a command.
char filename[31]; // variable for "filename".
cout << "Enter file name to open :: "; // asks user for input for "filename".
cin.getline(filename, 30); // this gets the line from input for "filename".
in_stream.open(filename); // this in_stream (fstream) the "filename" to open.
if (in_stream.fail())
{
cout << "Could not open file to read.""\n"; // if the open file fails.
return;
}
//.....the rest of the text goes beneath......
}
Follow the steps,
Include Header files or name space to access File class.
Make File class object Depending on your IDE platform ( i.e,
CFile,QFile,fstream).
Now you can easily find that class methods to open/read/close/getline or else of any file.
CFile/QFile/ifstream m_file;
m_file.Open(path,Other parameter/mood to open file);
For reading file you have to make buffer or string to save data and you can pass that variable in read() method.
**#include<fstream> //to use file
#include<string> //to use getline
using namespace std;
int main(){
ifstream file;
string str;
file.open("path the file" , ios::binary | ios::in);
while(true){
getline(file , str);
if(file.fail())
break;
cout<<str;
}
}**
#include <fstream>
ifstream infile;
infile.open(**file path**);
while(!infile.eof())
{
getline(infile,data);
}
infile.close();
fstream are great but I will go a little deeper and tell you about RAII.
The problem with a classic example is that you are forced to close the file by yourself, meaning that you will have to bend your architecture to this need. RAII makes use of the automatic destructor call in C++ to close the file for you.
Update: seems that std::fstream already implements RAII so the code below is useless. I'll keep it here for posterity and as an example of RAII.
class FileOpener
{
public:
FileOpener(std::fstream& file, const char* fileName): m_file(file)
{
m_file.open(fileName);
}
~FileOpeneer()
{
file.close();
}
private:
std::fstream& m_file;
};
You can now use this class in your code like this:
int nsize = 10;
char *somedata;
ifstream myfile;
FileOpener opener(myfile, "<path to file>");
myfile.read(somedata,nsize);
// myfile is closed automatically when opener destructor is called
Learning how RAII works can save you some headaches and some major memory management bugs.