Store Binary File Into a String? (C++)

Started by
13 comments, last by Zahlman 13 years, 11 months ago
Hello, I was wondering how can I take a binary file and grab it's contents and place it into a string? And yes I looked at the fread example on cplusplus.com. I have done some Google for a few hours. Every method I tried to use doesn't work or it only gets 4 characters of the binary file... I seem to have more luck with text files using the fopen reading the file as a binary which is kinda ironic if you ask me. But anyways why I want to do this is because I have a Mysql server I'm using to store files. I need to upload the contents of the binary file to Mysql for it to actually store the file. So then I can do my will with that file in the database. Any suggestions?
Check out my open source code projects/libraries! My Homepage You may learn something.
Advertisement
"Every method I tried to use doesn't work or it only gets 4 characters of the binary file... I seem to have more luck with text files using the fopen reading the file as a binary which is kinda ironic if you ask me."

Can you post some of the methods you've tried ?

One thing that seems "familiar" in that I've seen it done in the past is something like the following...pseudo code kind of...

char * buffer = allocate( x number of bytes );

read sizeof(buffer) from file...which will read sizeof(char *) = 4 bytes

Oh what an optimization to find (embarrassingly)...correcting it sped up load times no end...LOL !

If the file contains binary data, you should not put it in a string. Strings are for text.

FILE* f = fopen(filename, "rb");fseek(f, SEEK_END, 0);long size = ftell(f);fseek(f, SEEK_SET, 0);std::vector<char> buf(size);fread(&buf[0], 1, size, f);fclose(f);


And of course, this is the C-style FILE*-based API. For sanity, you could/should use std::ifstream.

In any way, you should use a std::vector<T> for whenever you need a contiguous buffer of suitable size to pass somewhere, like say MySQL. &v[0] gives you a pointer to the first element, and v.size() gives you the number of elements.

To make it is hell. To fail is divine.

Hey Zao!

I tried out your method it works so far, right now I'm just debugging this little problem with the accumulate function I'm using to convert the vector into the string.

So far the output is correct, what I find really odd is when I return that string through the function it's out put is this: 'Ä'. Is there any reason why when I return that string it turns out like that?

//====================================//getFileContents(const char *szfilePath)//====================================//...std::vector<char> vBuf(lSize);fread(&vBuf[0], 1, lSize, pFile);  // terminate  fclose (pFile);std::string strBuf = accumulate(vBuf.begin(), vBuf.end(), std::string(""));buffer = (char*)strBuf.c_str();  return buffer;	}//======================================//SomeOther.cpp//======================================buf = fileSearch.getFileContents(szFilename);//After that is called buf equals to "Å"?


Is this some kind of garbage collection issue?
Check out my open source code projects/libraries! My Homepage You may learn something.
std::ifstream file("filename.txt", std::ios::binary);std::istreambuf_iterator<char> b(file), e;std::string content(b, e);


EDIT:

std::string strBuf = accumulate(vBuf.begin(), vBuf.end(), std::string(""));buffer = (char*)strBuf.c_str();  return buffer;	}


You're effectively returning a pointer to a local variable. Once the function has returned, strBuf and all of its resources are destroyed. buffer will point to memory with unpredictable content.

[Edited by - the_edd on April 25, 2010 4:03:13 PM]
1) You can't just return the .c_str() of a local variable, for the same reason that you can't return a reference to a local variable or a pointer into a local array. So just return the string. But actually, don't just return the string; just return the vector - keep reading.

2) Using std::accumulate like that is going out of your way to do huge amounts of extra work and slow down the program while churning through memory.

You can create a string from a std::vector<char> directly, like so:

std::string strBuf(vBuf.begin(), vBuf.end());


3) But why would you want to do that? As you were already told, std::string instances are for text, and you don't have text, or you would be opening it as a text file rather than as a binary file. Just return the vector.
Alright well now I'm back to the first problem started of only getting 4 characters of the files. But I need it in a form of a string so I can run a mysql command through C++ to be able to upload the file. Is there some alternative then using a string to store the binary contents so I can transfer the file via Winsock and Mysql?
Check out my open source code projects/libraries! My Homepage You may learn something.
Yes there are alternatives!

#1 - convert your binary data into a string of hexidecimal digits. This will double the size of your data, but it will be safe to store in a database text field.

or

#2 - convert your binary data into a string of "base 64" encoding. This is more commonly used on the web, and makes your data 25% larger instead of 100%. Check it out here: http://en.wikipedia.org/wiki/Base64

But why are you trying to store files in a database? Files don't belong in databases, it makes the database preform very poorly.

Store it on disk instead, and if you need to store data about the file too, store that in the database, but keep the file seperate!
Quote:Original post by ajm113
Alright well now I'm back to the first problem started of only getting 4 characters of the files. But I need it in a form of a string so I can run a mysql command through C++ to be able to upload the file. Is there some alternative then using a string to store the binary contents so I can transfer the file via Winsock and Mysql?

Did you try the code the_edd posted? How do you know you only read 4 bytes?
@Zipster and edd, sorry I forgot to mention! I tried that I get the same effect pretty much. I'm just looking at what VS2008 gives me in debug mode. I'm guesting what VS2008 isn't as always accurate in debug with strings that has binary data?

@ Atrix256

I really like the hex idea! I already got a hex converter going and sending hex to the server right now for the file. Plus I think it would save me from having to create a anti mysql injection attack system.

The reason why I'm using a database instead of a regular old FTP route is for security reasons. Just so no one can get into my computer using what I created or try to access files the user uploaded. Plus it may be for a website too on the side.

It will make my life easier just using PHP and C++ for mysql then having to write a security system myself using C++ and PHP to keep people hacking files or doing any damage to the files easily.

I have one more question if you can answer me this if anyone doesn't mind me asking.

For some odd reason even though the values in debug mode show correctly on the variables in VS2008.

It seems that sprintf is messing the values up and sometimes crashing itself. Here is a example of what I have:

bool Mysql_class::UploadFile(int UserId, MYSQL_FILE_PACKET packet){	if(strlen(packet.fileData.c_str()) < 1 || strlen(packet.fileName.c_str()) < 4)		{			return false;		}		int StatementId = FindAvailableStatement();	if(StatementId < 0)	{	return false;	}	try	{			char query[2025];			char* fileName = (char*)packet.fileName.c_str();			 char* gameName = (char*)packet.GameName.c_str();			 char* fileData = (char*)packet.fileData.c_str();			 __int64 CreationTime = packet.fileCreationDate;		sprintf(query, "UPDATE files SET fileCreationDate=%i, fileData=\'%s\' WHERE owner=%i;", CreationTime, fileData,  UserId);		// pstmt = con->prepareStatement();		MySQLstatment[StatementId].stmt = con->createStatement();        	MySQLstatment[StatementId].stmt->execute(query);


When really the value for query is supposed to be this
"UPDATE files SET fileCreationDate=2147483647, fileData='0x01CF7EC0 48656C6C6F20576F726C6421DA486F77417265596F753F' WHERE owner=1;".

The variable's value after is really this:
"UPDATE files SET fileCreationDate=2147483647, fileData='(null)' WHERE owner=30375616;" Which is really odd because fileData isn't empty and idk where the heck 30375616 is coming from...

Sorry if this question kinda seems low level for me to ask, but I'm kinda light headed for my room being really stuffy.

[Edited by - ajm113 on April 26, 2010 9:53:30 PM]
Check out my open source code projects/libraries! My Homepage You may learn something.

This topic is closed to new replies.

Advertisement