Ahankhah Posted March 2, 2011 Posted March 2, 2011 Dear all:), Is it possible to read/write a binary file from Visual LISP:? Quote
Lee Mac Posted March 2, 2011 Posted March 2, 2011 (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 March 2, 2011 by Lee Mac Quote
Fidelojo Posted yesterday at 12:32 PM Posted yesterday at 12:32 PM 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 Quote
mhupp Posted 19 hours ago Posted 19 hours ago 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- 1 Quote
Fidelojo Posted 6 hours ago Posted 6 hours ago 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. Quote
Lee Mac Posted 5 hours ago Posted 5 hours ago 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 1 Quote
Fidelojo Posted 2 hours ago Posted 2 hours ago 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? Quote
Recommended Posts
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.