Important: The information in this document is obsolete and should not be used for new development.
Writing File Data
Generally your application writes data to a file in response to the File menu commands Save or Save As. However, your application might also incorporate a scheme that automatically saves all open documents to disk every few minutes. It therefore makes sense to isolate the routines that handle the menu commands from the routines that handle the actual writing of data to disk. This section shows how to write the data stored in a TextEdit record to a file. See "Saving a File" on page 1-26 for instructions on handling the Save and Save As menu commands.It is very easy to write data from a specified buffer into a specified file. You simply position the file mark at the beginning of the file (using
SetFPos
), write the data into the file (usingFSWrite
), and then resize the file to the number of bytes actually written (usingSetEOF
). Listing 1-9 illustrates this sequence.Listing 1-9 Writing data into a file
FUNCTION DoWriteData (myWindow: WindowPtr; myTemp: Integer): OSErr; VAR myData: MyDocRecHnd; {handle to a document record} myLength: LongInt; {number of bytes to write to file} myText: TEHandle; {handle to TextEdit record} myBuffer: Handle; {handle to actual text in TERec} myVol: Integer; {volume reference number of myFile} myErr: OSErr; BEGIN myData := MyDocRecHnd(GetWRefCon(myWindow)); {get window's data record} myText := myData^^.editRec; {get TERec} myBuffer := myText^^.hText; {get text buffer} myLength := myText^^.teLength; {get text buffer size} myErr := SetFPos(myTemp, fsFromStart, 0); {set file mark at start} IF myErr = noErr THEN {write buffer into file} myErr := FSWrite(myTemp, myLength, myBuffer^); IF myErr = noErr THEN {adjust file size} myErr := SetEOF(myTemp, myLength); IF myErr = noErr THEN {find volume file is on} myErr := GetVRefNum(myTemp, myVol); IF myErr = noErr THEN {flush volume} myErr := FlushVol(NIL, myVol); IF myErr = noErr THEN {show file is up to date} myData^^.windowDirty := FALSE; DoWriteData := myErr; END;TheDoWriteData
function first retrieves the TextEdit record attached to the specified window and extracts the address and length of the actual text buffer from that record. Then it callsSetFPos
,FSWrite
, andSetEOF
as just explained. Finally,DoWriteData
determines the volume containing the file (using theGetVRefNum
function) and flushes that volume (using theFlushVol
function). This is necessary to ensure that both the file's data and the file's catalog entry are updated.Notice that the
DoWriteData
function takes a second parameter,myTemp
, which should be the file reference number of a temporary file, not the file reference number of the file associated with the window whose data you want to write. If you pass the reference number of the file associated with the window, you risk corrupting the file, because the existing file data is overwritten when you position the file mark at the beginning of the file and callFSWrite
. IfFSWrite
does not complete successfully, it is very likely that the file on disk does not contain the correct document data.To avoid corrupting the file containing the saved version of a document, always call
DoWriteData
specifying the file reference number of some new, temporary file. Then, whenDoWriteData
completes successfully, you can call theFSpExchangeFiles
function to swap the contents of the temporary file and the existing file. Listing 1-10 illustrates how to update a file on disk safely; it shows a sequence of updating, renaming, saving, and deleting files that preserves the contents of the existing file until the new version is safely recorded.Listing 1-10 Updating a file safely
FUNCTION DoWriteFile (myWindow): OSErr; VAR myData: MyDocRecHnd; {handle to window's document record} myFSpec: FSSpec; {FSSpec for file to update} myTSpec: FSSpec; {FSSpec for temporary file} myTime: LongInt; {current time; for temporary filename} myName: Str255; {name of temporary file} myTemp: Integer; {file reference number of temporary file} myVRef: Integer; {volume reference number of temporary file} myDirID: LongInt; {directory ID of temporary file} myErr: OSErr; BEGIN myData := MyDocRecHnd(GetWRefCon(myWindow));{get that window's data} myFSpec := myData^^.fileFSSpec; {get FSSpec for existing file} GetDateTime(myTime); {create a temporary filename} NumToString(myTime, myName); {Find the temporary folder on file's volume; create it if necessary.} myErr := FindFolder(myFSpec.vRefNum, kTemporaryFolderType, kCreateFolder, myVRef, myDirID); IF myErr = noErr THEN {make an FSSpec for temp file} myErr := FSMakeFSSpec(myVRef, myDirID, myName, myTSpec); IF (myErr = noErr) OR (myErr = fnfErr) THEN{create a temporary file} myErr := FSpCreate(myTSpec, 'trsh', 'trsh', smSystemScript); IF myErr = noErr THEN {open the newly created file} myErr := FSpOpenDF(myTSpec, fsRdWrPerm, myTemp); IF myErr = noErr THEN {write data to the data fork} myErr := DoWriteData(myWindow, myTemp); IF myErr = noErr THEN {close the temporary file} myErr := FSClose(myTemp); IF myErr = noErr THEN {swap data in the two files} myErr := FSpExchangeFiles(myTSpec, myFSpec); IF myErr = noErr THEN {delete the temporary file} myErr := FSpDelete(myTSpec); DoWriteFile := myErr; END;The essential idea behind this "safe-save" process is to save the data in memory into a new file and then to exchange the contents of the new file and the old version of the file by callingFSpExchangeFiles
. TheFSpExchangeFiles
function does not move the data on the volume; it merely changes the information in the volume's catalog file and, if the files are open, in their file control blocks (FCBs). The catalog entry for a file contains
Fields that describe the data remain with the data; fields that describe the file remain with the file. The creation date remains with the file; the modification date remains with the data. (For a more complete description of the
- fields that describe the physical data, such as the first allocation block, physical end, and logical end of both the resource and data forks
- fields that describe the file within the file system, such as file ID and parent
directory ID
FSpExchangeFiles
function, see the chapter "File Manager" in this book.)