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 written. When a file is opened for the first time, Windows places the file
pointer at the beginning of the file. As each byte is read or written, Windows
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 of a file to be 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 a 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. Writing zero bytes does nothing.
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.
When an application writes to a file, Windows usually collects the data being
written in an internal buffer and writes the data to the disk on a regular
basis.
An application can force the operating system to write the contents of the
buffer to the disk by using the
FlushFileBuffers function. Alternatively, an application can specify that write operations are
to bypass the internal buffer and write directly to the disk by setting a flag
when the file is created or opened by using the
CreateFile function.
If there is data in the internal buffer when the file is closed, Windows does
not automatically write the contents of the buffer to the disk before closing
the file. If the application does not force the operating system to write the
buffer to disk before closing the file, the caching algorithm determines when the
buffer is written.
Applications must not read from nor write to the input buffer that a read
operation is using until the read operation completes. A premature access to the
input buffer may lead to corruption of the data read into that buffer.
Locking and Unlocking Files
Although Windows allows more than one application to open a file and write to
it, 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 and
LockFileEx functions lock a specified range of bytes 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 anywhere in the specified area. Attempts to read
from or write to a region locked by another process always fail.
The
LockFileEx function allows an application to specify either a
shared lock or an
exclusive lock. An exclusive lock denies all other processes both read and write access to
the specified region of the file. A shared lock denies all processes write
access to the specified region of the file, including the process that first locks
the region. This can be used to create a read-only region in a file.
The application unlocks the region by using the
UnlockFile or
UnlockFileEx function. An application should unlock all locked areas before closing a
file.
Asynchronous Input and Output
Asynchronous input and output (asynchronous I/O) allows some I/O functions to return immediately, even
though an I/O request is still pending. Asynchronous I/O enables an application to
continue with other processing and wait for the I/O to be completed at a later
time. Asynchronous I/O is also called overlapped I/O.
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 operation. The handle of the file being read from or written to must
have been opened with the FILE_FLAG_OVERLAPPED flag. You can also create an event
and put the handle in the
OVERLAPPED structure; the
wait functions can then be used to wait for the I/O operation to complete by waiting on the
event handle.
An application can also wait on the file handle to synchronize the completion
of an I/O operation, but doing so requires extreme caution. Each time an I/O
operation is started, the operating system sets the file handle to the
nonsignaled state. Each time an I/O operation is completed, the operating 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 is finished when the handle is set to the signaled state. If an
application must perform multiple asynchronous I/O operations on a single file, it
should wait on the event handle in the
OVERLAPPED structure for each I/O operation, rather than on the file handle.
To cancel all pending asynchronous I/O operations, use the
CancelIO function. This function only cancels operations issued by the calling thread
for the specified file handle.
The
ReadFileEx and
WriteFileEx functions enable an application to specify a routine to execute (see
FileIOCompletionRoutine) when the asynchronous I/O request is completed.
For more information, see
Synchronization and Overlapped Input and Output.
I/O Completion Ports
I/O completion ports are used with asynchronous I/O. The
CreateIoCompletionPort function associates an I/O completion port with one or more file handles.
When an asynchronous I/O operation started on a file handle associated with an I/O
completion port is completed, an I/O completion packet is queued to the port.
This can be used to combine the synchronization point for multiple file handles
into a single object.
A thread uses the
GetQueuedCompletionStatus function to wait for an I/O completion packet to be queued to the I/O
completion port, rather than waiting directly for the asynchronous I/O to complete.
Threads that block their execution on an I/O completion port are released in
last-in-first-out (LIFO) order. This means that when an I/O completion packet is
queued to the I/O completion port, the system releases the last thread to block
its execution on the port.
The most important property of an I/O completion port is the concurrency
value. The concurrency value of an I/O completion port is specified when the I/O
completion port is created. This value limits the number of runnable threads
associated with the I/O completion port. When the total number of runnable threads
associated with the I/O completion port reaches the concurrency value, the
system blocks the execution of the threads until the number of runnable threads
associated with the I/O completion port drops below the concurrency value. The most
efficient scenario occurs when there are I/O completion packets waiting in the
queue, but no waits can be satisfied because the port has reached its
concurrency limit. In this case, when a running thread calls
GetQueuedCompletionStatus, it will immediately pick up the queued I/O completion packet. No context
switches will occur, because the running thread is continually picking up I/O
completion packets and the other threads are unable to run.
The best value to pick for the concurrency value is the number of CPUs on the
machine. If your transaction required a lengthy computation, a larger
concurrency value will allow more threads to run. Each transaction will take longer to
complete, but more transactions will be processed at the same time. It is easy
to experiment with the concurrency value to achieve the best effect for your
application.
The
PostQueuedCompletionStatus function allows an application to queue its own special-purpose I/O
completion packets to the I/O completion port without starting an asynchronous I/O
operation. This is useful for notifying worker threads of external events.
The I/O completion port is freed when there are no more references to it. The
port handle and every file handle associated with the I/O completion port
reference the I/O completion port. All the handles must be closed to free the I/O
completion port. To close the port handle, call the
CloseHandle function.
- Software for developers
-
Delphi Components
.Net Components
Software for Android Developers
- More information resources
-
MegaDetailed.Net
Unix Manual Pages
Delphi Examples
- Databases for Amazon shops developers
-
Amazon Categories Database
Browse Nodes Database