2015-07-21 65 views
2

我需要在Python在.NET组件(经由pythonnet's clr module访问打开一个可写的文件句柄,然后手离开文件描述符的功能。如何从Python文件句柄打开.NET FileStream对象?

从Python文件对象获取到的win32 HANDLE*是相当简单的,如图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,应该现在是可能的,无论是从直IntPtr(把手)构建标准FileStream对象或从SafeFileHandle包装

0123。
FileStream(IntPtr, FileAccess) 
FileStream(SafeFileHandle, FileAccess) 

问题是...我怎么能说服clr模块投handle作为IntPtr

我已经试过以下的各种版本,但他们都给予我的错误:

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") 

如何得到这个该死的文件句柄到C#有什么建议?

+0

这个怎么样? http://stackoverflow.com/a/14334609/2230844 – denfromufa

+1

否则为什么不使用COM,如果这是Win32? – denfromufa

+1

@denfromufa,由于各种原因,CLR API对于这个项目来说是优越的。您链接的答案解释了如何从C++获取托管句柄到C#中,但不幸的是,这对Python的情况并没有帮助。 –

回答

1

得到了一个答案,感谢​​上的好人。

关键是使用Overloads构造函数强制将win32 HANDLE改为IntPtr类型。

下面是一个完整的工作示例:

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 
2

可能有点太晚了这个答案,但会像this工作过?

from contextlib import contextmanager 
import ctypes 
import io 
import os, sys 
import tempfile 

libc = ctypes.CDLL(None) 
c_stdout = ctypes.c_void_p.in_dll(libc, 'stdout') 

@contextmanager 
def stdout_redirector(stream): 
    # The original fd stdout points to. Usually 1 on POSIX systems. 
    original_stdout_fd = sys.stdout.fileno() 

    def _redirect_stdout(to_fd): 
     """Redirect stdout to the given file descriptor.""" 
     # Flush the C-level buffer stdout 
     libc.fflush(c_stdout) 
     # Flush and close sys.stdout - also closes the file descriptor (fd) 
     sys.stdout.close() 
     # Make original_stdout_fd point to the same file as to_fd 
     os.dup2(to_fd, original_stdout_fd) 
     # Create a new sys.stdout that points to the redirected fd 
     sys.stdout = io.TextIOWrapper(os.fdopen(original_stdout_fd, 'wb')) 

    # Save a copy of the original stdout fd in saved_stdout_fd 
    saved_stdout_fd = os.dup(original_stdout_fd) 
    try: 
     # Create a temporary file and redirect stdout to it 
     tfile = tempfile.TemporaryFile(mode='w+b') 
     _redirect_stdout(tfile.fileno()) 
     # Yield to caller, then redirect stdout back to the saved fd 
     yield 
     _redirect_stdout(saved_stdout_fd) 
     # Copy contents of temporary file to the given stream 
     tfile.flush() 
     tfile.seek(0, io.SEEK_SET) 
     stream.write(tfile.read()) 
    finally: 
     tfile.close() 
     os.close(saved_stdout_fd) 
+0

是的,这也是一个合理的选择,尽管在Windows下尝试修改'stdin' /'stdout'文件句柄可能非常烦琐。我认为将Windows C API文件句柄强制转换为C#文件句柄仍然更直接。无论如何,你现在是负责实际使用这个的代码的人:-)。它是否导致问题? –

+0

我认为最好的答案是,还没有...最新版本的'pythonnet'存在兼容性问题,并试图找到一个标准Lib备用版本。 –