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 Wednesday at 12:32 PM Posted Wednesday 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 Wednesday at 06:15 PM Posted Wednesday at 06:15 PM 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 yesterday at 06:32 AM Posted yesterday at 06:32 AM 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 yesterday at 07:50 AM Posted yesterday at 07:50 AM 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 yesterday at 10:18 AM Posted yesterday at 10:18 AM 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? 1 Quote
BIGAL Posted yesterday at 11:21 PM Posted yesterday at 11:21 PM I looked at the file and its plain ascii text, are you sure need to write a binary file ? I used to have DEBUG so could look at a file and see if its plain text or binary. Can you post a file that has more than one line please. Just a comment in Acad and Bricscad the start up suite is contained in the registry. 1 Quote
Fidelojo Posted 17 hours ago Posted 17 hours ago 6 hours ago, BIGAL said: I looked at the file and its plain ascii text, are you sure need to write a binary file ? I used to have DEBUG so could look at a file and see if its plain text or binary. So when I open the file it's readable but when I try to write to it using write-line command the characters are displayed in a file as some unknown symbols, so I can't claim for sure that it's a binary file but it's only reason that comes to my mind that can cause such behavior, in addition those functions for reading and writing binary by Lee worked on a file flawless in combo. But yeah, I can't tell for sure it's a binary file, but it's my assumption. 6 hours ago, BIGAL said: Can you post a file that has more than one line please. Sure, provided below. 6 hours ago, BIGAL said: Just a comment in Acad and Bricscad the start up suite is contained in the registry. Thanks for info, I know that because I have Acad at home so I looked into it but on work I searched through whole ZWCAD registry and there's nothing in there, but on the other side I didn't found AppAutoLoad.app file anywhere among Acad files, so I guess ZWCAD put it in a file instead of registry (not sure why but that's how it is). AppAutoLoad.app Quote
Lee Mac Posted 43 minutes ago Posted 43 minutes ago The file is not a binary file, it is just a plain text file using UTF-16 big endian encoding (most text files are ANSI). To read/write it, you cannot use open/read-line/write-line on AutoCAD, as these do not support Unicode double-byte encoding. Instead, you can use the ADO Stream object - here are some existing examples from VovKa: https://www.theswamp.org/index.php?topic=39617.0 Quote
BIGAL Posted 2 minutes ago Posted 2 minutes ago Like Lee inside Notepad++ is the correct encoding and it is detected which is why I could read. 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.