Files |
![]() |
A computer's memory cannot hold information when the power is turned off. Thus, information to be saved must be stored in a file on disk. Advanced AutoLISP programs often need to save information between sessions, or access stores of information. This requires the ability to work with files.
AutoLISP has functions which can find, read, and create files. Generally, these files will be "plain ASCII text files," the same sort of files created with an editor like Windows NotePad.
Files and memory buffers
When AutoLISP creates a file, two things are accomplished. First, an empty file is created on disk and given a name determined by the user, or, in some cases, by the program. Second, a buffer is created in memory for temporary storage of information until it is sent to the file on disk.
It would be inefficient to write every little piece of information directly to disk because it takes much longer to write information to disk than to memory. So, as each piece of information is generated by the program, it is sent to the buffer. When the buffer becomes full, its contents are flushed to disk automatically by the operating system. If the program finishes generating information and sending it to the buffer and the buffer is only partly full, the operating system flushes the buffer's contents to disk only if the program tells it to do so.
The situation is somewhat similar when AutoLISP needs to read information from a file. It would be inefficient to read every piece of information directly from disk. So, instead, a whole section of information is read from the file and placed in a buffer so the program can read individual pieces of information quickly from the buffer. When additional information is needed from the file, the next section is automatically read into the buffer by the operating system, replacing the first section.
So AutoLISP does not write to, or read from, the disk directly. Rather, it writes to, and reads from, the buffer. The operating system takes care of flushing the buffer to disk and refilling the buffer from disk.
The three step procedure
Using files always involves these three programming steps:
Here is a very simple example which opens a file by the name of FILE1.TXT, then write the phrase "Line one" to the buffer, then closes the file (which actually places the information in the file on disk).
(setq fw (open "FILE1.TXT" "w"))
(write-line "Line one" fw)
(close fw)
The open function has a file name as its first argument, and a single
lower case letter as its second argument:
- "w" to open the file for writing
- "a" to open the file for appending (places new information
at the end of the file)
- "r" to open the file for reading
The open function returns the memory location of the buffer, which
in the above example is stored in variable fw.
The phrase "Line one" is written to the buffer by the write-line function, and is placed on disk when the buffer is closed by the close function.
If you get a directory listing after executing the first line, you would see that a new file has been created with the name FILE1.TXT, but it is empty. If you get a directory listing after the second line, the file is still empty.
When you open a file for reading, the information that is placed in the buffer is not removed from the file. In fact, the information in a file that is opened for reading is not altered in any way.
Various situations can be encountered when opening a file for writing or appending. For example, if you open a file for writing, but a file by that name already exists, that existing file will be destroyed because it will be overwritten by the new information going into the new file. Or, suppose you open a file for appending, but that file does not exist. Then the file is opened and the information is placed at the beginning of the file, just as though you had opened it for writing.
Practice session
The following exercise can be done best if you have two windows open at the same time: an AutoCAD window and a DOS window. In the DOS window you should change to the folder that AutoCAD uses by default. (That is, if you right click on your AutoCAD shortcut, select Properties, and select the Shortcut tab, this folder is identified as the "Start in" folder.) This exercise will be easiest if this default folder is empty, which may require that you create a new folder and temporarily establish it as your default AutoCAD folder.
If you are not comfortable using the DOS commands suggested below, you can substitute the following Windows procedures: In place of the DOS DIR command, use the Windows Explorer to get file listings. To view the exact size of the file, right click the file and selecting properties. In place of the DOS TYPE command, double click the file and open it with Notepad.
The findfile and getfiled functions
You should look up both the findfile
function and the getfiled
function in the "15 - Files" in the "Catalog of function definitions."
The findfile function is illustrated below in the sample program called
balloon2 (section 15, added line 4). The getfiled function is illustrated
below in the sample program called read (section 20, first line).
Sample program 1, write
This program creates a file containing any number of lines. The while loop (section 20) allows the user to enter any number of lines. Every time the user enters a line, it is written to the file (buffer). When the user finally hits 'Enter' to quit entering lines, the getstring functions returns a null string (""), which causes the test in the while loop to fail.
The byte counting algorithm in the while loop adds an extra two bytes each time a line is written to file. This is done to account for the two extra characters (ascii 10 and 13) which DOS places at the end of each line.
------ marker ------ beginning of working program ------ try it out ------
;| WRITE
Copyright © 1988,1998 Ronald W. Leigh
Input: File name and several lines
Output: Creates file and places lines in it
Variables:
bytes Number of bytes in file
fname File name
fw File pointer, file opened for writing
lin Text line
lnum Line number
vvv Temporary value in foreach loop
|;
;10====PROGRAM, GET FILE NAME, OPEN FILE
(defun c:write (/ bytes fname fw lin lnum vvv)
(setq fname (getstring "\nFile name: "))
(setq fw (open fname "w"))
;20====GET LINES, SEND TO FILE
(setq lnum 1 bytes 0)
(while (/= "" (setq lin (getstring 1
(strcat "\nLine " (itoa lnum) "
for file ('Enter' to quit): "))))
(write-line lin fw)
(setq lnum (1+ lnum))
(setq bytes (+ bytes (strlen lin) 2)))
(close fw)
;30====REPORT
(foreach vvv
(list "\n(File contains " (1- lnum) " lines, " bytes " bytes.")
(princ vvv))
(princ)
)
-------- marker -------- end of working program -------- try it out --------
Sample program 2, read
This program reads a text file with any number of lines, placing the lines in a list. The lines can then be displayed on the text screen or placed in the drawing. This program illustrates opening a file for reading (see section 20, third line).
Since the getfiled function is used (section 20, first line), it is unlikely that the user could select a file that did not exist since the dialog box displays a message in such a case, then returns to the dialog box. However, it could easily happen that the user would hit 'Escape', which causes the getfiled function to return nil. This makes the rest of the program meaningless, so the variable fname is used as a flag for the rest of section 20 as well as for sections 30 and 40. Because each of these sections begins with an if statement using fname is the test, the remainder of the if statement (which extends to the end of the section) will not execute unless fname is non-nil. (By the way, the quit and exit functions are often used to accomplish the same thing. However, they trigger an error and thus work best if an error routine is in place, so they are not used here.)
------ marker ------ beginning of working program ------ try it out ------
;| READ
Copyright © 1988,1998 Ronald W. Leigh
Input: Name of file
Output: Displays file on text screen or places
in drawing
Variables:
ans Answer to yes-no options
cnt Count
fname File name
fr File pointer, opened for reading
lin Line of text
llist Line list
lspac Line spacing
obm Old blipmode
oom Old osnap mode
sp Start point of text
temp Temporary value in request for line spacing
thei Text height
ts Current text style
tshei Text style height
vvv Temporary value in foreach
function
|;
;10====PROGRAM, SETUP
(defun c:read (/ ans cnt fname fr lin llist lspac
obm oom sp temp thei ts tshei vvv)
(setq pi 3.1415926535897932385)
(setq obm (getvar "blipmode") oom (getvar "osmode"))
;20====GET FILE NAME, READ FILE INTO LIST, DISPLAY NUMBER OF LINES
(setq fname (getfiled "Select a Text File" "" "" 0))
(if fname (progn
(setq fr (open fname "r"))
(setq llist () cnt 0)
(while (setq lin (read-line fr))
(setq llist (append llist (list lin)))
(setq cnt (1+ cnt)))
(close fr)
(princ "\n**File contains ")
(princ cnt)
(princ " lines.")
))
;30====OPTION--DISPLAY FILE ON TEXT SCREEN
(if fname (progn
(initget "Yes No")
(setq ans (getkword "\nDisplay file on text screen? (Y/N):
"))
(if (= ans "Yes") (progn
(textscr) (terpri) (terpri)
(foreach vvv llist (princ vvv) (terpri))
(terpri)))
))
;40====OPTION--ADD TEXT LINES TO DRAWING
(if fname (progn
(initget "Yes No")
(setq ans (getkword "\nAdd text lines to drawing? (Y/N):
"))
(if (= ans "Yes") (progn
(graphscr)
(initget 1)
(setq sp (getpoint "\nStartpoint: "))
(setq ts (getvar "textstyle"))
(setq tshei (cdr (assoc 40 (tblsearch "style"
ts))))
(if (> tshei 0)
(progn
(princ (strcat "\n**Current
text style has fixed height of " (rtos tshei 2 3)))
(setq thei tshei))
(progn
(initget 7)
(setq thei (getdist
sp "\nText height: "))))
(setq lspac (* 2 thei))
(initget 6)
(setq temp (getdist sp (strcat "\nLine spacing
<" (rtos lspac 2 3) ">: ")))
(if temp (setq lspac temp))
(setvar "cmdecho" 0)
(foreach vvv llist
(if (> tshei 0)
(command ".text" sp
0 vvv)
(command ".text" sp
thei 0 vvv))
(setq sp (polar sp (* pi 1.5) lspac)))
(setvar "cmdecho" 1)
))
))
;50====RESTORE
(setvar "blipmode" obm)
(setvar "osmode" oom)
(princ)
)
-------- marker -------- end of working program -------- try it out --------
Sample program 3, balloon2
The balloon program was used as a sample program in lesson 6. In this lesson, however, we have added 16 lines so the balloon program will save its default balloon size in a file. The added lines are marked in the program below. (By the way, this program works properly only if the balloon2 program is in its own file, namely BALLOON2.LSP, rather than combined with other programs in a file with a different name.)
Many firms use the same size balloon on all their assemblies. Without the added 16 lines, the user would have to enter that balloon size every time a new drawing is started (or, if system variable LISPINIT is set to 0, every time AutoCAD is started). But with the added lines, the user enters the balloon size only once. It is saved in a file and retrieved every time balloon2 is run after that. The user can reset the balloon size at any time, and the new setting is saved in the file.
Added lines 3 - 6: These lines (section 15) find the location of the BALLOON2.LSP file and place it in variable blndfl. This location is used so that the file which saves the user's balloon diameter (BALLOON2.DIA) will reside in the same folder as the program file. Variable blndfl is used later by the section which reads the balloon diameter from the file (added lines 7-12) and the section which writes a new diameter to file when it is changed by the user (added lines 13-16). The first if statement checks to make sure variable blndfl is not a string before trying to find the program file. If it is a string (presumably the location of the program file) there is no need to search for the program file. The second if statement is needed just in case the program file is not found and the findfile function returns nil, which would cause the strlen and substr functions to crash (added line 6).
Added lines 7 - 12: Before attempting to read the balloon diameter from the BALLOON2.DIA file, the if statement checks to make sure of three things: (1) that variable blndia is null, (2) that blndfl is a string, and (3) that file BALLOON2.DIA can be found. If these three tests pass, BALLOON2.DIA is read and the string is converted to a real before being placed in blndia. When the program is used again in the same drawing, variable blndia will already be set so there is no need to open the file repeatedly -- only when the diameter is changed and the new diameter is written to file in lines 13-16.
Added lines 13 - 16: The default balloon diameter is shown in the prompt (just above added line 13). If the user simply hits 'Enter', variable temp is nil and the test in the if statement (just above added line 13) fails. However, if the user enters a value, and if variable blndfl is a string, then the new value is saved in the BALLOON2.DIA file.
------ marker ------ beginning of working program ------ try it out ------
;| BALLOON2 -- Stores balloon diameter in file
Copyright © 1988,1998 Ronald W. Leigh
Input: size of balloon, arrow location,
balloon
location, size of balloon, number
Output: draws assembly balloon
Variables:
blndfl Balloon diameter file location,
GLOBAL
ADDED 1
blndia Balloon diameter, GLOBAL
blnnum Balloon number, GLOBAL
cen Center of balloon
ep Endpoint of arrow
fr/fw File descriptors: file opened for reading/writing
ADDED 2
oom Old osnap mode
sp Start point of arrow
temp Temp. value for blndia and blnnum input
ts Name of current text style
tshei Text style
height
|;
;10====MAIN PROGRAM, SETUP
(defun c:balloon2 (/ cen ep fr fw oom sp temp ts tshei)
(setq oom (getvar "osmode"))
(graphscr)
;15====GET LOCATION OF BALLOON2.LSP PROGRAM FILE
(if (/= (type blndfl) 'STR)
(progn
;ADDED 3
(setq blndfl (findfile
"balloon2.lsp"))
;ADDED 4
(if (= (type blndfl)
'STR)
;ADDED 5
(setq blndfl (substr blndfl 1 (- (strlen blndfl)
12)))))) ;ADDED 6
;20====GET SIZE, START POINT, CENTER, & NUMBER
(if (and (null
blndia)
;ADDED 7
(= (type
blndfl)
'STR)
;ADDED 8
(findfile (strcat
blndfl "balloon2.dia"))) (progn ;ADDED 9
(setq fr (open (strcat blndfl "balloon2.dia") "r"))
;ADDED 10
(setq blndia (atof (read-line
fr)))
;ADDED 11
(close
fr)))
;ADDED 12
(if (null blndia)
(if (= 0 (getvar "dimscale"))
(setq blndia (/ (getvar "dimtxt") 0.28))
(setq blndia (/ (* (getvar "dimtxt") (getvar
"dimscale")) 0.28))
)
)
(initget 6)
(setq temp (getreal (strcat "\nBalloon diameter <" (rtos blndia
2 3) ">: ")))
(if temp (progn
(setq blndia temp)
(if (= (type blndfl) 'STR)
(progn
;ADDED 13
(setq fw (open (strcat blndfl "balloon2.dia")
"w")) ;ADDED 14
(write-line (rtos blndia 2 4)
fw)
;ADDED 15
(close
fw)))))
;ADDED 16
(setvar "osmode" 512)
(initget 1)
(setq sp (getpoint "\nStartpoint of arrow: "))
(setvar "osmode" 0)
(initget 1)
(setq cen (getpoint sp "\nLocation of balloon: "))
(if (null blnnum) (setq blnnum 0))
(setq blnnum (1+ blnnum))
(initget 6)
(setq temp (getint (strcat "\nBalloon number <" (itoa blnnum)
">: ")))
(if temp (setq blnnum temp))
;30====CALC. END POINT OF ARROW, GET TEXT STYLE HEIGHT, DRAW BALLOON
(setq ep (polar cen (angle cen sp) (/ blndia 2)))
(setq ts (getvar "textstyle"))
(setq tshei (cdr (assoc 40 (tblsearch "style" ts))))
(if (> tshei 0)
(princ "\nText style has fixed height; may not fit balloon."))
(setvar "cmdecho" 0)
(command ".dim1" "leader" sp ep) (command)
(command ".circle" cen "D" blndia)
(if (> tshei 0)
(command ".text" "M" cen 0 blnnum)
(command ".text" "M" cen (* 0.28 blndia) 0 blnnum)
)
;40====RESET
(setvar "cmdecho" 1)
(setvar "osmode" oom)
(princ)
)
-------- marker
-------- end of working program -------- try it out --------