I'm making a C++ program to be able to open a .bmp image and then being able to put it in a 2D array. Right now i have the code like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "Image.h"
using namespace std;
struct colour{
int red;
int green;
int blue;
};
Image::Image(string location){
fstream stream;
string tempStr;
stringstream strstr;
stream.open(location);
string completeStr;
while(!stream.eof()){
getline(stream, tempStr);
completeStr.append(tempStr);
}
cout << endl << completeStr;
Image::length = completeStr[0x13]*256 + completeStr[0x12];
Image::width = completeStr[0x17]*256 + completeStr[0x16];
cout << Image::length;
cout << Image::width;
cout << completeStr.length();
int hexInt;
int x = 0x36;
while(x < completeStr.length()){
strstr << noskipws << completeStr[x];
cout << x << ": ";
hexInt = strstr.get();
cout << hex << hexInt << " ";
if((x + 1)%3 == 0){
cout << endl;
}
x++;
}
}
Now if i run this on my test file of 256x256 it will print fine, until it reaches 0x36E where it gives an error / doesn't go further. This happens because the completeStr string doesn't recieve all the data that is in the bmp file. Why isn't able to read all the lines in the bmp file?
There are a number of problems with your code. The principal
one (and probably the reason for your problem) is that you are
opening the file in text mode. Technically, this means that if
the file contains anything but printable characters and a few
specific control characters (like '\t'), you have undefined
behavior. In practice, under Windows, this means that sequences
of 0x0D, 0x0A will be converted into a single '\n', and that
a 0x1A will be interpreted as the end of the file. Not really
what one wants when reading binary data. You should open the
stream in binary mode (std::ios_base::binary).
Not a serious error, but you shouldn't really use an fstream
if you are only going to read the file. In fact, using an
fstream should be very rare: you should use either ifstream
or ofstream. The same thing holds for stringstream (but
I don't see any role for stringstream when reading a binary
file).
Also (and this is a real error), you are using the results of
getline without checking whether is succeeded. The usual
idiom for reading lines would be:
while ( std::getline( source, ling ) ) ...
But like stringstream, you don't want to use getline on
a binary stream; it will remove all of the '\n' (which have
already been mapped from CRLF).
If you want all of the data in memory, the simplest solution is
something like:
std::ifstream source( location.c_str(), std::ios_base::binary );
if ( !source.is_open() ) {
// error handling...
}
std::vector<char> image( (std::istreambuf_iterator<char>( source ) ),
(std::istreambuf_iterator<char>()) );
std::getline reads in a line of text.
It's not useful for a binary file.
Open the file in binary mode and use unformatted input operations (like read).
Related
I have some code here
https://github.com/Fallauthy/Projects/blob/master/cPlusPlusProjects/bazaPracownikow/bazaPracownikow/bazaPracownikow/main.cpp
And I have no idea how to show contents in my file. I mean i know how, but it doesn't show same I Have in file (in link). It show in next line. This code is responsible to load file
while (!baseFile.eof()) {
//wczytaj zawartosc pliku do zmiennej
std::string buffer;
baseFile >> buffer;
//wypisz
loadLineFromBase += buffer;
loadLineFromBase += " \n";
}
std::cout << loadLineFromBase << std::endl;
Unless I see all your code all I can do for you is give you a sample in return, I don't know what you're trying to do but it seems in this case you're looking for this.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string Display = "";
ofstream FileOut;
ifstream FileInput;
FileOut.open("C:\\Example.txt");
FileOut << "This is some example text that will be written to the file!";
FileOut.close();
FileInput.open("C:\\Example.txt");
if (!FileInput)
{
cout << "Error File not Found: " << endl;
return 1;
}
while (!FileInput.eof())
{
getline(FileInput, Display);
}
FileInput.close();
cout << Display << endl;
return 0;
}
Simply put if you're currently working wit ha text document
use getline()
When you use getline() it takes two arguments the first will be in this case your ifstream object, as in what you're using to open the file. The second will be the string you're using to store the contents in.
Using the method I outlined above you'll be able to read the entire file contents.
And please next time as it was said above outline your problem more in depth and if you provide us with all of your code we may better assist you!
Your snippet of code automatically add a newline to every string read from the input file, even if originally those were words separeted by spaces. Probably you want to keep the structure of the original file, so it's better to read one line at a time and, unless you need it for some other uses, print it out in the same loop.
std::string buffer;
// read every line of baseFile till EOF
while ( std::getline(baseFile, buffer) ) {
std::cout << buffer << '\n';
}
i am new to this site , and this my first question !
i have a question about fstream function .
fstream f("new.dat",ios::out|ios::in);
fstream is for both input and output , so when we use it like this , and there is a new.dat file before it will output and input both . but it is strange , when i do that , it will output data correctly , but it is unable to input .
i found out if you close it , and reopen it , it will input . why it is like that??
int main()
{
fstream writeFile("newFile.dat", ios::out|ios::in);
char i[3];
char u[3]="HI";
if (!writeFile)
{
cerr << "error" << endl;
}
writeFile << u <<endl;
writeFile >> i;
cout << i << endl;
}
this is my full code , and result is an empty line.
The fstream object has a position in its output file, and since you opened it just for output and input without any position or writing modifiers, that position is at the end of the file. When you output i to the file, writeFile writes i to the file, and then moves its position past i so when you ask it to write more, you don't overwrite i.
You can reset the position to the start of the file with a call to writeFile.seekg(0), which places that internal position at the 0 position in the file (at the start).
If you're curious about stream manipulation, I'd suggest a look at cppreference.com and specifically its documentation on c++'s input and output libraries here.
Couple things going on here:
You can't open a file for reading if it doesn't exist, this includes a file you want to read and write. No file, no open.
Once you manage to open a file, the stream keeps track of where it is in the file. As you read or write, obviously the location moves.
There is only one location marker in the stream, so you can read to where you want to write, then write. Unfortunately this means any further reading will pick up after the write. If that's not what you want, get and store the current location (with tellg) before writing, and seek (with seekg) to the stored location after writing.
This has some problems such as what if the block of data you wish to insert is longer or shorter than the block of data you want to overwrite? The simple solution to this problem is read into buffer, edit buffer, write buffer back to file.
When you open a file and start writing into it, you overwrite whatever was in the file. If you want to add to a file, open with ios::app. This sets the stream's location to the end of the file. I am unaware of any sort of insert that pushes existing data along as you write in new data.
Some simple file handling example code
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
fstream f1("filename", ios::out);
if (f1.is_open())
{
if (f1 << "Hi")
{
cout << "wrote"<<endl;
}
f1.close();
}
fstream f2("filename", ios::out|ios::app);
if (f2.is_open())
{
if (f2 << " there!")
{
cout << "appended"<<endl;
}
f2.close();
}
fstream f3("filename", ios::in);
if (f3.is_open())
{
cout << f3.rdbuf()<< endl;
f3.close();
}
fstream f4("filename", ios::in|ios::out);
if (f4.is_open())
{
f4.seekg(3);
if (f4 << "Fred!")
{
cout << "overwrote"<<endl;
}
f4.close();
}
fstream f5("filename", ios::in);
if (f5.is_open())
{
cout << f5.rdbuf()<< endl;
f5.close();
}
// note the extra ! on the end left over from Hi there! I do not know how
// to get rid of this. I have always just done stuff like this to get around it.
fstream f6("filename", ios::in);
stringstream s1;
string token;
f6 >> token;
s1 << token << " Tim!";
f6.close();
fstream f7("filename", ios::out);
f7 << s1.rdbuf();
f7.close();
// and then moved temp over filename.
fstream f8("filename", ios::in);
cout << f8.rdbuf()<< endl;
f8.close();
}
I'm reading info from one text file, then outputting it to a bin file. I got the name to write properly, but the integer and doubles do not work properly. Disregard the system("pause"), they are so I can check my outputs.
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
struct SaleSlip{
char name[20];
int prodID;
double value;
};
void main(){
fstream slips, binslip;
SaleSlip sales[17];
binslip.open("SaleSlips.bin", ios::out | ios::binary | ios::trunc);
slips.open("SaleSlips.txt", ios::in);
if(slips.eof()){
cout << "Cannot open file - SaleSlips.txt"<< endl;
system("pause");
exit(2);
}
int i = 0;
while(!slips.eof()){
slips >> sales[i].name;
slips.ignore(80, ' ');
slips >> sales[i].prodID;
slips.ignore(80, ' ');
slips >> sales[i].value;
slips.ignore(80, '\n');
cout << sales[i].name;
cout << sales[i].prodID;
cout << sales[i].value << endl;
binslip.write((const char *)&sales[i].name, sizeof(sales[i].name));
binslip.write((const char *)&sales[i].prodID, sizeof(sales[i].prodID));
binslip.write((const char *)&sales[i].value, sizeof(sales[i].value));
i++;
}
slips.close();
binslip.close();
system("pause");
}
SaleSlips.txt has one line per item of the array so "Ryan 2 1400.52" is one line. Ryan is interpreted correctly, but when I read back in from the binary it isn't right, nor is it when I check it in textpad.
binslip.write is an UnformattedOutputFunction. There is formatted and unformatted input/output. When you use unformatted output, you are writing raw bytes to the file. There is no interpretation as to what the bytes actually represent.
When you wrote to SalesSlips.bin, you wrote characters followed by numbers (rather, what you thought would be numbers). When you tried to examine SalesSlips.bin, the computer read text characters, and was expecting the rest of the file to be text, but it wasn't. Numbers are represented differently then characters. Even if you were to just deal with numbers alone, integral and floating point values are represented differently in binary. It may be a bit much for you to absorb right now, but the gist of it is you need to use a FormattedOutputFunction. This will perform the internal conversions necessary for you to output your data properly.
Imagine you have a number, lets say, 50. That number is meaningless without units that describe what 50 represents. 50 seconds? 50 feet? 50 states? You can think of binslip.write as just writing 50, and when you try to read the file later, all you see is 50, and you don't understand what it was supposed to represent, which is why it looks like gibberish to you.
To fix your code you need to replace the binslip.write lines with this:
binslip << sales[i].name << sales[i].prodID << sales[i].value;
In this case, operator<< behaves as a FormattedOutputFunction, so when you write SaleSlips.bin, you can open it in a text editor and view Ryan 2 1400.52 like you expected.
While reading and writing in BINARY mode, you are not expected to read the data in any text editor. It simply serves no purpose. If you want to read it in a text editor, recommendation is to use NORMAL mode.
Anyways, if you don't bother about viewing your BINARY data in a text editor, you could use the following lines to Read and write binary file:
while(!slips.eof())
{
slips >> sales[i].name;
slips.ignore(80, ' ');
slips >> sales[i].prodID;
slips.ignore(80, ' ');
slips >> sales[i].value;
slips.ignore(80, '\n');
cout << sales[i].name;
cout << sales[i].prodID;
cout << sales[i].value << endl;
//// WRITE THE STRUCTURE AT ONCE
binslip.write((const char *)&sales[i], sizeof(sales[i]));
i++;
}
binslip.flush();
binslip.close();
//// OPEN UP THE FILE IN READ MODE
binslip.open("SaleSlips.bin", ios::in | ios::binary );
SaleSlip sale;
//// READ UP THE COMPLETE STRUCTURE
binslip.read((char *)&sale, sizeof(sale));
//// PRINT IT.
cout<<sale.name;
cout<<sale.prodID;
cout<<sale.value;
I need to read a jpg file to a string. I want to upload this file to our server, I just find out that the API requires a string as the data of this pic. I followed the suggestions in a former question I've asked Upload pics to a server using c++ .
int main() {
ifstream fin("cloud.jpg");
ofstream fout("test.jpg");//for testing purpose, to see if the string is a right copy
ostringstream ostrm;
unsigned char tmp;
int count = 0;
while ( fin >> tmp ) {
++count;//for testing purpose
ostrm << tmp;
}
string data( ostrm.str() );
cout << count << endl;//ouput 60! Definitely not the right size
fout << string;//only 60 bytes
return 0;
}
Why it stops at 60? It's a strange character at 60, and what should I do to read the jpg to a string?
UPDATE
Almost there, but after using the suggested method, when I rewrite the string to the output file, it distorted. Find out that I should also specify that the ofstream is in binary mode by ofstream::binary. Done!
By the way what's the difference between ifstream::binary & ios::binary, is there any abbreviation for ofstream::binary?
Open the file in binary mode, otherwise it will have funny behavior, and it will handle certain non-text characters in inappropriate ways, at least on Windows.
ifstream fin("cloud.jpg", ios::binary);
Also, instead of a while loop, you can just read the whole file in one shot:
ostrm << fin.rdbuf();
You shouldn't read the file to a string because it is legal for a jpg to contain values that are 0. However in a string, the value 0 has a special meaning (it's the end of string indicator aka \0). You should instead read the file into a vector. You can do this easily like so:
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
int main(int argc, char* argv[])
{
std::ifstream ifs("C:\\Users\\Borgleader\\Documents\\Rapptz.h");
if(!ifs)
{
return -1;
}
std::vector<char> data = std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
//If you really need it in a string you can initialize it the same way as the vector
std::string data2 = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
std::for_each(data.begin(), data.end(), [](char c) { std::cout << c; });
std::cin.get();
return 0;
}
Try opening the file in binary mode:
ifstream fin("cloud.jpg", std::ios::binary);
At a guess, you were probably trying to read the file on Windows and the 61st character was probably 0x26 -- a control-Z, which (on Windows) will be treated as marking the end of the file.
As far as how to best do the reading, you end up with a choice between simplicity and speed, as demonstrated in a previous answer.
This is a very strange issue. I'm trying to print a large text file, it's a Wikipedia entry. It happens to be the page on Velocity. So, when I tell it to print the file, it prints "In", when it should print "In physics, velocity is etc, etc etc".
Here's the code I'm using to print out:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char* wikiRead;
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
}
Please help.
wiki >> wikiRead;
The default delimiter for stream is space, so when the stream encounters a space, it simply stops reading, that is why it reads only one word.
If you want the stream to read all words, the you've to use a loop as:
char* wikiRead = new char[1024]; //must allocate some memory!
while(wiki >> wikiRead)
{
cout << wikiRead << endl;
}
wiki.close();
delete []wikiRead; //must deallocate the memory
This will print all the words in the file, each on a new line. Note if any of the word in the file is more than 1024 character long, then this program would invoke undefined behavior, and the program might crash. In that case, you've to allocate a bigger chunk of memory.
But why use char* in the first place? In C++, you've better choice: Use std::string.
#include<string>
std::string word;
while(wiki >> word)
{
cout << word << endl;
}
wiki.close();
Its better now.
If you want to read line-by-line, instead of word-by-word, then use std::getline as:
std::string line;
while(std::getline(wiki, line))
{
cout << line << endl;
}
wiki.close();
This will read a complete line, even if the line contains spaces between the words, and will print each line a newline.
You ask the stream to read the (binary) value of a pointer (probably 4 bytes, depending on your machine architecture), then you ask it to print the text pointed to by those 4 bytes!
I wonder why you ignored the compiler warning (most of the modern compiler warns you about using uninitialized variables). How about this?
ifstream wiki;
wiki.open("./wiki/velocity.txt");
char wikiRead[255];
wiki >> wikiRead;
cout << wikiRead << endl;
wiki.close();
Alternatively I'd suggest you to use string object with getline to get a single line of text.
string str;
getline(wiki, str);
The >> operator applied to a char * reads only one word. Moreover, you're reading into an uninitialized pointer, which is not valid. Usually std::string, not char *, is used for string processing in C++.
If you only want to print the file's contents, you can hook the file's buffer directly to std::cout:
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::cout << wiki.rdbuf() << '\n';
}
If you want to put the contents into an automatically-allocated string, use std::getline with the delimiter disabled.
int main() {
std::ifstream wiki("./wiki/velocity.txt");
std::string wiki_contents;
getline( wiki, wiki_contents, '\0' /* do not stop at newline */ );
std::cout << wiki_contents << '\n'; // do something with the string
}
Since you want to read a large file, reading it block by block is a better way.
ifstream wiki;
wiki.open("./wiki/velocity.txt");
const int buf_size = 1024;
char* wikiRead = 0;
int cnt = 1;
do
{
wikiRead = realloc( wikiRead, bufsize*cnt );
wiki.Read( wikiRead + (bufSize*(cnt-1)), buf_size ); //appends to reallocated memory
cnt++;
}while( !wiki.eof())
wikiRead[(bufSize*(cnt-2)) + wiki.gcount() + 1] = '\0'; // null termination.
wiki.Close();
cout << wikiRead;
delete[] wikiRead;
The operator>> is designed to only read one word at a time. If you want to read lines, use getline.
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main()
{
ifstream wiki;
wiki.open("./wiki/velocity.txt");
string wikiRead;
while (getline(wiki, wikiRead))
{
cout << wikiRead << endl;
}
wiki.close();
}