Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Read & write Binary File 1

Status
Not open for further replies.

gsrajput

Programmer
Jan 10, 2002
25
US
I opened the file with fopen and have record layout but to convert the buffer into integers need help.

Thanks much
 
There are many types of 'integers' in binary files - 1, 2, 3, 4, 6 and 8 bytes (signed and unsigned), and in 'big-endian' and 'little-endian' format. Some times these integers are also stored packed decimal format. Can you provide a couple of samples of the hex codes and what they should evaluate to?

Rick
 
** open Binary File
lnFileHandle = Fopen("ABC.DAT",12)
** Then I try to read the first ten bytes of the file
luBuffer = Fread(lnFileHandle,10)

and this is the value I got in buffer
luBuffer = "ÚG+2lD"

now I would like to see this value in Ascii that what it is.

Thanks RgBean for prompt attention.
 
Do you mean you to show each character in Ascii ?
If that's what you mean you can use this:
Code:
Function DisplayAscii(tcChar)
    Return asc(tcChar)
EndFunc
Use it with:

Code:
?DisplayAscii(substr(luBuffer, 1, 1))
?DisplayAscii(substr(luBuffer, 2, 1))

Regards
 
gsrajput:

If the file is straight 8 bit integers(1 byte), the contents would be:
218, 71, 15, 3, 43, 50, 15, 3, 108, 68 without the commas or spaces included.

So, as infered by RgBean, you'll need to know what the file structure is before it will make sense.

By the way, here's the code I used to output the string above:

lcInp = "ÚG+2lD"
lcOut = ""
FOR i = 1 TO LEN(lcInp)
lcOut = lcOut + ALLT(STR(ASC(SUBSTR(lcInp,i,1))))+IIF(i<> LEN(lcInp),&quot;, &quot;,&quot;&quot;)
NEXT
_CLIPTEXT = lcOut

Darrell

'We all must do the hard bits so when we get bit we know where to bite' :)
 
No this is not what I want. I know there could be some value of this buffer e.g. 00124567890 or there could be some character data or could 've some different data types.

I would like to see that kind of value which is more readable.

Thanks much

Gurvinder.
 
Darrell,
Thanks much.

Actually I 'va the record layout and length of each record but previously this program was written in Clipper and the command it was using BIN2L() but as I 've to convert this to foxpro so I could n't find anything like that.
*** BIN2L()
To convert a character string formatted as a 32-bit signed long integer to a Clipper numeric value.
 
I don't know how BIN2L convert the data, but 32bit signed long integer is type of DWORD.

So if my guess is right maybe this is what you need
Code:
Function Buff2Num
LParameters tcBuffer, tnBytes

Local lnCurByte, lnRetVal as Integer
   If (pcount() < 2)
      If (len(tcBuffer) > 8)
         Wait 'Max Buffer to pass is 8 character' window nowait
         Return
      else
         tnBytes = len(tcBuffer)
      endif
   else
      If (vartype(tnBytes) != 'N')
         If (len(tcBuffer) > 8)
            Wait 'Max Buffer to pass is 8 character' window nowait
            Return
         else
            tnBytes = len(tcBuffer)
         endif
      endif
   endif

   lnRetVal = 0
   For lnCurByte = 1 to tnBytes 
      lnRetVal = lnRetVal + ;
        asc(substr(tcBuffer, lnCurByte, 1)) * ;
        (256^(lnCurByte-1))
   next
   Return int(lnRetVal)
EndFunc
And use it with:
Code:
** convert &quot;WORD&quot; type
?Buff2Num(substr(lpBuffer,1,2))
** convert &quot;DWORD&quot; type
?Buff2Num(substr(lpBuffer,1,4))
** convert &quot;QWORD&quot; type
?Buff2Num(substr(lpBuffer,1,8))

Regards
 
Gurvinder,
If AirCon's routine doesn't give you what you need, please let us know.
As one of my old Computer Science Professors said: &quot;Bits is Bits&quot;. While there are different ways to interpret bits, the actual values don't change.
Two routines I use (when I can't use my trusty WinHex utility) are shown below.
Code:
?showhex(&quot;ÚG+2lD&quot;) && returns - &quot;DA470F032B320F036C44&quot;
?showascii(&quot;ÚG+2lD&quot;) && returns - 
* 218,  71,  15,   3,  43,  50,  15,   3, 108,  68
Rick
Code:
* Program....: SHOWHEX.PRG
lparameters p_cBin
local lcString

lcString = &quot;&quot;
FOR lnii = 1 to len(p_cBin)
   lnByte = asc(substr(p_cBin, lnii, 1))
   lcHex = right(transform(lnByte,&quot;@0x&quot;),2)
   lcString = lcString + lcHex
ENDFOR &&* lnii = 1 to len(p_cBin)

RETURN lcString
*!* EOP: SHOWHEX.PRG

* Program....: SHOWASCII.PRG
lparameters p_cBin
local lcString

lcString = &quot;&quot;
FOR lnii = 1 to len(p_cBin)
   lcByte = str(asc(substr(p_cBin, lnii, 1)), 3)+&quot;, &quot;
   lcString = lcString + lcByte
ENDFOR &&* lnii = 1 to len(p_cBin)

RETURN left(lcString, len(lcString)-2)
*!* EOP: SHOWASCII.PRG
 
Rick,
Thank you very much for the Code. I hope this would help me a lot. I 'll let you know if this or Aircon's routine worked.
I 'm still working on to that project.
Gurvinder.
 
Dear Aircon,
It was a 32bit signed integer and your code worked fine to convert that. I appreciate all of your help and Tek-Tips sight. Thanks to Rick also.

Gurvinder



[2thumbsup]
 
Gurvinder, AirCon,
Just a quick note - that routine is for UNsigned numbers.
?Buff2Num(chr(255)+chr(255)+chr(255)+chr(255))
should give -1, and it gives 4294967295 - the unsigned version.

It wouldn't take but another parameter and a check on the high order bit of the last character to implement this Signed/Unsigned variant.

Rick
 
Rick,
Thanks for the tip. I just need to ask you or Aircon about the reverse step of this because when I need to right this value back to the file the I need to convert value of Integer to Binary again.

Thanks again.

Regards,

Gurvinder.
 
Rick
You right. It is an unsigned DWORD. Since VFP cannot check whether the value is sign/unsign, we have to use another logic for that.
i.e.: BitTest the first bit, etc..

Gurvinder
This is the reverse code and remember this is also unsigned, so you need to workaround a bit to make it signed.
Code:
Procedure Num2DWord(tn_Num)
Local c0, c1, c2, c3
   c3 = chr(int(tn_Num / 16777216))
   tn_Num = mod(tn_Num, 16777216)

   c2 = chr(int(tn_Num / 65536))
   tn_Num = mod(tn_Num, 65536)

   c1 = chr(int(tn_Num / 256))
   c0 = chr(mod(tn_Num, 256))

   Return c0 + c1 + c2 + c3
EndProc

Regards

-- AirCon --
 
Dear Aircon,
Thanks much. Is this going to work for both short and Long Integers?


Regards,

Gurvinder
 
Yes it does. For short you just need to use &quot;c0&quot; & &quot;c1&quot;, and eliminate the &quot;c2&quot; & &quot;c3&quot;

Regards

-- AirCon --
 
Gurvinder,
Well I finally found a Signed integer variant. I wrote it a long time ago, and it only works with 1, 2, 3, and 4 byte strings, but it would be easy to expand (as the comment says!). It's not &quot;optimized&quot;, but it's easy to see what's going on, and doesn't use any new VFP features - I think I originally wrote it for a FPD/W app.
Code:
* Program....: ASC2SBEINT.PRG
* Abstract...: Ascii String to Signed BigEndian Integer (i.e. Most significant byte on right)
*              Handles 1 to 4 byte strings (could be easily be expanded)
*
*               RETURN 0 if any error
*
* Example....: ? ASC2SBEINT(chr(255)+chr(255)+chr(255)+chr(255), 4, .T.)
*               prints  -1
*
* Changes....:

*FUNCTION asc2SBEint

LPARAMETERS p_cString, p_nLength, p_lSigned

IF PCOUNT() < 1 OR TYPE(&quot;p_cString&quot;) <> &quot;C&quot;
   RETURN 0
ENDIF

IF PCOUNT() < 2 OR TYPE(&quot;p_nLength&quot;) <> &quot;N&quot;
   p_nLength = LEN(p_cString)
ENDIF
IF PCOUNT() < 3 OR TYPE(&quot;p_lSigned&quot;) <> &quot;L&quot;
   p_lSigned = .F.
ENDIF

IF   p_nLength > LEN(p_cString)
   p_cString = PADR(p_cString, p_nLength, CHR(00))
ENDIF

LOCAL lnRet_val

DO CASE
CASE p_nLength = 1
   lnRet_val = int(asc(SUBSTR(p_cString, 1, 1)))
   IF p_lSigned and lnRet_val >= 256/2
      lnRet_val = -(256-lnRet_val)
   ENDIF
   
CASE p_nLength = 2
   lnRet_val = int(asc(SUBSTR(p_cString, 1, 1));
            + asc(SUBSTR(p_cString, 2, 1))*256)
   IF p_lSigned and lnRet_val >= 256^2/2
      lnRet_val = -(256^2-lnRet_val)
   ENDIF

CASE p_nLength = 3
   lnRet_val = int(asc(SUBSTR(p_cString, 1, 1));
            + asc(SUBSTR(p_cString, 2, 1))*256;
            + asc(SUBSTR(p_cString, 3, 1))*256^2)
   IF p_lSigned and lnRet_val >= 256^3/2
      lnRet_val = -(256^3-lnRet_val)
   ENDIF

CASE p_nLength = 4
   lnRet_val = int(asc(SUBSTR(p_cString, 1, 1));
            + asc(SUBSTR(p_cString, 2, 1))*256;
            + asc(SUBSTR(p_cString, 3, 1))*256^2;
            + asc(SUBSTR(p_cString, 4, 1))*256^3)
   IF p_lSigned and lnRet_val >= 256^4/2
      lnRet_val = -(256^4-lnRet_val)
   ENDIF
            
OTHERWISE
   lnRet_val = 0
ENDCASE

RETURN INT(lnRet_val)

*!* EOP: ASC2SBEINT.PRG
Note: For pre-VFP, you need to change LPARAMETERS to PARAMETERS and LOCAL to PRIVATE, and shorten the filename to 8 characters - e.g. A2SBEINT.PRG

I haven't found the opposite conversion - I must not have needed it, but if you find you need the signed routine, it'd be easy to write a variant of AirCon's routine.

Rick
 
Rick,
Thanks for the additional code as I'm going to add all in my library and now it is much more clear now. You and Aircon been such a great help for me and I appreciate that. Well now everything is working fine then I noticed Foxpro's FOPEN() does n't support shared files. Do you guys have any substitute for that? I 've not tried yet but I think Windows API might help that.

Thansk again.

Gurvinder.
 
Yes a few API can do it. But I think you should start a new thread for this ;-)

Anyway I give you a hint. CreateFile, ReadFile, WriteFile and CloseHandle is the API you need. Try to search from
Good luck!

-- AirCon --
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top