Search code examples
c#pythonclrhandlepython.net

How can I open a .NET FileStream object from a Python file handle?


I need to open a writable file handle in Python and then hand off the file descriptor to a function in a .NET assembly (accessed via pythonnet's clr module.

Getting from the Python file object to the win32 HANDLE* is fairly straightforward, as shown in this question:

import clr
from Microsoft.Win32.SafeHandles import SafeFileHandle
from System.IO import FileStream, FileAccess

pyf=open("c:/temp/testing123.txt","w")
fileno=pyf.fileno()
print fileno               # 6
handle = msvcrt.get_osfhandle(fileno)
print handle               # 1832L

According to MSDN, it should now be possible to construct a standard FileStream object from either a straight IntPtr (the handle) or from a SafeFileHandle wrapper.

FileStream(IntPtr, FileAccess)
FileStream(SafeFileHandle, FileAccess)

The problem is... how can I convince the clr module to cast handle as an IntPtr?

I've tried various versions of the following, but they all give me errors:

FileStream(IntPtr(handle), True)
FileStream(IntPtr(Int64(handle), True)
FileStream(IntPtr(Int32(handle), True)
SafeFileHandle(IntPtr(handle), True)
...

=> TypeError ("value cannot be converted to System.IntPtr")

Any suggestions for how to get this darn file handle into C#?


Solution

  • Got an answer thanks to the good folks on the pythonnet mailing list.

    The key is to use the Overloads constructor to force-cast the win32 HANDLE to IntPtr type.

    Here's a complete working example:

    import tempfile, msvcrt
    import clr, msvcrt
    from System.IO import FileStream, FileAccess
    from System import IntPtr
    
    with tempfile.NamedTemporaryFile(suffix='.txt', delete=False) as pyf:
        fileno=pyf.fileno()
        print "fileno", fileno
        handle = msvcrt.get_osfhandle(fileno)
        print "HANDLE", handle
    
        pyf.write("Python\n")
        pyf.flush()
    
        cs_handle = IntPtr.Overloads[long](handle)
        cs_fs = FileStream(cs_handle, FileAccess.Write)
        cs_fs.Write("CLR\n", 0, 4)
        cs_fs.Flush()
    
    print "file should contain a line from Python and a line from CLR: ", pyf.name