Jump to content

Recommended Posts

Posted

Dear all:),

Is it possible to read/write a binary file from Visual LISP:?:?

Posted (edited)

You could use the methods associated with the FileSystemObject as demonstrated by these courtesy of MP:

 

http://www.theswamp.org/index.php?topic=17465.0

 

Or you could use the ADO Stream object:

 

;;-----------------=={ Read Binary Stream }==-----------------;;
;;                                                            ;;
;;  Uses the ADO Stream Object to read a supplied file and    ;;
;;  returns a variant of bytes.                               ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  filename - filename of file to read.                      ;;
;;  len      - number of bytes to read                        ;;
;;  (if non-numerical, less than 1, or greater than the size  ;;
;;   of the file, everything is returned).                    ;;
;;------------------------------------------------------------;;
;;  Returns:                                                  ;;
;;  Variant of Binary data which may be converted to a list   ;;
;;  bytes using the relevant VL Variant functions or used     ;;
;;  with LM:WriteBinaryStream.                                ;;
;;------------------------------------------------------------;;

(defun LM:ReadBinaryStream ( filename len / ADOStream result ) (vl-load-com)
 
 (setq result
   (vl-catch-all-apply
     (function
       (lambda ( / size )
         (setq ADOStream (vlax-create-object "ADODB.Stream"))
         (vlax-invoke ADOStream 'Open)
         (vlax-put-property   ADOStream 'type 1)
         (vlax-invoke-method  ADOStream 'loadfromfile filename)
         (vlax-put-property   ADOStream 'position 0)
         (setq size (vlax-get ADOStream 'size))
         (vlax-invoke-method  ADOStream 'read (if (and (numberp len) (< 0 len size)) (fix len) -1))
       )
     )
   )
 )
 (if ADOStream (vlax-release-object ADOStream))

 (if (not (vl-catch-all-error-p result))
   result
 )
)

;;-----------------=={ Write Binary Stream }==----------------;;
;;                                                            ;;
;;  Uses the ADO Stream Object to write a variant of bytes to ;;
;;  a specified file. File is created if non-existent or      ;;
;;  overwritten if found.                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  filename - filename of file to read.                      ;;
;;  data     - variant of binary data to write to the file.   ;;
;;             (as returned by LM:ReadBinaryStream)           ;;
;;------------------------------------------------------------;;
;;  Returns:  Filename of specified file, else nil.           ;;
;;------------------------------------------------------------;;

(defun LM:WriteBinaryStream ( filename data / ADOStream result ) (vl-load-com)
 
 (setq result
   (vl-catch-all-apply
     (function
       (lambda ( )
         (setq ADOStream (vlax-create-object "ADODB.Stream"))
         (vlax-put-property ADOStream 'type 1)
         (vlax-invoke ADOStream 'open)
         (vlax-invoke-method ADOStream 'write data)
         (vlax-invoke ADOStream 'savetofile filename 2)
       )
     )
   )
 )
 (if ADOStream (vlax-release-object ADOStream))

 (if (not (vl-catch-all-error-p result))
   file
 )
)

Edited by Lee Mac
  • 14 years later...
Posted

Hi,

 

so I'm using ZWCAD and it has a file called 'AppAutoLoad.app' which stores all script files paths from Startup Suite. If I paste new path in it it works fine, accepts it and loads it upon next running of CAD software but it seams to be a binary file because when I write to it using write-line command some weird characters are written. I tried writing content to it using LISP scripts provided here by Lee Mac and it work fine when using both functions together, the content is read as a variant and that variant has been written back like this:

(LM:WriteBinaryStream (findfile "../AppAutoLoad.app") (LM:ReadBinaryStream (findfile "../AppAutoLoad.app") nil))

 

So that worked fine in ZWCAD, but when I tried constructing variant object on my own it won't work, I tried looking on multiple forums, reading docs I could find about it, but I can't make it work, this is the function I made for appending new content to the file:

(defun MM:AppendToBinaryFile ( path text / fileData )
	(setq text (mapcar 'ascii (MM:strToLst text)) ; Converting text to list of corresponding ASCII values
		  fileData (vlax-variant-value (LM:ReadBinaryStream path nil))) ; Reading variant value of the existing file data

	(if fileData ; Check if there is any existing data
		(setq fileData (reverse (vlax-safearray->list fileData))) ; Convering data to list of ASCII values and reversing it for appending new values
	)

	(foreach letter text
		(setq fileData (cons letter fileData)) ; Adding every new character to the existing data
	)
	
	(setq fileData (reverse fileData) ; Reversing values to restore proper order
		  vlax-vbByte 17 ; Setting value for non-existing variant type
		  byte-array (vlax-make-safearray vlax-vbByte (cons 0 (1- (length fileData))))) ; Creating empty safearray of appropriate size

	(vlax-safearray-fill byte-array fileData) ; Filling safearray with full data (old + new)

	(setq fileData (vlax-make-variant byte-array (+ vlax-vbArray vlax-vbByte))) ; Creating variant object

	(LM:WriteBinaryStream path fileData) ; Writting data back to file

	(princ)
)

 

Also MM:strToLst is just a function that splits string into list of characters, I'll post it if someone needs it for testing:

(defun MM:strToLst ( str / )
	(if (> (strlen str) 0)
		(cons (substr str 1 1) (MM:strToLst (substr str 2)))
		nil
	)
)

 

Can anyone help on this topic or point on some error in my code? I did some testing and final safearray seems to keeps containing zeroes only even after filling it but I don't know why is that, I tried to fix it somehow but without success.

I am also sending the file I am working with. After reading the content, vlax-variant-type command gives me code 8209.

AppAutoLoad.app

Posted

Rather then reading the file and then writing it back with new data added just open the file in append mode. aka add the data you want at the end.

 

;; Example usage:
;; (MH:AppendText "C:/path/to/your/file.txt" "This is a new line of text")

(defun MH:AppendText (filename text / file)
  (vl-load-com)
  (setq file (open filename "A")) 'open file in append
  (if file
    (progn
      (write-line text file)
      (close file)
      (princ (strcat "\nText appended to " filename))
    )
    (princ (strcat "\nError: Could not open " filename))
  )
  (princ)
)

 

also ZWCAD might now be able to use some of the Visualisp commands like vlax- and vl-

  • Thanks 1
Posted
12 hours ago, mhupp said:

Rather then reading the file and then writing it back with new data added just open the file in append mode.

Thanks for advice, I tried that already but no success, it seams like is not possible to write to binary files using standard write-line command. That's why I went from this solution from Lee Mac which is using ADO Stream object and it works fine when reading with LM:ReadBinaryStream and then writing the result of that function (whic is vlax-variant) back to the file using LM:WriteBinaryStream, but when I try creating my own vlax-variant object and write it back to the file it doesn't go as expected.

 

12 hours ago, mhupp said:

also ZWCAD might now be able to use some of the Visualisp commands like vlax- and vl-

Yes. it does, I'm using them in my code, but problem occurs while building vlax-variant object which is needed for writing data back to the file, somehow only zeroes are written and I can't figure out why.

Posted

FWIW, you can change this:

(mapcar 'ascii (MM:strToLst text))

 

To:

(vl-string->list text)

 

An untested suggestion: where the variant is concerned, rather than using hardcoded variant & safearray datatypes, try querying the types of the original variant & safearray using:

vlax-variant-type
vlax-safearray-type

 

 

  • Like 1
Posted
2 hours ago, Lee Mac said:

FWIW, you can change this:

(mapcar 'ascii (MM:strToLst text))

 

To:

(vl-string->list text)

Thanks for this, learned something new, much cleaner and easier.

 

2 hours ago, Lee Mac said:

An untested suggestion: where the variant is concerned, rather than using hardcoded variant & safearray datatypes, try querying the types of the original variant & safearray using:

vlax-variant-type
vlax-safearray-type

I tried your suggestion, but didn't work, I also did some more testing and the reading of the data is done properly, the appending of the new content is done properly, and then I think the problem occurs when creating safearray using value 17 or in other words using VisualLisp variant data type vlax-vbByte, which is unsupported according to this post.

So the value that has been returned from vlax-variant-type performed on result of reading with (LM:ReadBinaryStream (findfile "../AppAutoLoad.app") nil) is 8209 which is value of vlax-vbArray(8192) combined with vlax-vbByte(17), but since the vlax-vbByte data type seems to be unsupported I guess that I can't recreate the variant of the same type (8209) anymore?

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...