Suppose I write a program in C/C++ and create an array of certain size. I want to keep that permanently even if I switch off the computer and later access it. Is there a way to do that? If so do let me know and also after saving it, how to access it.
Save the data to a file and load it on programm start.
Say you create a vector of MAX size for a string:
char * str = (char *) malloc( MAX );
At some point, you fill it with some data:
strcpy( str, "Useful data in the form of a string" );
Finally, at the program's end, you save it to a file:
FILE * f = fopen( "data.bin", "wb" );
fwrite( str, 1, MAX, f );
fclose( f );
At the beginning of the next execution, you'd like to load it:
char * str = (char *) malloc( MAX );
FILE * f = fopen( "data.bin", "rb" );
fread( str, 1, MAX, f );
fclose( f );
This solution has a few shortcomings: for example your data will be only useful for the computer in which you saved it. If you want portability, then you should use text and XML: http://www.jclark.com/xml/expat.html
Hope this helps.
You could use a memory mapped file and use offsets in the memory mapped file in place of pointers. You would have to implement your own dynamic block allocation management in the memory mapped file.
Using offsets would be less efficient than pointers. But you would load and save the data structure in a snap.
It is possible to avoid the use of offset and use real pointers instead. To do this, you save the pointer value to the memory mapped file when you close the memory mapped file. When you load the memory mapped file, you would then have to adjust all pointers in the data structure by adding the offset of the pointer to the memory mapped file.
If the data structure is small, you could do it in one pass when the file is mapped into memory. If the data structure is big, you could do it in a lazy way and only fix pointers of struct when you access them for the first time.
Related
I have an unsigned char array in c++, and I want to save it's bits into a file.
So for example if I have the array below
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
I want to save this into the file so that the binary data of the file looks like this (without the spaces).
00000000 00000001 00000010
I have tried this code below but it doesn't seem to work. I give the program a blank file that is 0 bytes in size, and after the program runs the file remains 0 bytes in size (nothing gets written to it).
// Create unsigned char array
unsigned char *arrayToWrite= (unsigned char*)malloc(sizeof(unsigned char)*720);
// Populate it with some test values
arrayToWrite[0] = 0;
arrayToWrite[1] = 1;
arrayToWrite[2] = 2;
// Open the file I want to write to
FILE *dat;
dat = fopen("filePath.bin", "wb");
// Write array to file
fwrite(&arrayToWrite, sizeof(char)*720, 1, dat);
fclose(dat);
I would expect after this program runs that the file "filePath.bin" would be 720 bytes long filled with mostly 0's except for the first and second position I filled with test data.
What am I doing wrong? Any help would be much appreciated! Thank you!
The basic issue there is that you're passing the pointer to your arrayToWrite variable, rather than to the array itself. Change fwrite(&arrayToWrite... to fwrite(arrayToWrite....
BTW, malloc() does NOT promise to give you zeroed memory. For that, use calloc() to allocate and zero memory or memset() to zero already-allocated memory. (Though all that is more a C thing; for C++ you'd be better off using something like std::vector instead of raw C arrays.)
C++ code is written different way:
std::vector<unsigned char> vectorToWrite = { 0, 1, 2 };
vectorToWrite.resize( 720 );
std::ofstream file( "filePath.bin", std::ios::out | std::ios::binary );
if( !file ) {
// error handling
}
file.write( vectorToWrite.data(), vectorToWrite.size() * sizeof( decltype(vectorToWrite)::value_type ) );
Note: I put sizeof( decltype(vectorToWrite)::value_type ) there so if you later change vector data it will still properly work without further change, but in case of char it can be omitted completely as sizeof(char) is always equal to 1
I am currently writing a file-page-manager program which basically write, append and read pages to binary files. For the writing function, I have to delete the whole content of the specified page and write new content. I need to delete data from a file within a specific range like delete data from position 30 to position 4096.
If there is no more data after position 4096 then you can use truncate(2) to shrink the file to 30 bytes.
If you have more data after 4096 byte then you could first overwrite the data starting at position 30 by the data present after 4096th byte. Then you can truncate the file to [original_filesize - (4096-30)] bytes.
The only way to delete data in a file is to mark it as deleted. Use some value to indicate that the section(s) are deleted. Otherwise, copy the sections you want to save to a new file.
So easy with std::string
Follow the steps:
read the file and extract it to the std::string
std::ifstream input_file_stream( "file" );
const unsigned size_of_file = input_file_stream.seekg( 0, std::ios_base::end ).tellg();
input_file_stream.seekg( 0, std::ios_base::beg ); // rewind
std::string whole_file( size_of_file, ' ' ); // reserved space for the whole file
input_file_stream.read( &* whole_file.begin(), size_of_file );
then erase what you want:
// delete with offset
whole_file.erase( 10, // size_type index
200 ); // size_type count
and finally write to a new file:
// write it to the new file:
std::ofstream output_file_stream( "new_file" );
output_file_stream.write( &*whole_file.begin(), whole_file.size() );
output_file_stream.close();
input_file_stream.close();
I have two code samples, the first is the following:
//THIS CODE READS IN THE CALC.EXE BINARY INTO MEMORY BUFFER USING ISTREAM
ifstream in("notepad.exe", std::ios::binary | std::ios::ate);
int size = in.tellg();
char* buffer = new char[size];
ifstream input("calc.exe", std::ios::binary);
input.read(buffer, size);
This is the second:
//THIS CODE GETS FILE MAPPING IMAGE OF SAME BINARY
handle = CreateFile("notepad.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
mappinghandle = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
image = (DWORD) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
My question is, what exactly is the difference between these two methods? If we are ignoring the sizing issue that is better handled by file mapping, are these two objects returned essentially the same? Will not the image variable point to essentially the same thing as the buffer variable - this being an image of the binary executable in memory? What are all the differences between the two?
The method using std::ifstream actually copies the data of the file into RAM, when input.read() is called whereas MapViewOfFile doesn't access the file data.
MapViewOfFile() returns a pointer, but the data will only actually be read from disk when you access the virtual memory that the pointer points to.
// This creates just a "view" of the file but doesn't read data from the file.
const char *buffer = reinterpret_cast<const char*>( MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0) );
// Only at this point the file actually gets read. The virtual memory manager now
// reads a page of 4KiB into memory.
char value = buffer[ 10 ];
To further illustrate the difference, say we read a byte at offset 12345 from the memory-mapped file:
char value = buffer[ 12345 ];
Now the virtual memory manager won't read all the data up to this offset, but instead only map the page that is closest to that offset into memory. That would be the page located between offset 12288 (=4096*3) and 16384 (=4096*4).
The first one reads from the file into a buffer, the buffer is independent of the original file.
The second one is accessing the file itself, you won't be able to delete the file while a mapping exists, and although you can't make changes because you have a read-only mapping, changes made to that file outside your program can be visible in your mapping.
I would like to write char* buf[] to shared memory.
I got several pointer to several maps - char* m_pP[MAX], maps are opened
m_oMMF[channel] = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, wstring);
m_pP[channel] = (char*) MapViewOfFile(m_oMMF[channel], FILE_MAP_ALL_ACCESS, 0, 0, size);
size of map is big enough, I got int offset where I wanna to write in shared memory using this m_P[] pointer but I am struggling at the syntax of this.
Im not so experienced in C++.
Can anyone help me with this?
Thanks
Not sure If I understood clearly.
But I assume, you have character pointer pointing to mapped memory and you are trying to write data after certain offset.
char * ptr_to_memory = m_pP[channel];
//buf is array of character pointer, so you need to know the "index" as well as "size" of the data you need to write.
char * data_to_write = buf[index];
memcpy( ptr_to_memory + offset, data_to_write, size );
Remember to do some sanity check, whether ( ptr + offset ) is within the mapped region.
I have a program that records data from a serial port. Every so often, I want to split up files such that the data logs don't become very large. The problem is, after I recreate the FILE* and try to write into it, the program crashes. No compiler errors/warnings before hand also...
The program does create one log for the first time interval, but once it's time to create a new data log, it crashes at the fwrite.
First off, initializations/declarations.
char * DATA_DIR = "C:\DATA";
sprintf(path,"%s%s%s",DATA_DIR,curtime,".log"); //curtime is just the current time in a string
FILE * DATA_LOG = fopen(path, "wb+");
And later on in a while loop
if(((CURRENT_TIME-PREVIOUS_TIME) > (SEC_IN_MINUTE * MINUTE_CHUNKS) ) && (MINUTE_CHUNKS != 0) && FIRST_TIME == 0) //all this does is just checks if its time to make a new file
{
fclose(DATA_LOG); //end the current fileread
char * path;
char curtime[16];
//gets the current time and saves it to a file name
sprintf(curtime , "%s" , currentDateTime());
sprintf(path,"%s%s%s",DATA_DIR,curtime,".log");
DATA_LOG = fopen(path, "wb+"); //open the new file
//just some logic (not relevant to problem)
PREVIOUS_TIME = CURRENT_TIME;
newDirFlag = 1;
}
fwrite(cdata , sizeof(char) , numChars , DATA_LOG); //crashes here. cdata, sizeof, and numChars don't change values
Any ideas why is this happening? I'm stumped.
Couple of problems, path has no memory allocated (you're writing stuff to some random memory address which is bad). You also should check the return values of fwrite fopen for errors. If there is one use perror so you know what the problem is. It's likely the fopen is failing or you're corrupting your stack by writing to path.
Also use snprintf it's much safter than just sprintf which is vulnerable to buffer overflow.
EDIT: just saw your comment that it's c++. Why not use std::string and fstream instead? They are much safer than what you're currently doing (and probably easier).
Your MAIN problem is that char * path; has no memory assigned to it. This means that you are writing to some RANDOM [1] location in memory.
I would suggest that you use char path[PATH_MAX]; - that way you don't have to worry about allocating and later deallocating the storage for your path.
Alternatively, you could use:
stringstream ss;
ss << DATA_DIR << currentDateTime() << ".log";
string path = ss.str();
fopen(path.c_str(), "wb+")
which is a more C++ style solution.
[1] By random, I don't mean truly a random number, but some unknown value that happens to be in that location on the stack. It is almost always NOT a good place to store a string.