Problems saving float array to binary file and reading back (C++) - c++

I am trying to simply write an array of float values to a file and then read it back.
I have tried writing it directly from an array, but when reading it back I keep hitting a problem for arrays with length greater than 153. The code example writes each float value one by one for clarity.
For values with index greater than or equal to 153 they have the value 153.0, where they should be 153.0, 154.0, 155.0, ...
Why doesn't this code work for me?
int length = 160;
char* fileName = "testFile.dat";
// Write data to file
FILE* file = fopen (fileName, "w");
for(int i = 0; i< length; i++){
// We are just storing the indices, so value at i is equal to i
float f = (float) i;
fwrite(&f, sizeof(float), 1, file);
}
fclose(file);
// Read data from file into results array
file = fopen(fileName, "r");
float* results = new float[length];
for(int i = 0; i< length; i++){
float f;
fread(&f, sizeof(float), 1, file);
results[i] = f;
}
fclose(file);
// Now check data in results array
bool fail = false;
for(int i = 0; i< length; i++){
if(results[i]!=(float)i){
fail = true; // This should not be hit, but it is!
}
}
delete [] results;
Thanks,
Dave

FILE* file = fopen (fileName, "wb");
FILE* file = fopen (fileName, "rb");

Related

How to create a dynamic array using new C++?

I'm trying to initialize an array of integers dynamically, since the size of the array changes based on input.
The program is as follows:
int main()
{
int* list = createList("dis.bin");
for (int i = 0; i < sizeof(list) / sizeof(int); i++)
{
printf("%d\n", list[i]);
}
}
With createList() function as written:
int* createList(const char* file_name)
{
int counter = 1;
int* inst{};
FILE* myFile = fopen(file_name, "rb");
if (myFile == nullptr)
{
printf("\nFile not opened\n");
return 0;
}
int x = 0;
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
inst = new int[counter];
inst[i] = x;
printf("%08x #%-4d | Int equiv: %-12d | Bin equiv: %s\n", x, counter, inst[i], ToBinary(inst[i], 0));
counter += 1;
x = 0;
}
return inst;
}
createList reads from a .bin file (basically containing an array of bytes) and inserts each pair of 4 bytes to an item in the array inst. I do this by allocating a new amount of space for the array based on the counter variable. (So whatever value counter is becomes the size of the array with inst = new int[counter]) Then I set the contents of the array at the given index i equal to x (the pair of bytes read) I would assume it is working correctly in createList at least, because of the printf statement which is printing each element in inst[].
However, when I call createList("dis.bin") in main and assign it to the variable int* list, I try to iterate through each value. But this just prints out one uninitialized value (-842150451, if you're curious). So I'm not sure what I'm doing wrong here?
I should mention that I am NOT using vectors or really any std container. I am just working with arrays. I also am using printf for specific reasons.
This question is tagged as C++, but OP is showing C code and says they need it in C, so I will show this in C... but the pre-req is that it uses new and not malloc
int* createList(const char* file_name, int& count)
{
// initialize count, so that way if we return early, we don't have invalid information
count = 0;
// open the file ad "READ" and "BINARY"
FILE* myFile = fopen(file_name, "rb");
if (!myFile)
{
printf("\nFile not opened\n");
return 0;
}
// calculate how many 4-byte integers exist in the file using
// the file length
fseek(myFile, 0, SEEK_END);
count = ftell(myFile) / sizeof(int);
rewind(myFile);
// allocate the memory
int* returnData = new int[count];
// read in 4-byte chunks to our array until it can't read anymore
int i = 0;
while (fread(&returnData[i++], sizeof(int), 1, myFile) == 1);
// close the file
fclose(myFile);
// return our newly allocated data
return returnData;
}
int main()
{
int count;
int* myInts = createList("c:\\users\\andy\\desktop\\dis.bin", count);
for (int i = 0; i < count; ++i) {
printf("%d\n", myInts[i]);
}
// don't forget to delete your data. (another reason a vector would be better suited... no one remembers to delete :)
delete myInts;
}
Two things here:
The usage of new was misinterpreted by me. For whatever reason, I thought that each time I allocated new memory for inst that it would just be appending new memory to the already allocated memory, but this is obviously not the case. If I wanted to simulate this, I would have to copy the contents of the array after each iteration and add that to the newly allocated memory. To solve this, I waited to allocate memory for inst until after the file iteration was complete.
As Andy pointed out, sizeof(list) / sizeof(int) would not give me the number of elements in list, since it is a pointer. To get around this, I created a new parameter int &read for the createList() function in order to pass the number of items created.
With these points, the new function looks like this and works as intended:
int* createList(const char* file_name, int &read)
{
int counter = 1;
FILE* myFile = fopen(file_name, "rb");
if (myFile == nullptr)
{
printf("\nFile not opened\n");
return 0;
}
int x = 0;
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
printf("%08x #%-4d | Int equiv: %-12d | Bin equiv: %s\n", x, counter, x, ToBinary(x, 0));
counter += 1;
}
int* inst = new int[counter];
read = counter;
rewind(myFile); // rewind to beginning of file
for (int i = 0; !(feof(myFile)); i++)
{
fread(&x, sizeof(int), 1, myFile);
inst[i] = x;
x = 0;
}
return inst;
}
With main changed a bit as well:
int main()
{
int read;
int* list = createList("dis.bin", read);
for (int i = 0; i < read; i++)
{
printf("%d\n", list[i]);
}
}
As for the comments about the invalidity of !(feof(myFile)), although helpful, this was not a part of my question and thus not of my concern. But I will source the solution to that for the sake of spreading important information: Why is "while ( !feof(file) )" always wrong?

Write contents of text file to an array of file blocks (512 Bytes) in C++

I am trying to separate a 5 KB text file into a File array of 10 blocks, which are each 512 Bytes.
I have the file loading properly and writing to a char array but I don't understand what is happening at while(infile >> temp[i]) below. Does that mean "while test1.txt still has characters to write, write it to temp[]"?
Basically, I want characters 0 to 511 in input1.txt to load into temp[] then store temp in fileArray[0]. And then characters 512 to 1023 to load into temp[] and then be stored into fileArray[1] and so on. If the file is shorter than 5 KB, fill the rest of the items in fileArray[] with 0's.
Code:
FILE* fileArray[10];
//something like for(int a = 0; a < fileArray.length; a++)
ifstream infile;
int i = 0;
int k = 0;
char temp[512];
infile.open("inputFiles/test1.txt"); //open file in read mode.. IF FILE TOO BIG, CRASHES BECAUSE OF TEMP
while (infile >> temp[i])//WHAT DOES THIS MEAN?
i++;
k = i;
for (int i = 0; i < k; i++) {
cout << temp[i]; //prints each char in test1.txt
}
New Code:
FILE* input = fopen(filename, "r");
if (input == NULL) {
fprintf(stderr, "Failed to open %s for reading OR %s is a directory which is fine\n", filename, filename);
return;
}
FILE **fileArray = (FILE**) malloc(10 * 512); //allow files up to 5.12KB (10 sectors of 512 Bytes each)
//load file into array in blocks of 512B
//if file is less than 5.12KB fill rest with 0's
std::filebuf infile;
infile.open("inputFiles/test1.txt", std::ios::in | std::ios::binary);
for (int a = 0; a < 10; a++) {
outfile.open(fileArray[a], std::ios::out | std::ios::binary);
int block = 512 * a;
int currentBlockPosition = 0;
while (currentBlockPosition < 512) {
std::copy(std::istreambuf_iterator<char>(&infile[block + currentBlockPosition]), {},
std::ostreambuf_iterator<char>(&outfile));
//input[block * currentBlockPosition] >> fileArray[a];
//currentBlockPosition++;
}
}
while (infile >> temp[i])//WHAT DOES THIS MEAN?
i++; // This is means while there exist data in the file put this data in temp array
and I think it is good idea to take the whole data from the file and then split array

read bytes of data after reading plain text pgm p5 file

I'm trying to read a .pgm version p5 file. The header is in plain text then the actual data is stored in plain bytes. The header can be an arbitrary length. I how can I start reading byte by byte after reading in the plain text line by line?
int main()
{
//Declare
int rows = 0, cols = 0, maxVal = 0;
ifstream infile("image.pgm");
string inputLine = "";
string trash = "";
//First line "P5"
getline(infile,inputLine);
//ignore lines with comments
getline(infile,trash);
while (trash[0] == '#')
{
getline(infile,trash);
}
//get the rows and cols
istringstream iss(trash);
getline(iss, inputLine, ' ');
rows = atoi(inputLine.c_str());
getline(iss, inputLine, ' ');
cols = atoi(inputLine.c_str());
//get the last plain text line maxval
getline(infile,inputLine);
maxVal = atoi(inputLine.c_str());
//Now start reading individual bites
Matrix<int, rows, cols> m;
//now comes the data
for(i = 0; i<rows; i++)
{
for(j = 0; j < cols; j++)
{
//store data into matrix
}
}
system("Pause");
return 0;
}
Use ifstream::read to read a block of binary data and copy it into a buffer. You know the size of data from the image size in the header.
If your matrix object has a method to get an address you can copy it directly, or read it into some temporary buffer and then copy that into the Matrix. Reading a byte a time is likely to be very slow.

deleting a structure from file in c++

So, here's the code of the procedure which reads every structure from file, deletes first-found structure which has an AgreementNo that is equal to the inserted int query. It then shortens the array and rewrites the file.
The problem is, it just shortens the array and deletes the last element - as if the searching criterias are not met, even though they should be.
(Before the procedure starts, the file is opened in a+b mode, so in the end, it is reopened that way.)
void deleteClient(int query, FILE *f){
int filesize = ftell(f);
int n = filesize/sizeof(Client);
Client *c = new Client[n];
Client *c2 = new Client[n-1];
rewind(f);
fread(c, sizeof(Client), n, f);
for(int i=0; i<n; i++){
if(c[i].agreementNo == query ){
c[i] = c[n];
break;
}
}
for (int i=0; i<n-1; i++){ c2[i] = c[i]; } // reduce the size of the array ( -1 extra element)
fclose(f);
remove("Client.dat");
f = fopen("Client.dat", "w+b");
for(int i=0;i<n-1; i++) {
fwrite(&c2[i], sizeof(Client), 1, f);
}
fclose(f);
f = fopen("Client.dat", "a+b");
}
What could be the cause of the described problem? Did I miss something in the code?
I'd do it this way:
struct MatchAgreementNo
{
MatchAgreementNo(int agree) : _agree(agree) {}
bool operator()(const Client& client) { return client.agreementNo == agree; }
};
void deleteClient(int query, FILE *f)
{
int rc = fseek(f, 0, SEEK_END);
assert(rc == 0);
long filesize = ftell(f);
int n = filesize / sizeof(Client);
assert(filesize % sizeof(Client) == 0);
Client *begin = mmap(NULL, filesize, PROT_READ|PROT_WRITE,
MAP_SHARED, fileno(f), 0);
assert(begin != MAP_FAILED);
Client *end = std::remove_if(begin, begin + n, MatchAgreementNo(query));
rc = ftruncate(fileno(f), (end - begin) * sizeof(Client));
assert(rc == 0);
munmap(begin, filesize);
}
That is, define a predicate function which does the query you want. Memory-map the entire file, so that you can apply STL algorithms on what is effectively an array of Clients. remove_if() takes out the element(s) that match (not only the first one), and then we truncate the file (which may be a no-op if nothing was removed).
By writing it this way, the code is a bit higher-level, more idiomatic C++, and hopefully less error-prone. It's probably faster too.
one change needed in your code is to save the index of the first found "bad" entry somewhere, and then copy your original array around that entry. Obviously, if no "bad" entry is found, then you aren't supposed to do anything.
One word of warning: the approach of reading the original file as a whole is only applicable for relatively small files. For the larger files, a better approach would be opening another (temporary) file, reading the original file in chunks and then copying it as you go (and after you found the entry which is skipped just copying the rest of the contents). I guess there is even more space for the optimization here, considering that except for that one entry, the rest of file contents is left unchanged.
void deleteClient(int query, FILE *f){
int filesize = ftell(f);
int n = filesize/sizeof(Client);
int found = -1;
Client *c = new Client[n];
Client *c2 = new Client[n-1];
rewind(f);
fread(c, sizeof(Client), n, f);
for(int i=0; i<n; i++){
if(c[i].agreementNo == query ){
printf("entry No.%d will be deleted\n", i);
found = i;
break;
}
}
if(found == -1) return;
if (i>0) for (int i=0; i<found; i++) { c2[i] = c[i]; } // copy the stuff before the deleted entry if it's >0
for (int i=found+1; i<n; i++){ c2[i-1] = c[i]; } // reduce the size of the array ( -1 extra element)
fclose(f);
remove("Client.dat");
f = fopen("Client.dat", "w+b");
for(int i=0;i<n-1; i++) {
fwrite(&c2[i], sizeof(Client), 1, f);
}
fclose(f);
f = fopen("Client.dat", "a+b");
}

Error when library receives the FILE pointer and read the file

The function read a matrix from a file, and print it on the screen. but there is something wrong when library fscanf(fp, "%u", &elem); read file from fp.
It's OK when I change uint8_t elem to uint8_t *elem .
I want to know why! What should pay attention when program transfers a FILE pointer to the library. Thx!
main function:
int main(int argc, char *argv[]){
Matrix8g mat;
FILE *fp;
if((fp = fopen("mat.dat","r")) == NULL){
printf("can't open the file");
}
//matrix with 24 rows and 11 cols
mat.Make_from_file(fp, 24, 11);
//print the matrix
mat.Print();
fclose(fp);
}
Part of library file (Make_from_file):
/* Set the matrix from a file */
int Matrix8g::Make_from_file(FILE *fp, int rows, int cols){
int i, j;
uint8_t elem;
this->rr = rows;
this->cc = cols;
Resize_matrix();
try{
for(i = 0; i < rows; i++){
for(j = 0; j < cols; j++){
fscanf(fp, "%u", &elem);
Set(i, j, elem);
}
}
}catch(...){
NOTE("Error when set the matrix from a file");
return 0;
}
return 1;
}
If you look at this reference c reference
You would see that fscanf needs a reference to the data structure to which the extracted date should be written. fscanf copies from the given file/stream to the given pointer. It has no information about what type the data has. It uses the format string to interpret the byte from the input. Its similar to a type casting. fscanf can't know which type is needed as target structure but a pointer allows a straight copy operation.