2015-07-21 64 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備用版本。 –