just want to ask if anyone knows why I cant convert an entire picture into decimal.
Problem: after about 180 couts it turns 0 for the rest of the pixels.
Code:
#include <fstream>
#include <iostream>
int main() {
char unsigned charTemp = 0;
int unsigned intTemp = 0;
std::fstream file;
file.open("PIC.pbm", std::ios::in);
//Ignore header
for (int i = 0; i < 13; i++) {
file.ignore();
}
//read and print
//img res is 40x40 = 1600
for (int i = 0; i < 1600; i++) {
file >> charTemp;
intTemp = charTemp;
std::cout << intTemp << " ";
charTemp = 0;
intTemp = 0;
}
std::cout << "\n\n\n";
system("pause");
return 0;
}
Pic: any 40x40 pbm
A better method with picture and image files is to read them as binary files:
std::ifstream file("PIC.pbm", ios::binary);
std::vector<unsigned char> bitmap(1600);
// Skip over the header
file.seekg(13, ios::beg); // Skip over 13 bytes.
// Read in the data at once
file.read((char *) &bitmap[0], 1600);
// Now process the bitmap from memory
for (int i = 0; i < 1600; ++i)
{
cout << static_cast<unsigned int>(bitmap[i]) << " ";
if ((i % 40) == 39)
{
cout << "\n";
}
}
cout << "\n";
The idea here is to read in the bitmap in one transaction into memory. Streams like to flow (don't interrupt the flow). Memory is faster to access than files, so the bitmap values are processed from memory.
The cast is used so that the formatted insertion doesn't treat the byte as a character, but a number.
First, open your PIC.pbm file in another hex editor because it's quite possible that those bytes really are zeroes. If not, then you've got problems reading the file.
The fstream constructor does not default to reading in binary mode, so it reads files as "text" - and I've learned the hard way that you can't trust the standard-library with knowing anything about text anymore (what with mishandling Unicode, line-endings, etc - I feel it's best to always use binary and a dedicated Unicode library).
You should check the fstream::good() function after each read operation to see if it failed, and if so, then check iostate:
using namespace std;
// ...
fstream file;
file.open( "PIC.pbm", ios::in | ios::binary );
file.ignore( 13 );
for (int i = 0; i < 1600; i++) {
file >> charTemp;
if( !file.good() ) {
cout << endl;
cout << "Error reading file: iostate == " << file.iostate << endl;
break;
}
else {
intTemp = charTemp;
std::cout << intTemp << " ";
charTemp = 0;
intTemp = 0;
}
}
Related
I cannot find the problem in my code. readFile function works well, but writeFile function does not make any changes in the file:
#include <iostream>
#include <fstream>
using namespace std;
const int BUF_SIZE = 1024;
void readFile(fstream &file, char buffer[BUF_SIZE]);
void writeFile(fstream &file);
void readFile(fstream &file, char buffer[BUF_SIZE])
{
int position;
cout << "Please enter a position to read from the file some info" << endl;
cin >> position;
file.seekg(position, ios::beg);
file.read((char*) buffer, BUF_SIZE); // <<<<<
for(int i = 0; i < file.gcount(); i++){
cout << buffer[i];
}
}
void writeFile(fstream &file)
{
char temp[100] = "HHHH";
//cout << "Please enter some info to add to the file" << endl;
file.write((char*) &temp, 100);
for(int i = 0; i < file.gcount(); i++){
cout << temp[i];
}
}
int main(int argc, char const *argv[])
{
char buffer[BUF_SIZE];
if (argc != 2){
cout << "Program usage: prog_name file_name";
return 1;
}
fstream file(argv[1], ios::in | ios::out | ios::binary | ios::app);
if (!file){
cout << "File can not open or doesn't exist";
return 1;
}
//Try to read & write some info from/to file in particular position
readFile(file, buffer);
writeFile(file);
file.close();
return 0;
}
When I create a new ostream it works well, but I want to understand why fstream in/out mode works in my code only for reading.
I see several problems:
The reason behind the writing problem is probably because you reach the end of the file (is the file smaller than BUF_SIZE bytes?). This sets the EOF bit, which makes any write operations to fail. You have to clear that bit before (use the std::fstream::clear method):
void readFile(fstream &file, char buffer[BUF_SIZE])
{
int position;
cout << "Please enter a position to read from the file some info" << endl;
cin >> position;
file.seekg(position, ios::beg);
file.read(buffer, BUF_SIZE);
for(int i = 0; i < file.gcount(); i++){
cout << buffer[i];
}
file.clear(); // clears EOF
}
The line file.write((char*) &temp, 100); is wrong since you are actually passing a point to the temp variable, which is also a pointer, but it is camouflaged by the cast. These ones are OK: file.write(temp, 100); or file.write(&temp[0], 100);
When printing the written characters, you are using std::fstream::gcount, which literally means get count (amount of characters read in the last get operation). You are writing (put) not reading (get). Indeed, you are actually indicating how many bytes you are willing to write, so use it:
file.write(temp, 100);
for(int i = 0; i < 100; i++){
cout << temp[i];
}
Finally, you are always writing 100 characters, probably including some garbage from the buffer. As I see that you want to let the user choose what to write (the commented line), you can instead:
const size_t size = strlen(temp);
file.write(temp, size);
for(size_t i = 0; i < size; i++){
cout << temp[i];
}
In addition, some suggestions:
Use a std::string to read the user input, in this way you avoid a possible buffer overflow (if the user enters more than 100 characters).
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // read the link bel
string temp;
getline(cin, temp); // need #include <string>
file.write(temp.c_str(), temp.size());
You will probably want to read this answer to learn more about the first line (basically it avoids the getline to be skipped after using cin >> position).
Avoid the for loop to print the user input. For both the buffer and the std::string options you can just cout << temp << endl;.
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();
}
I'm using a simple encryption that I found online. Basically, I'm streaming in a file, checking to see if that file is open (if not, display an error message) and putting each line in each element of the array while encrypting the information. Afterwards I stream that encrypted information onto an output file.
However, I'm getting nothing in my output.txt file. The encryption works fine if you test it by itself.
Here is my code:
#include <string>
#include <fstream>
#include <sstream> // for ostringstream
#include <iostream>
#include <stdio.h>
#include <algorithm>
/* Credits to kylewbanks.com */
string encrypt (string content) {
char key[3] = {'K'}; //Any chars will work
string output = content;
for (int i = 0; i < content.size(); i++)
output[i] = content[i] ^ key[i % (sizeof(key) / sizeof(char))];
return output;
}
int main() {
string input, line;
string content[10000];
string encryptedContent[10000];
int counter = 0, innerChoice = 0, i, finalCounter;
cout << "\tPlease enter the file name to encrypt!\n";
cout << "\tType '0' to get back to the menu!\n";
cout << "Input >> ";
cin >> input;
/* Reads in the inputted file */
ifstream file(input.c_str());
//fopen, fscanf
if(file.is_open()) {
/* Counts number of lines in file */
while (getline(file, line)) {
counter++;
}
cout << counter;
finalCounter = counter;
for (i = 0; i < finalCounter; i++) {
file >> content[i];
encryptedContent[i] = encrypt(content[i]);
cout << encryptedContent[i];
}
} else {
cout << "\tUnable to open the file: " << input << "!\n";
}
/* Write encryption to file */
ofstream outputFile("output.txt");
for (i = 0; i < finalCounter ; i++) {
outputFile << encryptedContent;
}
outputFile.close();
}
Any clue what is wrong?
string content[10000];
string encryptedContent[10000];
This is wrong because it is creating 20000 strings (you probably think it is creating a large enough character array to read the data).
string content; is enough. It can be resized to handle any length of strings.
You just need to read/write the file in binary:
int main()
{
string input = "input.txt";
ifstream file(input, ios::binary);
if (!file.is_open())
{
cout << "\tUnable to open the file: " << input << "!\n";
return 0;
}
string plaintext;
//read the file
file.seekg(0, std::ios::end);
size_t size = (size_t)file.tellg();
file.seekg(0);
plaintext.resize(size, 0);
file.read(&plaintext[0], size);
cout << "reading:\n" << plaintext << "\n";
//encrypt the content
string encrypted = encrypt(plaintext);
//encrypt again so it goes back to original (for testing)
string decrypted = encrypt(encrypted);
cout << "testing:\n" << decrypted << "\n";
/* Write encryption to file */
ofstream outputFile("output.txt", ios::binary);
outputFile.write(encrypted.data(), encrypted.size());
return 0;
}
I am having some trouble playing around with files. Here is what I am trying to accomplish. I am attempting to filter a PPM image by take the inverse of the blue value (every third value). I can successfully open and write files, but I am experiencing some issues. In my while (myfile.good()) loop, I think only the final 3 numbers get assigned to the variables r, g, and b. What I am trying to do is have every first( out of three) value assigned to the variable r, every second value assigned to g, and every third value assigned to b. However, I want to take 255 - the current b value, and set that as the new b value to apply to filter. Do I have to make 3 separate files (1 for each variable), and then open them all to write them in a 4 file which would serve as the final copy? Or is there a way to copy them all and assign it to a variable? Any help is much appreciated. I am new to c++ so please forgive me. Thank you for your assistance.
Example of values I am attempting to use: http://imgur.com/H6EDFIq
#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
char filename[50];
ifstream myfile;
cin.getline(filename, 50);
myfile.open(filename);
if(!myfile.is_open())
{
cout << "File cannot load.";
}
char r [50];
char g [50];
char b [50];
myfile >> r >> g >> b;
while (myfile.good())
{
myfile >> r >> g >> b;
}
myfile.close();
ofstream myfile2;
myfile2.open(filename);
//this is just to test to see what gets written onto the file
//for (int a=0; a<20; a++)
//{
// ** Is this even allowed?? int r = 255 - r;
//myfile2 << r << " " << g << " " << b;
//}
myfile2.close();
return 0;
}
Unless you have a particular need to store the data in memory then it's simpler to just write the data to a new file as you read it.
Here's an example that reads a P3 ppm with 8-bit color entries, inverts the blue channel as you requested, then writes a new file with that data. It doesn't do a ton of error checking but I didn't want to make it any longer than it already is. You'll want to add your own filename prompting and such.
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream inFile("lena.ppm");
if(!inFile)
{
std::cerr << "Could not open input file.\n";
return -1;
}
std::string type;
std::string comment;
int width = 0, height = 0, colors = 0;
std::getline(inFile, type);
if(type != "P3")
{
std::cerr << "File is not a P3 format PPM.\n";
return -1;
}
if(inFile.peek() == '#')
{
std::getline(inFile, comment);
}
inFile >> width >> height >> colors;
std::ofstream outFile("lena2.ppm");
if(!outFile)
{
std::cerr << "Could not open output file.\n";
return -1;
}
outFile << type << "\n";
if(!comment.empty())
{
outFile << comment << "\n";
}
outFile << width << " " << height << "\n" << colors << "\n";
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < width; ++x)
{
int r = 0, g = 0, b = 0;
if(!(inFile >> r >> g >> b))
{
std::cerr << "File ended early.\n";
return -1;
}
b = (255 - b);
if(x != 0 && !(x % 5)) //Keep lines under 70 columns per spec.
{
outFile << "\n";
}
outFile << r << " " << g << " " << b << " ";
}
outFile << "\n";
}
return 0;
}
You'll want to check for a .ppm header which is the first line of the .ppm image. Check out .ppm magic numbers, either P3 or P6 and you'll need to check for that. Second line are the dimensions of the image, so you'll need to take that into consideration too.
This is something I worked on earlier so you can get an idea. It might not work immediately so just give it a read.
#include <iostream>
#include <fstream>
#include <sstream>
#include <exception>
int main() {
std::string filename = //whatever your file name is
std::ifstream input(filename.c_str(), std::ios::in | std::ios::binary);
if (input.is_open()) {
std::string line;
std::getline(input, line);
if (line != "P6" || line != "P3" ) { //you're going to want to check if you're using P3 or P6
//print out errors
}
std::stringstream image_dimensions(line);
try {
image_dimensions >> w //your width variable if you want to store it here
image_dimensions >> h //your height variable if you want to store it here
} catch (std::exception &e) {
std::cout << "Format error found in header " << e.what() << std::endl;
return;
}
int size = w*h;
std::getline(input, line);
std::stringstream max_value(line); //max colour value of the image
//you can initialise the vectors here if you want
std::vector<unsigned char> r;
std::vector<unsigned char> g;
std::vector<unsigned char> b;
//we know it max capacity so reserve that size for the vectors
r.reserve(size);
g.reserve(size);
b.reserve(size);
char read_rgb;
for (unsigned int i = 0; i < size; ++i) {
input.read(&read_rgb, 1);
r[i] = (unsigned char) read_rgb;
input.read(&read_rgb, 1);
g[i] = (unsigned char) read_rgb;
input.read(&read_rgb, 1);
b[i] = (unsigned char) read_rgb;
}
}
input.close();
}
You'll want to store r,g,b as arrays of your choosing. Once you've done that, you can just iterate over the array of B and edit it to apply your filter and then just write it to a ppm file.
Also, for error handling, you can always open up the .ppm file using Notepad or Notepad++ and read the image.
My problem is that using ifstream read and fread on a file descriptor don't seem to produce the same results.
I open a file and read its input using ifstream open/read in ios::binary mode. Then I write this buffer out to a file. out1.
Next, I open the same file, read its input using FILE* file descriptors and fread. Then I write this buffer out to another file, out2.
When I compare out1 to out2 they do not match. out2, which uses FILE*, seems to stop reading, near the end.
More worrisome is that neither buffer matches the input file. The ifstream::read method seems to be modifying the end of line characters, even though I open the input file as ios::binary.
The fread method seems to be returning a value less than length (199) even though it's reading significantly more characters than that, as I can see the buffer that got read. This doesn't match the length determined by the seekg commands.
I'm quite confused and any help would be appreciated. Code is attached.
Thanks!
-Julian
ifstream read_file;
read_file.open("V:\\temp\\compressiontest\\out\\test_20224-5120_256x256.jpg", ios::binary);
read_file.seekg(0, ios::end);
unsigned long length = read_file.tellg();
cout << "Length: " << length << endl;
read_file.seekg(0, ios::beg);
unsigned char* buffer = new unsigned char[length];
unsigned char* buf = new unsigned char[length];
for(int i = 0; i < length; i++)
{
buffer[i] = 0;
buf[i] = 0;
}
if(read_file.is_open())
{
read_file.read((char*)buffer, length);
}
else
{
cout << "not open" << endl;
}
read_file.close();
FILE* read_file_1 = NULL;
read_file_1 = fopen("V:\\temp\\compressiontest\\out\\test_20224-5120_256x256.jpg", "r");
size_t read_len = fread(buf, 1, length, read_file_1);
fclose(read_file_1);
if(read_len != length)
cout << "read len != length" << " read_len: " << read_len << " length: " << length << endl;
int consistent = 0;
int inconsistent = 0;
for(int i = 0; i < length; i++)
{
if(buf[i] != buffer[i])
inconsistent++;
else
consistent++;
}
cout << "inconsistent:" << inconsistent << endl;
cout << "consistent:" << consistent << endl;
FILE* file1;
file1 = fopen("V:\\temp\\compressiontest\\out1.jpg", "w");
fwrite((void*) buffer, 1, length, file1);
fclose(file1);
FILE* file2;
file2 = fopen("V:\\temp\\compressiontest\\out2.jpg", "w");
fwrite((void*) buf, 1, length, file2);
fclose(file2);
return 0;
You're calling fopen() for read using mode r instead of mode rb and for write using mode w instead of mode wb, which on Windows (default) means that you're both reading and writing with text translation, not in binary mode.