Preface: I am a inexperienced coder so its probably an obvious error. Also like all of this code is stolen and slapped together so I claim no ownership of this code.
System: I am using windows 10 64 bit. I write my code in Notepad++ and compile with MinGW G++.
What I'm trying to do: I am trying to read an entire file (BMP format) into a variable and return a pointer to that variable as the return of a function.
What's happening: The variable is only storing the first char of the file.
char* raw_data(std::string filename){
//100% non-stolen
std::ifstream is (filename, std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
std::cout << is.tellg() << "\n";
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... \n";
// read data as a block:
is.read (buffer,length);
std::cout << "\n\n" << *buffer << "\n\n";
if (is)
{std::cout << "all characters read successfully.";}
else
{std::cout << "error: only " << is.gcount() << " could be read";}
is.close();
// ...buffer contains the entire file...
//101% non-stolen
return {buffer};
}
return {};
}
The code calling the function is
char * image_data = new char [image_size];
image_data = raw_data("Bitmap.bmp");
This compiles fine and the EXE outputs
0
Reading 2665949 characters...
B
all characters read successfully.
The file Bitmap.bmp starts:
BM¶ƒ 6 ( € ‰ €ƒ Δ Δ ¨δό¨δό¨δό¨
As you can see, the variable buffer only stores the first char of Bitmap.bmp (if I change the 1st char it also changes)
Any help would be appreciated.
Thank you for your time.
std::cout << "\n\n" << *buffer << "\n\n";
Buffer is a char*, so by dereferencing it you get a single char, which in your case is B. If you want to output the whole data that you read just don't dereference the pointer, in C/C++ char* has special treatment when outputing with std::cout,printf and such.
std::cout << "\n\n" << buffer << "\n\n";
Keep in mind that by convention, C-strings in char* should be null-terminated, yours is not and the caller of your function has no effective way to check how long it is, that information is lost as functions like strlen expect the Cstring to be null-terminated too. You should look at std::vector<char> or std::string for holding such data, as they will hold the information about the size, and clean after themselves.
Related
I'm trying to figure out a way to manipulate the binary code of any file in the computer in goal to apply a compress/decompress algorithm in c++ .
I have been searching about that for long time and all i found was how to read a .bin file :
#include <iostream>
#include <fstream>
using namespace std;
int main (){
streampos size;
char * memblock;
ifstream file ("name.bin", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char[size];
file.seekg (0, ios::beg);
file.read (memblock, size);
for(int i = 0 ; i < size ; i++){
cout << memblock[i] ;
}
file.close();
cout << "\n\n the entire file content is in memory";
delete[] memblock;
}
else cout << "Unable to open file";
return 0;
}
I just wanna those bytes without ASCII translation, other words i wanna all the file as binary not what is inside it
<< is overloaded for char types to output the ASCII formated character. The data (the ones and zeros) in your memblock array are accurately read in as binary. It's just the way you're displaying them that is ASCII. Instead of a char[] for memblock, make it a uint8_t[]. Then, when you output, do
std::cout << std::hex << std::fill('0') << std::setw(2) << memblock[i];
^ ^ ^
| | |
| | sets the width of the next output
| sets the fill character (default is space)
tells the stream to output all numbers in hexadecimal
You'll have to #include <iomanip> for the stream format manipulators hex, fill, and setw to work.
Note that setw will only be set on the stream for the next output operation, while hex and fill will be set until explicitly set otherwise. That said, you only need to set these two manipulators once, probably outside your loop. Then when you're finished, you can set them back like:
std::cout << std::dec << std::fill(' ');
See https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2 for the list of overloaded operator<< functions for char and char arrays.
The answer was simpler than we thought :
include bitset
for(int i = 0 ; i < size ; i++){
//changing the value of "memblock[i]" to binary byte per byte with for loop
//and of course using bitset
bitset<8> test (memblock[i]);
cout << test ;
}
I'm trying to read a file into a buffer and then use regex iterator. I know I can use a C++ string iterator with the regex iterator (constructor is std::regex_iterator<std::string::iterator>), but I'd like to avoid copying my buffer into a string and keep using low level functions to read the file (right now I'm using open() and read()).
struct stat buff;
int file = open(argv[1], O_RDONLY);
if(!file)
cout << "Error opening file" << endl;
else if(fstat(file, &buff))
cout << "Error" << endl;
else
{
cout << (buff.st_size) << endl;
char fr[buff.st_size+1];
read(file, fr, buff.st_size); // using string::c_str() or string::data() didn't work
fr[buff.st_size] = '\0';
// then use regex iterator to iterate through matches
}
close(file);
I think that my options are to find a way to use read() with a C++ string instead of char * or a way to use the regex iterator on a char array. I could write one, but I'm also trying to keep my program as small as possible.
Is there a way I can do that? How can I use C++ string as C char * (for read())?
Just use std::regex_iterator<char*>. A pointer is a fine bidirectional iterator on it's own. Also, avoid allocating a large char array on the stack, it might overflow. Instead, use the heap:
std::unique_ptr<char[]> fr = new char[buff.st_size + 1];
If you want to use a std::string you can simply pass the address of the first element of the string to the read() function like this:
struct stat buff;
int file = open(argv[1], O_RDONLY);
if(!file)
cout << "Error opening file" << endl;
else if(fstat(file, &buff))
cout << "Error" << endl;
else
{
cout << (buff.st_size) << endl;
// char fr[buff.st_size+1];
std::string fr; // use a std::string
fr.resize(buff.st_size); // resize it to create internal buffer
read(file, &fr[0], fr.size()); // this should work
// read(file, fr, buff.st_size);
// fr[buff.st_size] = '\0';
// then use regex iterator to iterate through matches
}
close(file);
This question already has answers here:
How do I read an entire file into a std::string in C++?
(23 answers)
Closed 8 years ago.
This may be trivial, but I'm new to C++ and an getting confused here.
I have the method:
bool load_database_file( const std::string& filename, std::string& contents ) {
std::ifstream is (filename, std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = (int)is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer, length);
if (is)
std::cout << "all characters read successfully.";
else
std::cout << "error: only " << is.gcount() << " could be read";
is.close();
// ...buffer contains the entire file...
std::string str(buffer);
contents = str;
delete[] buffer;
}
return true ;
}
where I would like to read a file and assign it's contents to contents so that it can be read by the calling function.
My issue is that after this function is run, I see that only the first character of buffer was copied to contents.
How can I copy/convert the entire contents of buffer (a char *) to contents (a std::string).
std::string str(buffer);
Should be:
std::string str(buffer, buffer+length);
Otherwise, how can the constructor know how many bytes to allocate/copy?
By the way, your code is needlessly clumsy. Why not read directly into the string's buffer rather than using a separate buffer that you have to allocate and free just to hold the data before you allocate another buffer?
I have a large document that has two pieces. The first is a header, which uses standard characters and ends with [END]. The second part is in binary, and looks something like: NUL DLE NUL DC1 NUL. I am attempting to read in this document using an ifstream. My code is:
std::string filename = "file.txt";
std::ifstream originalFile;
originalFile.open(filename,std::ios::binary);
std::streampos fsize = 0;
fsize = originalFile.tellg();
originalFile.open(0,std::ios::end);
fsize = originalFile.tellg() - fsize;
char * buffer = new char [int(fsize)];
originalFile.seekg(0,std::ios::beg);
originalFile.reade(buffer,fsize);
std::cout << fsize << std::endl;
std::cout << buffer << std::endl;
When I run it, The program outputs the entire header of my file, and then ends. It does not access or print any of the binary data. Is this the right command to be using? If not, is there something else I can try?
Your dump of the file data (which presumably;y really looks like std::cout << buffer << std::endl;) is stopping when it hits the NUL character which it considers to be the end of a C-style string.
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();
}