5.1.2 File Operations

This section describes the file input/output and system information provided by the Win32 file functions.

5.1.2.1 Creating and Opening Files

The CreateFile function can create a new file or open an existing file. When an application uses this function, it must specify whether it wants to read from the file, write to the file, or both. The application must also specify what action to take if the file exists and if the file does not exist. For example, an application can specify that CreateFile is to always create the file. The function will create the file if it does not exist, and overwrite the file if it does exist.

CreateFile also enables an application to specify whether it wants to share the file for reading, writing, both, or neither. A file that is not shared cannot be opened by another application (or more than once by the first application) until it has been closed by the first application.

Win32 assigns a unique identifier, called a file handle, to each file that is opened or created. The application can use the file handle in functions that read from and write to the file. The handle is valid until the file is closed. When an application starts, it inherits all open file handles from the process that started it, if the handles are inheritable. For more information about processes, see Chapter 3, “Processes and Threads.”

For information about the standard-input, standard-output, and standard-error file handles, see Chapter 8, “Handles and Objects.”

An application should check the return value of CreateFile before attempting to use the handle to access the file. If an error occurred, the application should use GetLastError to obtain extended error information.

5.1.2.2 Closing and Deleting Files

An application should use the CloseHandle function to close an open file and the DeleteFile function to delete a file. A file must be closed before it can be deleted.

5.1.2.3 Copying and Moving Files

A file must be closed or opened only for reading before it can be copied. An application uses the CopyFile function to copy an existing file to a new file. Applications can specify whether CopyFile should fail if the new file already exists.

A file must be closed before an application can move it. The MoveFile function copies an existing file to a new location and deletes the original.

5.1.2.4 Reading from and Writing to a File

Every open file has a file pointer that specifies the next byte to be read or the location to receive the next byte that is written. When a file is opened for the first time, Win32 places the file pointer at the beginning of the file. As each byte is read or written, Win32 advances the file pointer. An application can also move the file pointer by using the SetFilePointer function.

An application reads from and writes to a file by using the ReadFile and WriteFile functions. These functions require a handle to a file opened for reading and writing, respectively. ReadFile and WriteFile read and write a specified number of bytes at the location indicated by the file pointer. The data is read and written exactly as given; the functions do not format the data.

When the file pointer reaches the end of the file and the application attempts to read from the file, no error occurs, but no bytes are read. Therefore, reading zero bytes without an error means the program has reached the end of the file.

An application can truncate or extend a file by using the SetEndOfFile function. This function sets the end of file to the current position of the file pointer. A WriteFile of zero bytes does nothing.

When an application writes to a file, the data being written is usually collected in an internal buffer and written to the disk on a regular basis. If there is data in the internal buffer when the file is closed, Win32 automatically writes the contents of the buffer to the disk before closing the file.

An application can force the system to write the contents of the buffer to the disk by using the FlushFileBuffers function. Alternatively, an application can specify that write operations should bypass the internal buffer and write directly to the disk by setting a flag when the file is created or opened with CreateFile.

Locking and Unlocking Files

Although Win32 allows more than one application to open a file and write to it, the applications must not write over each other's work. An application can prevent this problem by temporarily locking a region in a file. The LockFile function specifies a range of bytes to lock in a file. The range may extend beyond the current end of the file. Locking part of a file prevents all other processes from reading or writing the specified area. Any attempts to read or write a region licked by another process will fail. The application unlocks the region by using the UnlockFile function.

Asynchronous Input and Output

Asynchronous input/output is a process that enables some Win32 file I/O functions to return immediately, even though an I/O request is still pending. This enables an application to continue with other processing and wait for the I/O to complete at a later time.

The ReadFile and WriteFile functions enable an application to specify an OVERLAPPED structure that indicates where to position the file pointer before the read or write. The structure also contains an event handle that WaitForSingleObject or WaitForMultipleObjects can wait on.

An application can also wait on the file handle to synchronize the completion of an I/O operation, but this requires extreme caution. Each time an I/O operation is started, the system sets the file handle to the non-signaled state; each time an I/O operation completes, the system sets the file handle to the signaled state. Therefore, if an application starts two I/O operations and waits on the file handle, there is no way to determine which operation completed when the handle is set to the signaled state. If you need to do multiple asynchronous I/O operations to a single file, your application should wait on the event handle in the OVERLAPPED structure for each I/O operation, rather than wait on the file handle.

The ReadFileEx and WriteFileEx functions enable an application to specify a routine to execute when the asynchronous I/O request completes.

An application can monitor the contents of a directory and its subdirectories by using the FindFirstChangeNotification, FindNextChangeNotification, and FindCloseChangeNotification functions. Waiting for a change notification is similar to having a read pending against a directory, and if desired, its subdirectories. When something changes within the directory being watched, the read completes. For example, an application could use these functions to update a directory listing whenever a filename within the monitored directory changes.

An application can specify a set of conditions that will trigger a change notification with the FindFirstChangeNotification function. This function also returns a handle that can be waited on by WaitForSingleObject or WaitForMultipleObjects. If the wait condition is satisfied, FindNextChangeNotification can be used to provide a handle to wait on subsequent changes.

The FindCloseChangeNotification function closes the handle.

5.1.2.5 Searching for Files

An application can search the current directory for all filenames that match a given pattern by using the FindFirstFile, FindNextFile, and FindClose functions. The pattern must be a valid filename and can include wildcard characters. The wildcard characters are the question mark (?) and the asterisk (*). The question mark matches any single character; the asterisk matches any combination of characters. For example, the pattern a* matches the names abc, a23, and abca, but the pattern a?c matches only the name abc.

FindFirstFile opens a search handle that FindNextFile uses to search for other files with the same pattern. Both functions also return information about the file that was found in a WIN32_FIND_DATA structure. This information includes the filename, size, attributes, and time. The FindClose function closes the search handle.

An application can search for a single file on a specific path by using the SearchPath function.

5.1.2.6 Creating Temporary Files

Applications can create temporary file names with the GetTempFileName function. The GetTempPath function retrieves the path to the directory where temporary files should be created.

5.1.2.7 Getting Information About Files

There are six file characteristics, called attributes, that may be associated with a file. These attributes indicate whether the file is read-only, hidden, system, archived, a directory, or normal. A file may have any combination of attributes, but the normal attribute is valid only if used alone.

A read-only file cannot be deleted or opened for writing. A hidden file cannot be displayed by using an ordinary directory listing. A system file is excluded from normal directory searches. The archived attribute is used by applications that require a way to mark a file for backup or removal. An application can retrieve and set a file's attributes by using the GetFileAttributes and SetFileAttributes functions.

The GetFileType function returns the type of a file: disk, character (such as a console), pipe, or unknown. The GetFileSize function returns the size of a file. Applications can retrieve the full path to a file by using the GetFullPathName function.

Applications can retrieve and set the date and time a file was created, last modified, or last accessed by using the GetFileTime and SetFileTime functions. The CompareFileTime function compares two file times. For more information on file times, see Chapter 20, “Time.”

5.1.2.8 Directory Operations

When an application starts, it inherits the current directory from the application that starts it. An application can determine which directory is current by using the GetCurrentDirectory function. An application can change the current directory by using the SetCurrentDirectory function.

When an application creates a new file, the system adds a file to the specified directory. Each directory can have any number of files, up to the physical limit of the disk. An application can create new directories and delete existing directories by using the CreateDirectory and RemoveDirectory functions. An application cannot delete a directory unless it is empty. Applications can move or delete files by using the MoveFile and DeleteFile functions.

5.1.2.9 Getting System Information

Win32 provides several functions that applications use to obtain information about file system components.

The GetVolumeInformation function retrieves information about the file system on a given volume. This information includes the volume name, volume serial number, file-system name, file-system flags, maximum length of a filename, and so on.

The GetSystemDirectory and GetWindowsDirectory functions retrieve the paths to the Windows system directory and Windows directory, respectively.

The GetDiskFreeSpace function retrieves organizational information about a disk, including the number of bytes per sector, the number of sectors per cluster, the number of free clusters, and total number of clusters.

The GetDriveType function indicates whether the disk referenced by the specified disk drive is removable, fixed, CD-ROM, RAM, or a network drive.

The GetLogicalDrives function indicates which drives are currently present on the system. The GetLogicalDriveStrings retrieves a null-terminated string for each drive present on the system. These strings can be used whenever a root directory is required.