I l@ve RuBoard Previous Section Next Section

17.2 Native File Manipulation: The win32file Module

There are times when the standard Python file objects can't meet your requirements, and you need to use the Windows API to manipulate files. This can happen in a number of situations, such as:

Python file objects are integrated closely with Python. You should use the win32file module only when standard Python file objects can't meet your requirements. Using the win32file module is a good deal more complex than using native Python files.

17.2.1 Opening and Creating Files

The win32file.CreateFile() function opens or creates standard files, returning a handle to the file. Standard files come in many flavors, including synchronous files (where read or write operations don't return until the operation has completed); asynchronous (or overlapped I/O) files, where read and write operations return immediately; and temporary files that are automatically deleted when the handle is closed. Files may also be opened requesting that Windows not cache any file operations, that no buffering is performed, etc. All the variations that CreateFile() can use are too numerous to list here. For full details, please see the Windows API documentation for CreateFile().

The CreateFile() function takes the following parameters:

This function returns a PyHANDLE object. PyHANDLEs are simply objects that wrap standard Win32 HANDLEs. When a PyHANDLE object goes out of scope, it's automatically closed; thus, it's generally not necessary to close these HANDLEs as it is necessary when using these from C or C++.

Let's see how these parameters interact and test out some of the documented semantics. Here's a small script that uses the win32file module to work with Win32 file handles. The code creates a file, then checks that other attempts to open the file either succeed or fail, based on the flags passed to CreateFile(). You will also find that auto-delete files behave as expected; i.e., after the last handle is closed, the file no longer exists on disk:

# CheckFileSemantics.py
#    Demonstrate the semantics of CreateFile.

# To keep the source code small, 
# we import all win32file objects.
from win32file import *

import win32api
import os

# First, lets create a normal file
h1 = CreateFile( \
       "\\file1.tst", # The file name \
       GENERIC_WRITE, # we want write access. \
       FILE_SHARE_READ, # others can open for read \
       None, # No special security requirements \
       CREATE_ALWAYS, # File to be created. \
       FILE_ATTRIBUTE_NORMAL, # Normal attributes \
       None ) # No template file.

# now we will print the handle, 
# just to prove we have one!
print "The first handle is", h1

# Now attempt to open the file again, 
# this time for read access
h2 = CreateFile( \
      "\\file1.tst", # The same file name. \
      GENERIC_READ, # read access \
      FILE_SHARE_WRITE | FILE_SHARE_READ, \
      None, # No special security requirements \
      OPEN_EXISTING, # expect the file to exist. \
      0, # Not creating, so attributes dont matter. \
      None ) # No template file

# Prove we have another handle
print "The second handle is", h2

# Now attempt yet again, but for write access.
# We expect this to fail.
try:
  h3 = CreateFile( \
        "\\file1.tst", # The same file name. \
        GENERIC_WRITE, # write access \
        0, # No special sharing \
        None, # No special security requirements \
        CREATE_ALWAYS, # attempting to recreate it! \
        0, # Not creating file, so no attributes  \
        None ) # No template file

except win32api.error, (code, function, message):
  print "The file could not be opened for write mode."
  print "Error", code, "with message", message

# Close the handles.
h1.Close()
h2.Close()

# Now lets check out the FILE_FLAG_DELETE_ON_CLOSE
fileAttributes = FILE_ATTRIBUTE_NORMAL | \
                 FILE_FLAG_DELETE_ON_CLOSE

h1 = CreateFile( \
       "\\file1.tst", # The file name \
       GENERIC_WRITE, # we want write access. \
       FILE_SHARE_READ, # others can open for read \
       None, # no special security requirements \
       CREATE_ALWAYS, # file to be created. \
       fileAttributes, \
       None ) # No template file.

# Do a stat of the file to ensure it exists.
print "File stats are", os.stat("\\file1.tst")

# Close the handle
h1.Close()

try:
    os.stat("\\file1.tst")
except os.error:
    print "Could not stat the file - file does not exist"

When you run this script, you see the following output:

The first handle is <PyHANDLE at 8344464 (80)>
The second handle is <PyHANDLE at 8344400 (112)>
The file could not be opened for write mode.
Error 32 with message The process cannot access the file because
it is being used by another process.
File stats are (33206, 0, 11, 1, 0, 0, 0, 916111892, 916111892, 916111892)
Could not stat the file - file does not exist

Thus, the semantics are what you'd expect:

17.2.2 Reading and Writing Files

The win32file module has functions for reading and writing files. Not surprisingly, win32file.ReadFile() reads files, and win32file.WriteFile() writes files.

win32file.ReadFile() takes the following parameters:

win32file.ReadFile() returns two pieces of information in a Python tuple: the error code for ReadFile and the data itself. The error code is either zero or the value winerror.ERROR_IO_PENDING if overlapped I/O is being performed. All other error codes are trapped and raises a Python exception.

win32file.WriteFile() takes the following parameters:

win32file.WriteFile() returns the error code from the operation. This is either zero or win32error.ERROR_IO_PENDING if overlapped I/O is used. All other error codes are converted to a Python exception.

17.2.3 Overlapped I/O

Windows provides a number of techniques for high-performance file I/O. The most common is overlapped I/O. Using overlapped I/O, the win32file.ReadFile() and win32file.WriteFile() operations are asynchronous and return before the actual I/O operation has completed. When the I/O operation finally completes, a Windows event is signaled.

Overlapped I/O does have some requirements normal I/O operations don't:

As you can imagine, the code for performing overlapped I/O is more complex than when performing synchronous I/O. Chapter 18, contains some sample code that uses basic overlapped I/O on a Windows-named pipe.

I l@ve RuBoard Previous Section Next Section