Solved

How to read a binary file and write a text file with that data?

Posted on 2006-06-28
12
1,295 Views
Last Modified: 2013-11-15
Hi,
I have a binary file with uint32 values. i need to read those,convert them to scaled floating point (3 places) and write to a text file. For example:

00 01 23 4F 00 01 24 4D...

is 2 values: 001234F (74575 int) and 0012244D (74829 int), each of 4 bytes and the whole file contains such values. I need to scale these in such a way:

(74575 - 65000)/22500

which is: 0.423

and write them to a file as csv values.Can someone tell me how to do that

Thanks!


0
Comment
Question by:rt2001
  • 3
  • 3
  • 3
  • +2
12 Comments
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 17007209
1. Open the input file in binary mode.
2. read the integers
3. convert them to float.
4. Open another file in text mode.
5. write the value.

That's it
0
 
LVL 12

Accepted Solution

by:
rajeev_devin earned 150 total points
ID: 17007231
Something like this


unsigned int val = 0;
float result = 0.0;

FILE *input = fopen("input.dat", "rb"); // b is for binary
FILE *output = fopen("output.dat", "w");

for (int i = 0; i < 2; ++i) {

      fread(&val, sizeof(unsigned int), 1, input);
      result = (float)(val - 65000)/22500;

      fprintf(output, "%f\n", result);
}

fclose(input);
fclose(output);
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 17007243
Another thing that I want to tell you is that
binary data 00 01 23 4F will not be 74575 in decimal if you are doing the thing in little-endian machine.

It will be
4F 23 01 00
0
 
LVL 12

Assisted Solution

by:stefan73
stefan73 earned 100 total points
ID: 17008617
two things:

Use "%.3f" format string, or rather

for (int i = 0; i < 2; ++i) {
     [...]

     fprintf(output, "%.3f\n", result);
}

You also may want to use doubles instead of floats. When you use floats, you save nothing, as when the printf() family is called with a float parameter, it's automatically converted to double.
0
 
LVL 18

Assisted Solution

by:JoseParrot
JoseParrot earned 150 total points
ID: 17015633
Hi,

Seems numbers are actually 0001234F (74575 int) and 0001244D (74829 int).

main()
{
  unsigned char a,b,c,d;
  unsigned long n1, n2;
  float f1,f2;
  FILE *F;

  F=fopen("MyNumbers.bin","rb");                        // read file
  a=fgetc(F); b=fgetc(F); c=fgetc(F); d=fgetc(F);  // get bytes 1st number
  n1=a;                                                             // compute integer value
  n1=(n1<<8)+b;                                               // shift left 8 times
  n1=(n1<<8)+c;
  n1=(n1<<8)+d;
  f1 = ((float)n1-(float)65000)/(float)22500;         // apply the formula
  printf("\n%6.3f",f1);                                         // just to check
  a=fgetc(F); b=fgetc(F); c=fgetc(F); d=fgetc(F); // get bytes 2nd gyte
  n2=a;
  n2=(n2<<8)+b;
  n2=(n2<<8)+c;
  n2=(n2<<8)+d;
  f2 = ((float)n2-(float)65000)/(float)22500;
  printf("\n%6.3f",f2);
  fclose(F);

  F=fopen("MyNumbers.csv","wt");
  fprintf(F,"%8.3f,%8.3f",f1,f2);                          // write csv
  fclose(F);
}

Hope it helps.

Jose
0
 
LVL 5

Assisted Solution

by:bastibartel
bastibartel earned 100 total points
ID: 17016771
Hi there,

You need to consider the following.
The binary representation (in memory) or as in your case in the file depends of the implementation of the program generating theses numbers.
Knowing that it is 4 bytes per value helps but is not enough.

There are several integer types within a single implementation already, let alone across different programming environments
The only way to find out what integer type suits your binary data is to try and find it empirically.
(your compiler's documentation will help you find the 4-byte integer types, but you may as well try them all)


So try the following and compare the resulting numbers to your expecations (either well known file or plausibility)
(I have copyied rajeev_devin's code - Thanks)

//** try any of these alternative integer types
// typedef int t_MyInt;
// typedef unsigned int t_MyInt;
// typedef long  t_MyInt;
// typedef _int32 t_MyInt;

t_MyInt val = 0;
float result = 0.0;

FILE *input = fopen("input.dat", "rb"); // b is for binary
FILE *output = fopen("output.dat", "w");

for (int i = 0; i < 2; ++i) {

     fread(&val, sizeof(t_MyInt), 1, input);
     result = (float)(val - 65000)/22500;

     fprintf(output, "%f\n", result);
}

fclose(input);
fclose(output);


Cheers Sebastian
0
Comprehensive Backup Solutions for Microsoft

Acronis protects the complete Microsoft technology stack: Windows Server, Windows PC, laptop and Surface data; Microsoft business applications; Microsoft Hyper-V; Azure VMs; Microsoft Windows Server 2016; Microsoft Exchange 2016 and SQL Server 2016.

 
LVL 18

Expert Comment

by:JoseParrot
ID: 17020114
Hi,
Clearly the input file is binary big endian and output file is ASCII csv.

So, the data cannot be read with any C or C++ reading command as fread, as Windows expect it to be little-endian.
Despite the interesting strategy of bastibartel, that code doesn't work properly in a little-endian machine like the ones with Pentium CPU.

That's why we should read the file byte by byte ...
     a=fgetc(F); b=fgetc(F); c=fgetc(F); d=fgetc(F);

... and "construct" the number ...
     n1=a;                        // compute integer value
     n1=(n1<<8)+b;          // shift left 8 times is the same of multiply by 256
     n1=(n1<<8)+c;
     n1=(n1<<8)+d;          // at this point, n1 is the number

... for the math operation ...
    f1 = ((float)n1-(float)65000)/(float)22500;   // f2 calculated same way

... and save the numbers with 3 decimal places, coma separated:
    fprintf(F,"%8.3f,%8.3f",f1,f2);

Jose
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 17020791
... And how is that so 'clear' I wonder curiously ?

Cheers,
Sebastian
0
 
LVL 18

Expert Comment

by:JoseParrot
ID: 17022177
Hi, Sebastian,
For me it's clear by this simple reason:

   The author describes the input data as  "00 01 23 4F 00 01 24 4D...", "and the whole file contains such values".
   If the bytes are in such sequence, then this is big-endian (BE for short).

Also, the code provided by rajeev_devin with the corrections by stephan73 is good enough and the question would PAQ, if the numbers would little-endian (LE for short).

We can, in this point, be confuse... actually the CPU (in case of Windows + Pentium) is LE. The file (as decribed by the author) is BE. So, I suggest to read the BE data, turn it LE, then call the C math.

Please note I didn't affirm that your code is bad and will not run in a LE CPU. My point is that fread waits for a LE number and what the file has is BE number.

About your code, a minor adjust I could suggest is that only "typedef unsigned int t_MyInt;"  complys to the author's initial declaration "I have a binary file with uint32 values". But, despite that, I like that strategy and find it pretty creative.

Jose

   
0
 

Author Comment

by:rt2001
ID: 17024590
Hi,
Many thanks for all your answers and the differerent prespectives. I found them all immensely helpful. The endianness was an issue and I solved by using a combination of Jose's and Rajeev's answers. I tried to use all the suggestions to write this code of mine.It works well except that float values that are negative are not showing up properly. How does float take care of negative values? any other suggestions are appreciated.Thanks.
-Tanuj.


void main()
{
typedef unsigned int t_uint32;
typedef unsigned char t_uint8;

t_uint32 val = 0;
t_uint8 byte=0;
float result = 0.0;

FILE *file1_in = fopen("file1_in.bin", "rb"); // b is for binary
FILE *file1_out = fopen("file1_out.csv", "wt");

while(!feof(file1_in)){
for (int i = 0; i < 4; ++i) {
     fread(&byte, sizeof(t_uint8), 1, file1_in);
       val=(val<<8) + byte;
 }
     result = (float)(val - 75000)/22500;
     fprintf(file1_out, "%f\n", result);
    val=0;
}
fclose(file1_in);
fclose(file1_out);
}
0
 

Author Comment

by:rt2001
ID: 17024606
Ok,silly question, just casting val to float does it. Anyways ,thanks guys!

Rgds,
Tanuj.
0
 
LVL 5

Expert Comment

by:bastibartel
ID: 17029844
Hello Jose,

I really did not know how to tell LE from BE - so thanks for the clarification. And I never took your comment as criticism :-)
It is always interesting to see though how various answers to the same problem co-exist on totally different abstraction levels.

You are of course right about the Uint issue - that had escaped my attention. (plus, I wanted to give a slightly bigger picture ;-))

Cheers Sebastian
0

Featured Post

Ransomware-A Revenue Bonanza for Service Providers

Ransomware – malware that gets on your customers’ computers, encrypts their data, and extorts a hefty ransom for the decryption keys – is a surging new threat.  The purpose of this eBook is to educate the reader about ransomware attacks.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Software - Posting same reply on multiple forums. 4 71
Check version 13 68
Ransomware attacks 5 84
Software to compare two files and flag if they are different 2 45
I previously wrote an article addressing the use of UBCD4WIN and SARDU. All are great, but I have always been an advocate of SARDU. Recently it was suggested that I go back and take a look at Easy2Boot in comparison.
A high-level exploration of how our ever-increasing access to information has changed the way we do our jobs.
The viewer will learn how to successfully create a multiboot device using the SARDU utility on Windows 7. Start the SARDU utility: Change the image directory to wherever you store your ISOs, this will prevent you from having 2 copies of an ISO wit…
The viewer will learn how to successfully download and install the SARDU utility on Windows 8, without downloading adware.

911 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now