TweetFollow Us on Twitter

MACINTOSH C
MACINTOSH C: A Hobbyist's Guide To Programming the Mac OS in C
Version 2.3

© 2000 K. J. Bricknell

Go to Contents

(Chapter 16)

FILES

A link to the associated demonstration program listing is at the bottom of this page




Preamble

Reference is made in this chapter to the Standard File Package, which displays dialog boxes that allow the user to specify the names and locations of files to be save or opened, and which reports the user's choices to your application.

Navigation Services was introduced with Mac OS 8.5 as an alternative to, and ultimately as a replacement for, the Standard File Package.

Those sections of this chapter which address the matter of Open and Save dialog boxes and the reporting of user choices to your application are oriented towards the Standard File Package. The use of Navigation Services for the same purpose is addressed at Chapter 16B - More On Files - Navigation Services.

The demonstration programs associated with this chapter and Chapter 16B are essentially identical except that the demonstration program Files1 uses the Standard File Package whereas the demonstration program Files2 uses Navigation Services.

Macintosh Files

A file is a named, ordered sequence of bytes stored on a Macintosh volume. The files associated with an application are typically:

  • The application file itself, which comprises the application's executable code and any application-specific resources and data.

  • Document files created by the user using the application, which the user can edit.

  • A preferences file created by the application to store user-specified preference settings for the application.
The Macintosh Operating System also uses files for certain purposes. For example, the File Manager uses a special file, called the volume's catalog file, to maintain the hierarchical organisation of files and folders in a volume.

Characteristics of Files

File Forks

All Macintosh files comprise two forks, known as the data fork and the resource fork. Unlike the bytes stored in the resource fork, the bytes in the data fork do not have to exhibit any particular internal structure. Your application is therefore responsible for interpreting the bytes in the data fork in whatever manner is appropriate.

Although all Macintosh files contain both a data fork and a resource fork, one or both of these forks may be empty. Fig 1 shows the typical contents of the data and resource forks of an application file and a document file.

(Data fork and resource fork)

Whether you store specific data in the data fork or the resource fork of a file depends largely on whether that data can usefully be structured as a resource. For example, if you want to store a small number of names and telephone numbers, you can easily define a resource type that pairs each name with its telephone number. You can then read names and corresponding numbers from the resource file by using Resource Manager functions. This approach is convenient because, to retrieve data stored in a resource, you simply specify the resource type and ID. You do not need to know, for example, how may bytes of data are stored in the resource.

In some cases, however, it is neither possible nor advisable to store your data in resources. For example, it is easiest to store a document's text, which is usually of variable length, in a file's data fork. You can then use File Manager functions to access any byte or group of bytes individually.

In general, you should store data created by the user in the data fork unless the data will occupy only a small number of resources. Always bear in mind that the Resource Manager was not designed as a general purpose data storage and retrieval system.

File Size

Volumes

The size of a file is usually limited only by the size of its volume. A volume is a portion of a storage device that is formatted to contain files. A volume can be an entire disk or only part of a disk. A 3.5 inch floppy disk, for example, is always formatted as one volume. Other memory devices, such as hard disks and file servers, can contain multiple volumes.

Logical Blocks and Allocation Blocks

The size of a volume varies from one type of device to another. Volumes are formatted into chunks known as logical blocks, each of which can contain up to 512 bytes. The actual size of a logical block on a volume is generally only of interest to the disk device driver. This is because the File Manager allocates space to a file in units called allocation blocks. An allocation block is a group of consecutive logical blocks. A non-empty file fork always occupies at least one allocation block.

The size of an allocation block is the chief distinguishing feature between the volume format known as the Hierarchical File System (HFS) and the newer, and optional, Hierarchical File System Plus (HFS+) introduced with Mac OS 8.1. The differences are as follows:

  • HFS (Mac OS Standard Format). For HFS-formatted volumes, the File Manager can access a maximum of 65,535 allocation blocks on any volume. For small volumes, such as volumes on floppy disks, the File Manager uses an allocation block size of only one logical block. However, the larger the volume, the larger is the allocation block. For example, on a 500 MB volume, the allocation block size is 8KB under HFS.

  • HFS + (Mac OS Extended Format). For HFS+-formatted volumes, the File Manager can access a maximum of 4.29 billion allocation blocks on any volume. This means that even huge volumes can be formatted with very small allocation blocks.

HFS is sometimes referred to as the Mac OS Standard Format. HFS+ is sometimes referred to as the Mac OS Extended Format. The HFS+ format is available for use with any storage device larger than 32MB that support the HFS volume format.

On large volumes, the significant reduction in allocation block size under HFS+ results in significant space savings. For example, on a 4 GB volume, a file containing only 4 KB of information requires 64 KB of space under HFS, whereas the same file requires only 4KB of space under HFS+.

Physical and Logical End-Of-File

To distinguish between the amount of space allocated to a file and the number of bytes of actual data in the file, two numbers are used to describe the size of the file:

  • Physical End-Of-File. The physical end-of-file is the number of bytes currently allocated to the file. Since the file's first byte is byte number 0, the physical end-of-file is 1 greater than the number of the last byte in its last allocation block. As a result, the physical end-of-file is always an exact multiple of the allocation block size.

  • Logical End-Of-File. The logical end-of-file is the number of those allocated bytes that currently contain data. It is one greater than the number of the last byte containing data.
Fig 2 illustrates logical end-of-file and physical end-of-file.

(Logical and physical end-of-file)

You can move the logical end-of-file to adjust the size of the file. When you move the logical end-of-file to a position more than one allocation block short of the current physical end-of-file, the File Manager automatically deletes the unneeded allocation block from the file. Similarly, if you increase the size of the file by moving the logical end-of-file past the physical end-of-file, the File Manager automatically adds one or more allocation blocks to the file.

Clumps

The number of allocation blocks added to the file is determined by the volume's clump size. A clump is a group of contiguous allocation blocks. The purpose of enlarging files by adding clumps is to reduce file fragmentation on a volume, thus improving the efficiency of read and write operations.

Combating File Fragmentation

If you plan to keep extending a file with multiple write operations, and you know in advance approximately how large the file is likely to become, you should first call SetEOF to set the file to that size. This reduces file fragmentation and improves I/O performance.

File Access

A file can be open or closed. Your application can perform certain operations, such as reading and writing data, only on open files. It can perform other operations, such as deleting, only on closed files.

Access Path and File Reference Number

When you open a file, the File Manager reads the information about the file from its volume and stores it in a file control block (FCB). The File Manager also creates an access path to the file. The access path specifies the volume on which the file is located and the location of the file on the volume. Each access path is assigned a unique file reference number (a number greater than 0) by which your application refers to that path. Multiple access paths may be opened to the same file.

File Mark

For each open access path, the File Manager maintains a current position marker, called the file mark, to keep track of where it is in the file during a read or write operation. The mark is the number of the next byte to be read or written. Each time a byte is read or written, the mark is moved. You can specify where each read or write operation should begin by setting the mark or specifying an offset.

Data Buffer

Each time you want to read or write a file's data, you need to pass the address of a data buffer in RAM. The File Manager uses the buffer when it transfers data to or from your application. You can use a single buffer for each read or write operation, or change the address and size of the buffer as necessary.

Disk Cache

When your application writes data to a file, the File Manager transfers the data from your application's data buffer to the disk cache, which is also a part of RAM (usually in the System heap). The File Manager uses the disk cache as an intermediate buffer when reading data from, or writing data to, the file system. When your application requests that data be read from a file, the File Manager looks for data in the disk cache and, if data is found in the cache, transfers that data to your application's data buffer. Otherwise, the File Manager reads the requested bytes from the disk and puts them in your data buffer.

The Hierarchical File System

Directories and Directory ID

The Macintosh Operating System uses a method of organising files called an hierarchical file system. In an hierarchical file system, files are grouped into directories (also called folders), which themselves may be grouped into other directories (see Fig 3). As shown at Fig 3, each directory has a number associated with it called the directory ID.

(Hierarchical file system)

Root Directory

The Finder works with the File Manager to maintain the organisation of files and folders on a volume. The hierarchical relationship of folders within folders on the desktop corresponds directly to the hierarchical directory structure maintained on the volume. The volume is known as the root directory, and the folders are known as subdirectories, or simply as directories.

Mounted Volumes

A volume appears on the desktop only after it has been mounted. When a volume is mounted, the File Manager places information about the volume in a nonrelocatable block of memory called a volume control block (VCB).

When a volume is mounted, the File Manager assigns a volume reference number by which you can refer to the volume for as long as it remains mounted. You can also identify a volume by its volume name, a sequence of 1 to 27 printing characters (excluding colons). The volume reference number should be used in preference to the volume name so as to avoid confusion between volumes with the same name.

The File Manager ignores case when comparing names but does recognize diacritical marks.

When an application ejects a disk from a drive, the File Manager places the volume offline. When a volume is offline, the volume control block is kept in memory and the volume reference number is still valid. If you make a File Manager call that references that volume, the File Manager presents the disk switch dialog box.

When a user drags a volume icon to the trash, the volume is unmounted. The volume control block is released and the volume is no longer known to the File Manager.

Parent Directory and Parent Directory ID

Each subdirectory is located within a directory called its parent directory. Typically, the parent directory is specified by a parent directory ID, which is simply the directory ID of the parent directory. The File Manager assigns a special parent directory ID to a volume's root directory. This is primarily to facilitate a consistent method of identifying files and directories using the volume reference number, the parent directory ID, and the file or directory name.

For the most part, your application does not need to be concerned about, or keep track of, the location of files in the file system hierarchy. Most of the files your application opens and saves are specified by the user via a dialog box, and their location is provided to your application by either the Finder, the Standard File Package, or Navigation Services. (One notable exception concerns preferences files, which are typically stored in the Preferences folder in the System folder.)

Aliases

In addition to files, folders and volumes, a fourth type of object, namely an alias, might appear on the Finder desktop. An alias is a special kind of file which represents another file, folder, or volume. The Finder, the Standard File Package, and Navigation Services automatically resolve aliases.

Identifying Files and Directories

Conventions for identifying files, directories and volumes have evolved as the File Manager has matured. System software Version 7.0 introduced a simple, standard form for identifying a file or directory called the file system specification. A file system specification is contained in a structure of type FSSpec:

     struct FSSpec
     {
       short  vRefNum;  // Volume reference number.
       long   parID;    // Directory ID of parent directory.
       Str63  name;     // Filename or directory name.
     };
     typedef struct FSSpec FSSpec;
     typedef FSSpec *FSSpecPtr, **FSSpecHandle;

In addition to the FSSpec structure, System 7 introduced a new set of high-level functions which accept FSSpec structures as input.

Creating, Opening, Reading From, Writing To, and Closing Files

Your application typically creates, opens, reads from, writes to, and closes files in response to the user choosing commands from the File menu. In addition, your application opens, reads from, writes to, and closes files in response to the required Apple events (see Chapter 10- Required Apple Events).

The following shows how to perform typical file operations within the context of a user choosing commands from an imaginary application's File menu. For the purposes of illustration, the assumption is made that the files involved store text documents and that, when retrieved from file, the documents are displayed in a window with scroll bars.

General File Menu and Required Apple Events Handling Strategy

A suggested general strategy for handling user choices from the New, Open..., Close, Save, Save As..., and (optional) Revert to Saved items in the File menu, and for responding to the required Apple events, is illustrated at Fig 4.

(General file menu handling strategy)

Preliminaries - Creating a Document Structure

When a user creates a new document or opens an existing document, your application displays the contents of the document in a window, which provides a standard interface for the user to view, and possibly edit, the document data. It is usual for your application to define a document structure, an application-specific data structure which contains information about both the window and the file whose contents are to be displayed in the window.

The following is an example application-defined document structure for an application that handles text files:

     typedef struct
     {
       TEHandle      textEditHdl;    // Handle to TextEdit structure.
       ControlHandle vScrollBarHdl;  // Handle to vertical scroll bar.
       ControlHandle hScrollBarHdl;  // Handle to horizontal scroll bar.
       SInt16        fileRefNum;     // File reference number for window's file.
       FSSpec        fileFSSpec;     // File's file system specification structure.
       Boolean       windowTouched;  // Has window's data changed?
     } documentStructure;
     typedef documentStructure *documentStructurePtr;
     typedef documentStructure **documentStructureHdl;

Note the fileRefNum and fileFSSpec fields. Note also that the last field (windowTouched) is used to indicate whether the contents of the document in memory differ from those in the associated file. When your application first reads in the file, it should set this field to false. Then, when any subsequent operations alter the contents of the document in memory, you should set the windowTouched field to true. If the user attempts to close a document window when the value of the windowTouched flag is true, your application should ask the user, via a dialog box, whether to save the changed version of the document to file.

To associate a particular document structure with a particular window, you simply assign the handle to that structure to the reference constant (refCon) field of the window structure using SetWRefCon.

Creating a New Document Window

The user expects to be able to create a new document using the New... command in the File menu. In addition, it is usual for an application to open a new untitled document window when it receives an Open Application event from the Finder. Typically, the application-defined function which handles the New... command (doNewCommand at Fig 4) would call another application-defined function (doNewDocWindow at Fig 4), which could be defined along the lines of the following example:

     OSErr doNewDocWindow(void)
     {
       documentStructureHdl docStrucHdl;

       // Open a new window.

       gWindowPtrs[++gNumberOfWindows] = GetNewWindow(rDocWindow,NULL,(WindowPtr) -1);
       if(gWindowPtrs[gNumberOfWindows] == NULL)
         return(MemError());

       // Allocate a relocatable block for a new document structure.

       docStrucHdl = myDocStrucHnd(NewHandle(sizeof(MyDocStruc)));
       if(docStrucHdl == NULL)
       {
         DisposeWindow(gWindowPtr[gNumberOfWindows--]);
         return(MemError());
       }

       // Create new text edit structure. Create scroll bars. 
       // Initialise document structure.

       MoveHHi((Handle) docStrucHdl);
       HLock((Handle) docStrucHdl);  
       (*docStrucHdl)->textEditHdl = TENew(gDestRect,gViewRect);
       (*docStrucHdl)->vScrollBarHdl = GetNewControl(rVScroll,
                                                     gWindowPtrs[gNumberOfWindows]);
       (*docStrucHdl)->hScrollBarHdl = GetNewControl(rHScroll,
                                                     gWindowPtrs[gNumberOfWindows]);
       (*docStrucHdl)->fileRefNum = 0;
       (*docStrucHdl)->windowTouched = false;

       if((*docStrucHdl)->textEditHdl == NULL || 
          (*docStrucHdl)->vScrollBarHdl == NULL ||
          (*docStrucHdl)->hScrollBarHdl == NULL)
       {
         DisposeWindow(gWindowPtr[gNumberOfWindows--]);
         DisposeControl((*docStrucHdl)->vScrollBarHdl);
         DisposeControl((*docStrucHdl)->hScrollBarHdl);
         TEDispose((*docStrucHdl)->textEditHdl == NULL);
         DisposeHandle((Handle) docStrucHdl);
         return(memFullErr);
       }

       // Make window visible.

       ShowWindow(gWindowPtr[gNumberOfWindows]);

       // Connect document structure to window.

       SetWRefCon(gWindowPtr[gNumberOfWindows],(SInt32) docStrucHdl);

       HUnlock((Handle) docStrucHdl);
       return(noErr);
     };

Note that this function does not actually create a new file, because it is usually better to wait until the user decides to save the new document before creating a file. Accordingly, doNewDocWindow sets the fileRefNum field of the document structure to 0 to indicate that no file is currently associated with this window.

Opening a File and Reading in Data

Your application will need to open a file when the user chooses the Open... command from the File menu (see doOpenCommand at Fig 4) and when it receives Open Documents and Print Documents events from the Finder. Your application's initial response to the user choosing the Open... command from the File menu should be to elicit a file selection from the user by presenting the standard Open dialog box (see Fig 5).

(Open dialog)

Presenting the Open Dialog Box

StandardGetFile is used to present the standard Open dialog box:

     void  StandardGetFile(fileFilter,numTypes,typeList,reply);

     FileFilterUPP      fileFilter; Pointer to optional file filter function.
     short              numTypes;   Number of file types to be displayed.
                                    -1 = all types.
     ConstSFTypeListPtr typelist;   List of file types to be displayed.
     StandardFileReply  *reply;     File reply structure (filled in by 
                                    StandardGetFile).

Standard File Reply Structure. The Open dialog box allows the user to navigate the file system hierarchy and select the required file. While the box is displayed, StandardGetFile handles all events until the user completes the interaction by clicking either the Open button or the Cancel button. When the user clicks one of those buttons, StandardGetFile returns the user's input in the reply parameter, that is, in a Standard File reply structure:

     struct StandardFileReply 
     {
       Boolean    sfGood;      // true if user clicked Open button.
       Boolean    sfReplacing; // true if file to be saved replaces file with 
                               // same name.
       OSType     sfType;      // File type of the selected file.
       FSSpec     sfFile;      // File system specification for selected item.
       ScriptCode sfScript;    // Script in which selected item's name is to 
                               // be displayed.
       short      sfFlags;     // Finder flags of selected item (stationery, etc.).
       Boolean    sfIsFolder;  // true if selected item is a folder.
       Boolean    sfIsVolume;  // true if selected item is a volume.
       long       sfReserved1; // (Reserved)
       short      sfReserved2; // (Reserved)
     };
     typedef struct StandardFileReply StandardFileReply;

Creating the Window and Opening the File

If the user clicked the Open dialog box's Open button, the next step is to call the application-defined function (doNewDocWindow at Fig 4) which creates a window and associated document structure and then open the file's data fork (doOpenFile at Fig 4).

The file's data fork is opened using FSpOpenDF:

     OSErr  FSpOpenDF(spec,permission,refNum);
     FSSpec *spec;        File system specification structure.
     SInt8  permission;   Access mode.
     short  *refNum;      Returned file reference number.

FSpOpenDF takes the FSSpec returned by StandardGetFile as its first parameter. The permission field specifies the access mode for opening the file. The access mode may be specified using one of the following constants:

Constant Value Description
fsCurPerm 0 Whatever permission is allowed.
fsRdPerm 1 Read permission.
fsWrPerm 2 Write permission.
fsRdWrPerm 3 Exclusive read/write permission.
fsRdWrShPerm 4 Shared read/write permission.

FSpOpenDF returns, in its third parameter, a file reference number. This reference number should be saved to the window's document structure so that it can be readily retrieved for use as a parameter in calls to functions which read from and write to the file.

Reading File Data

Once you have opened a file, you can read data from it. Generally, you need to read data from a file when the user first opens it or when the user reverts to the last saved version of a document by choosing the Revert to Saved item in the File menu (see doReadFile at Fig 4). Typically, an application-defined function for reading file data:

  • Retrieves the file reference number from the document structure.

  • Calls SetFPos to set the file mark to the beginning of the file:

         OSErr  SetFPos(refNum,posMode,posOff);
         short refNum;    File reference number.
         short posMode;   Positioning mode.
         long  posOff;    Positioning offset.
         
    
    The posMode parameter must contain one of the following constants:

    Constant Value Description
    fsAtMark 0 Remain at current mark.
    fsFromStart 1 Set mark relative to beginning of file.
    fsFromLEOF 2 Set mark relative to logical end of file.
    fsFromMark 3 Set mark relative to current mark.
    rdVerify 64 Add to above for read-verify.

  • Determine the number of bytes in the file by calling GetEOF :

         OSErr  GetEOF(refNum,logEOF);
         short refNum;    File reference number.
         long  *logEOF;   Receives length of file, in bytes.
    
    

  • Call FSRead to read the specified number of bytes from the file into the specified buffer:

         OSErr  FSRead(refNum,count,buffPtr);
         short refNum;     File reference number.
         long  *count;     On input: bytes to read.  On output: actual bytes read.
         void  *buffPtr;   Address of buffer into which bytes are to be read.
    
    

    Note that FSRead returns, in the count parameter, the actual number of bytes read.

Saving a File

There are several ways for the user to indicate that the current contents of a document should be saved. The user can choose the File menu commands Save or Save As... or the user can click the Save button in a dialog box that you display when the user attempts to close a "touched" document (that is, a document whose contents have changed since the last time it was saved) (see doCloseCommand at Fig 4). The dialog box used in this latter case would also be presented on receipt of a Quit Application event from the Finder when a "touched" document remains open.

Handling the Save Command

To handle the Save command (see doSaveCommand at Fig 4), your application should:

  • Check the file reference number field of the window's document structure to determine if the window already has a file.

  • If the window already has a file, call the application-defined function for writing files to disk (see doWriteFile at Fig 4). If the window does not have a file, call the application-defined function for handling the Save As... command.

Handling the Save As... Command

To handle the Save As... command (see doSaveAsCommand at Fig 4), your application should:

  • Call StandardPutFile to display the standard Save dialog box (see Fig 6):

         void  StandardPutFile(prompt,defaultName,reply);
         ConstStr255Param  prompt;        Prompt message.
         ConstStr255Param  defaultName;   Initial name of file.
         StandardFileReply *reply         File reply structure.
    
    
    StandardPutFile handles all user interaction until the user clicks the Save or Cancel button. When the user clicks the Open or Cancel button, StandardPutFile returns the user's input in the reply parameter (that is, in a Standard File reply structure).

    If the user clicks on the Save button, perform the remaining steps, otherwise return to the calling function.

    (Save dialog)

  • If the sfReplacing field of the Standard File reply structure does not contain true, call FSpCreate to create a new file and set the file type and creator:

         OSErr  FSpCreate(spec,creator,fileType,sciptTag);
         FSSpec     *spec;      File system specification structure.
         OSType     creator;     File creator.
         OSType     fileType;    File type.
         ScriptCode scriptTag;   Code of script system in which filename is displayed.
    
    

  • Copy the sfFile field of the Standard File reply structure to the file system specification structure field of the document structure.

  • If the window already has a file (that is, if the file reference number field of the document structure does not contain 0), close that file with a call to FSClose:

         OSErr  FSClose(refNum);
         short refNum;   File reference number.
    
    

  • Call FSpOpenDF to open the data fork.

  • Assign the file reference number returned by FSpOpenDF to the file reference number field of the document structure.

  • Call SetWTitle to set the window's title, using the string extracted from the name field of the sfFile field of the Standard File reply structure.

  • Call the application-defined function for writing files to disk (see doWriteFile at Fig 4).

Writing File Data

The application-defined function for writing data (see doWriteFile at Fig 4) should write to a temporary file, not to the document file itself. If you write directly to the document's file, you risk corrupting that file if the write operation does not complete successfully. The broad approach for saving data safely to disk is therefore to write the data to a temporary file and then, assuming the temporary file has been written successfully, swap the contents of the temporary file and the document's file.

The procedure for updating a file safely is as follows:

  • Get the file system specification from the document structure.

  • Create a temporary filename for the temporary file.

  • Call FindFolder to find the temporary folder on the file's volume, or create it if necessary:

         OSErr  FindFolder(vRefNum,folderType,createFolder,foundVRefNum,foundDirID);
         short   vRefNum;         Volume reference number.
         OSType  folderType;      Folder type for volume.
         Boolean createFolder;    kCreateFolder or kDontCreateFolder.
         short   *foundVRefNum;   Volume reference number for folder found.
         long    *foundDirID;     Directory ID of folder found.
    
    

  • Call FSMakeFSSpec to make a file system specification structure for the temporary file:

         OSErr  FSMakeFSSpec(vRefNum,dirID,fileName,spec);
         short            vRefNum;    Volume reference number.
         long             dirID;      Parent directory ID.
         ConstStr255Param fileName;   Full or partial pathname.
         FSSpec           spec;       Pointer to FSSpec structure.
    
    

  • Call FSpCreate to create the temporary file, and FSpOpenDF to open the temporary file's data fork.

  • Call the application-defined function for writing data to a file (see doWriteData at Fig 4). This function should:

    • Retrieve the address and length of the buffer (for example, from a TextEdit structure).

    • Call SetFPos to set the file mark to the beginning of the file.

    • Call FSWrite to write the buffer to the file:

           OSErr  FSWrite(refNum,count,buffPtr);
           short      refNum;     File reference number.
           long       *count;     On input: bytes to write.  
                                  On output: bytes written.
           const void *buffPtr;   Address of buffer containing data to write.
      
      

    • Call SetEOF to resize the file to the number of bytes actually written:

           OSErr  SetEOF(refNum,logEOF);
           short refNum;   File reference number.
           long  logEOF;   Logical end-of-file.
      
      

    • Call GetVRefNum to determine the volume containing the file:

           OSErr  GetVRefNum(refNum,vRefNum);
           short refNum;     File reference number.
           short *vRefNum;   Receives volume reference number.
      
      

    • Call FlushVol to flush the volume:

           OSErr  FlushVol(volName,vRefNum);
           ConstStr63Param volName;   Pointer to name of mounted volume
           short           vRefNum;   Volume reference number.
      
      
      Flushing the volume ensures that both the file's data and the file's catalog entry are updated.

      The catalog entry for a file contains fields that describe the physical data (such as the first allocation block and the physical and logical ends of both the resource and data forks) and fields that describe the file within the file system, such as file ID and parent directory ID.

  • Call FSClose to close the temporary file.

  • Call FSClose to close the existing file.

  • Call FSpExchangeFiles to swap the contents of the temporary file and the existing file:

         OSErr  FSpExchangeFiles(source,dest);
         const FSSpec *source;   Source file.
         const FSSpec *dest;     Destination file.
    
    FSpExchangeFiles does not actually move the data on the volume. It merely changes the information in the volume's catalog file and, if the files are open, their file control blocks (FCBs).

  • Call FSpDelete to delete the temporary file:

         OSErr  FSpDelete(spec);
         const FSSpec *spec;   File system specification.
    
    

  • Call FSpOpenDF to re-open the data fork of the existing file.
As a final step, you should call an application-defined function which copies the missing application name string resource (see Chapter 9 - Finder Interface) from the resource fork of the application file to the resource fork of the newly created file. This function (doCopyAppNameResource at Fig 4) should:

  • Call FSpCreateResFile to create the new file's resource fork:

         void  FSpCreateResFile(spec,creator,fileType,sciptTag);
         const FSSpec *spec;       File system specification structure.
         OSType       creator;     File creator.
         OSType       fileType;    File type.
         ScriptCode   scriptTag;   Code of script system.
    
    

  • Call FSpOpenResFile to open the resource fork:

        short  FSpOpenResFile(spec,permission);
         const FSSpec *spec;        File system specification structure.
         SignedByte   permission;   Permission code.
    
    
    The constants used to specify the access mode in the FSpOpenDF call (see above) are also used to specify the permission code in the FSpOpenResFile call.

  • Call an application-defined function (doCopyResource at Fig 4) which copies specified resources from one resource file to another to copy the missing-application name 'STR ' resource (ID -16396) from your application's resource fork to the resource fork of the newly-created file.

  • Call FSClose to close the resource fork.

Reverting to a Saved File

Many applications that manipulate files provide a Revert to Saved command in the File menu which allows the user to revert to the last saved version of a document. The procedure for handling this command (see doRevertCommand at Fig 4) is relatively simple. You firstly display an alert box asking whether to revert to the last saved version of the file (see Fig 7). If the user clicks the Cancel button, nothing should happen to the current document. If, however, the user clicks on the OK box, you simply call your application-defined function for reading file data (doReadFile at Fig 4) to read the disk version of a file back into the window.

(Revert to saved dialog)

Closing a File

Your application must close a file when the user clicks in the close box of the associated window or chooses the Close command from the File menu. You may also need to close files when the user chooses Quit from the File menu or a Quit Application event is received from the Finder.

After determining that the subject window is a document window and not a modeless dialog box (see doCloseCommand at Fig 4), your application should call the application-defined function for closing files (see doCloseFile at Fig 4). This function should:

  • Check whether the window is "touched" (that is, whether the contents of the window have been changed since the last time it was saved) by checking the windowTouched field of the document structure.

    If the document has been changed, present the user with a dialog box containing Yes, No and Cancel buttons and asking whether the document should be saved before it is closed. If the user clicks on the Cancel button, simply return. If the user clicks the Yes button, call the application-defined function for saving files and then proceed to the next step. If the user clicks the No button, simply proceed to the next step.

  • If the document structure indicates that a file has previously been opened for the document (that is, the file reference number field of the document structure contains a non-zero value), call FSClose to close the file, call FlushVol to ensure that both the file's data and the file's catalog entry are updated, and set the file reference number field in the document structure to 0.
  • Release memory associated with the storage of the file's data. Then dispose of the document structure and, finally, the window.

Customised Open and Save Dialog Boxes

The standard user interfaces provided by StandardGetFile and StandardPutFile may not be adequate for the needs of some applications. To accommodate such cases, the Standard File Package supports customised dialog boxes and, through callback functions, the handling of user actions within customised dialogs.

Typical Reasons for Customising the Standard Dialog Boxes

Specifying File Formats and File Types

A typical reason for customising the Save dialog box would be to allow the user to save a document in one of two file formats. In this case, you might simply add two radio buttons to the standard Save dialog box, as shown at Fig 8. If the application supported a number of different file formats, the radio buttons at Fig 8 could be replaced by a pop-up menu.

(Customised Save dialog)

A typical reason for customising the Open dialog box is to avoid clutter in the list of files and folders by filtering out all but one of those types. In this case, radio buttons or a pop-up menu might be added to the dialog box to enable the user to select which types of files to view in the list.

Selecting Volumes and Directories

In some circumstances, you need to allow the user to select a volume or directory. For example, the user might want to select a directory as a first step to searching all files in that directory for some specified information. Similarly, the user might want to select a volume before backing up all files on that volume. The standard Open dialog box is, however, designed for selecting files, not volumes or directories. It provides no obvious mechanism for choosing a selected directory instead of simply opening that directory.

To allow a user to select a directory - including the volume's root directory (the volume itself) - you can add an additional Select push button to the standard Open dialog box together with a Select a Folder: prompt at the top of the dialog box. By clicking the Select push button, the user would be able to select a highlighted directory rather than open it. Fig 9 shows the standard Open dialog box customised to allow the selection of a directory.

(Customised Open dialog)

Customising the Standard Dialog Boxes

To customise a dialog box, you should:

  • Using Resorcerer, copy the 'DLOG' and associated 'DITL' resources for the relevant standard dialog box from the System resource file to your project's resource file, assigning them the required new resource ID number. (The resource IDs for the standard Open and Save dialog boxes in the System file are, respectively, -6042 and -6043.)

  • Using Resorcerer, enlarge the dialog box as required to accommodate the additional items and then add the required additional items to the 'DITL' resource, taking care not to change the item numbers of the existing items. (The item numbers for your first additional item will be 10 for the Open dialog box and 13 for the Save dialog box.)

  • Write the supporting functions. Depending on the level of customising you require in your dialog box, you may need to write as many as four callback functions:

    • For customised Open dialogs, a file filter function for controlling the file types files that will appear in the dialog's list and thus the file types the user can open. For an Open dialog box customised to allow the selection of a directory, a file filter function which causes only folders and volumes to appear in the dialog's list.

    • A dialog hook function for handling user actions in the dialog box.

    • A modal dialog filter function for handling user events received from the Event Manager.

    • An activation function for highlighting the display when keyboard input is directed at a customised field defined by your application.

  • Call CustomGetFile or CustomPutFile, passing the resource IDs of the customised dialog boxes and universal procedure pointers to the callback functions:

         void  CustomGetFile(fileFilter,numTypes,typeList,reply,dlgID,where,dlgHook,
                             filterProc,activeList,activateProc,yourDataPtr);
    
         FileFilterYDUPP    fileFilter;    Optional file filter function.
         short              numTypes;      Number of file types to be displayed.
         ConstSFTypeListPtr typeList;      List of file types to be displayed.
         StandardFileReply  *reply;        Standard File reply structure.
         short              dlgID;         Dialog resource ID.
         Point              where;         Upper left corner of dialog box (global).
         DlgHookYDUPP       dlgHook;       UPP to dialog hook function.
         ModalFilterYDUPP   filterProc;    UPP to modal-dialog filter function.
         ActivationOrderListPtr activeList;  Pointer to list of active dialog items.
         ActivateYDUPP      activateProc;  UPP to activation function.
         void               *yourDataPtr;  UPP to optional data.
    
         void  CustomPutFile(prompt,defaultName,reply,dlgID,where,dlgHook,
                             filterProc,activeList,activateProc,yourDataPtr);
    
         ConstStr255Param   prompt;        Message to be displayed over text field.
         ConstStr255Param   defaultName;   Initial name of file.
         StandardFileReply  *reply;        Standard File reply structure.
         short              dlgID;         Dialog resource ID.
         Point              where;         Upper left corner of dialog box (global).
         DlgHookYDUPP       dlgHook;       UPP to dialog hook function.
         ModalFilterYDUPP   filterProc;    UPP to modal-dialog filter function.
         ActivationOrderListPtr activeList;  Pointer to list of active dialog items.
         ActivateYDUPP      activateProc;  UPP to activation function.
         void               *yourDataPtr;  UPP to optional data.
    
    


Main File Manager Constants, Data Types and Functions

Constants

Read/Write Permission

fsCurPerm     = 0
fsRdPerm      = 1
fsWrPerm      = 2
fsRdWrPerm    = 3
fsRdWrShPerm  = 4

File Mark Positioning Modes

fsAtMark     = 0
fsFromStart  = 1
fsFromLEOF   = 2
fsFromMark   = 3
rdVerify     = 64

Data Types

File System Specification Structure

struct FSSpec
{
  short  vRefNum;  // Volume reference number.
  long   parID;    // Directory ID of parent directory.
  Str63  name;     // Filename or directory name.
};
typedef struct FSSpec FSSpec;
typedef FSSpec *FSSpecPtr, **FSSpecHandle;

File Information Structure

struct FInfo
{
  OSType          fdType;      // File type.
  OSType          fdCreator;   // File's creator.
  unsigned short  fdFlags;     // Finder flags (fHasBundle, fInvisible, etc).
  Point           fdLocation;  // Position of top-left corner of file's icon.
  short           fdFldr;      // Folder containing file.
};
typedef struct FInfo FInfo;

Functions

Reading, Writing and Closing Files

OSErr  FSClose(short refNum); 
OSErr  FSRead(short refNum,long *count,void *buffPtr); 
OSErr  FSWrite(short refNum,long *count,const void *buffPtr); 

Manipulating the File Mark

OSErr  GetFPos(short refNum,long *filePos); 
OSErr  SetFPos(short refNum,short posMode,long posOff); 

Manipulating the End-Of-File

OSErr  GetEOF(short refNum,long *logEOF); 
OSErr  SetEOF(short refNum,long logEOF); 

Opening, Creating and Deleting Files

OSErr  FSpOpenDF(const FSSpec *spec,SInt8 permission,short *refNum);
OSErr  FSpOpenRF(const FSSpec *spec,SInt8 permission,short *refNum);
OSErr  FSpCreate(const FSSpec *spec,OSType creator,OSType fileType,
       ScriptCode scriptTag);
OSErr  FSpDelete(const FSSpec *spec);

Exchanging Data in Two Files

OSErr  FSpExchangeFiles(const FSSpec *source,const FSSpec *dest);

Creating File System Specifications

OSErr  FSMakeFSSpec(short vRefNum,long dirID,ConstStr255Param fileName,FSSpec *spec);

Updating Volumes

#define PBFlushVol(pb, async) ((async) ? PBFlushVolAsync(pb) : PBFlushVolSync(pb))

Obtaining Volume Information

OSErr  GetVInfo(short drvNum,StringPtr volName,short *vRefNum,long *freeBytes); 
OSErr  GetVRefNum(short fileRefNum,short *vRefNum);

Main Standard File Package Data Types and Functions

Data Types

typedef const OSType *ConstSFTypeListPtr;  // Pointer to an array of OSTypes.

Standard File Reply Structure

struct StandardFileReply 
{
  Boolean     sfGood;      // true if user clicked Open button.
  Boolean     sfReplacing; // true if file to be saved replaces file with same name.
  OSType      sfType;      // File type of the selected file.
  FSSpec      sfFile;      // File system specification for selected item.
  ScriptCode  sfScript;    // Script in which selected item's name is to be displayed.
  short       sfFlags;     // Finder flags of selected item (stationery, etc).
  Boolean     sfIsFolder;  // true if selected item is a folder.
  Boolean     sfIsVolume;  // true if selected item is a volume.
  long        sfReserved1; // (Reserved)
  short       sfReserved2; // (Reserved)
};
typedef struct StandardFileReply StandardFileReply;

Functions

Saving Files

void  StandardPutFile(ConstStr255Param prompt,ConstStr255Param defaultName,
      StandardFileReply *reply);
void  CustomPutFile(ConstStr255Param prompt,ConstStr255Param defaultName,
      StandardFileReply *reply,short dlgID,Point where,DlgHookYDUPP dlgHook,
      ModalFilterYDUPP filterProc,ActivationOrderListPtr activeList,
      ActivateYDUPP activate,void *yourDataPtr);

Opening Files

void  StandardGetFile(FileFilterUPP fileFilter,short numTypes,
      ConstSFTypeListPtr typeList,StandardFileReply *reply);
void  CustomGetFile(FileFilterYDUPP fileFilter,short numTypes,
      ConstSFTypeListPtr typeList,StandardFileReply *reply,short dlgID, 
      Point where,DlgHookYDUPP dlgHook,ModalFilterYDUPP filterProc,
      ActivationOrderListPtr activeList,ActivateYDUPP activate,
      void *yourDataPtr)

Relevant Resource Manager Functions

Creating and Opening Resource Files

void   FSpCreateResFile(const FSSpec *spec,OSType creator,OSType fileType,
       ScriptCode scriptTag);
short  FSpOpenResFile(const FSSpec *spec,SignedByte permission);

Relevant Finder Interface Functions

Find a Specified Folder

OSErr  FindFolder(short vRefNum,OSType folderType,Boolean createFolder,
       short *foundVRefNum,long *foundDirID)

Go to Demo

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »
Marvel Future Fight celebrates nine year...
Announced alongside an advertising image I can only assume was aimed squarely at myself with the prominent Deadpool and Odin featured on it, Netmarble has revealed their celebrations for the 9th anniversary of Marvel Future Fight. The Countdown... | Read more »
HoYoFair 2024 prepares to showcase over...
To say Genshin Impact took the world by storm when it was released would be an understatement. However, I think the most surprising part of the launch was just how much further it went than gaming. There have been concerts, art shows, massive... | Read more »

Price Scanner via MacPrices.net

Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more
24-inch M1 iMacs available at Apple starting...
Apple has clearance M1 iMacs available in their Certified Refurbished store starting at $1049 and ranging up to $300 off original MSRP. Each iMac is in like-new condition and comes with Apple’s... Read more
Walmart continues to offer $699 13-inch M1 Ma...
Walmart continues to offer new Apple 13″ M1 MacBook Airs (8GB RAM, 256GB SSD) online for $699, $300 off original MSRP, in Space Gray, Silver, and Gold colors. These are new MacBook for sale by... Read more
B&H has 13-inch M2 MacBook Airs with 16GB...
B&H Photo has 13″ MacBook Airs with M2 CPUs, 16GB of memory, and 256GB of storage in stock and on sale for $1099, $100 off Apple’s MSRP for this configuration. Free 1-2 day delivery is available... Read more
14-inch M3 MacBook Pro with 16GB of RAM avail...
Apple has the 14″ M3 MacBook Pro with 16GB of RAM and 1TB of storage, Certified Refurbished, available for $300 off MSRP. Each MacBook Pro features a new outer case, shipping is free, and an Apple 1-... Read more
Apple M2 Mac minis on sale for up to $150 off...
Amazon has Apple’s M2-powered Mac minis in stock and on sale for $100-$150 off MSRP, each including free delivery: – Mac mini M2/256GB SSD: $499, save $100 – Mac mini M2/512GB SSD: $699, save $100 –... Read more
Amazon is offering a $200 discount on 14-inch...
Amazon has 14-inch M3 MacBook Pros in stock and on sale for $200 off MSRP. Shipping is free. Note that Amazon’s stock tends to come and go: – 14″ M3 MacBook Pro (8GB RAM/512GB SSD): $1399.99, $200... Read more

Jobs Board

Sublease Associate Optometrist- *Apple* Val...
Sublease Associate Optometrist- Apple Valley, CA- Target Optical Date: Apr 20, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92307 **Requisition Read more
*Apple* Systems Administrator - JAMF - Syste...
Title: Apple Systems Administrator - JAMF ALTA is supporting a direct hire opportunity. This position is 100% Onsite for initial 3-6 months and then remote 1-2 Read more
Relationship Banker - *Apple* Valley Financ...
Relationship Banker - Apple Valley Financial Center APPLE VALLEY, Minnesota **Job Description:** At Bank of America, we are guided by a common purpose to help Read more
IN6728 Optometrist- *Apple* Valley, CA- Tar...
Date: Apr 9, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92308 **Requisition ID:** 824398 At Target Optical, we help people see and look great - and Read more
Medical Assistant - Orthopedics *Apple* Hil...
Medical Assistant - Orthopedics Apple Hill York Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.