2010-03-22 70 views
3

我正在使用传统文件格式。托管.NET等同于WinBase中的CreateFile和WriteFile(kernel32.dll)

该文件是使用非托管C++创建的,该C++利用WinBase.h CreateFile()& WriteFile()函数(可在kernel32.dll中找到)。我一直在以P

/Invoke的互操作来访问,像这样这些本机功能:

[DllImport("kernel32.dll")] 
    public static extern bool WriteFile(
     IntPtr hFile, 
     byte[] lpBuffer, 
     uint nNumberOfBytesToWrite, 
     out uint lpNumberOfBytesWritten, 
     [In] ref NativeOverlapped lpOverlapped); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern bool WriteFileEx(
     IntPtr hFile, 
     byte[] lpBuffer, 
     uint nNumberOfBytesToWrite, 
     [In] ref NativeOverlapped lpOverlapped, 
     WriteFileCompletionDelegate lpCompletionRoutine); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern IntPtr CreateFile(
     string lpFileName, uint dwDesiredAccess, 
     uint dwShareMode, IntPtr lpSecurityAttributes, 
     uint dwCreationDisposition, 
     uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern bool CloseHandle(IntPtr hObject); 

    public delegate void WriteFileCompletionDelegate(
     UInt32 dwErrorCode, 
     UInt32 dwNumberOfBytesTransfered, 
     ref NativeOverlapped lpOverlapped); 

与此问题是,当我打电话的WriteFile(),该文件总是由程序调用覆盖。

优选我想使用一个兼容的.NET等价物,它将允许我生成完全相同的输出格式。

的C++代码看起来像这样:(WORKING)

HANDLE hFile = CreateFile(sFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
WriteFile(hFile, &someVar1, sizeof(bool), &dwWritten, NULL); 
WriteFile(hFile, &someVar1, sizeof(long), &dwWritten, NULL); 
WriteFile(hFile, &someVar2, sizeof(bool), &dwWritten, NULL); 
WriteFile(hFile, sStr.GetBuffer(0), dwStrLen*sizeof(TCHAR), &dwWritten, NULL); 
CloseHandle(hFile); 

C#的是如下:(覆盖以前WRITE即会输出文件将只包含 'T')

{ 
    var hFile = COMFileOps2.CreateFile(FILE_NAME, (uint) COMFileOps2.FILE_GENERIC_WRITE, 
             COMFileOps2.FILE_SHARE_WRITE, IntPtr.Zero, COMFileOps2.CREATE_ALWAYS, 
             COMFileOps2.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); 

    var natOverlap = new NativeOverlapped(); 

    COMFileOps2.WriteFileEx(hFile, new byte[] {(byte) 't'}, 1, ref natOverlap, Callback); 
    COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'e' }, 1, ref natOverlap, Callback); 
    COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'s' }, 1, ref natOverlap, Callback); 
    COMFileOps2.WriteFileEx(hFile, new byte[] { (byte)'T' }, 1, ref natOverlap, Callback); 

    COMFileOps2.CloseHandle(hFile); 

} 

private static void Callback(uint dwerrorcode, uint dwnumberofbytestransfered, ref NativeOverlapped lpoverlapped) 
{ 
    throw new NotImplementedException(); 
} 

更新:下面的C#代码将写出“测试”:

uint written; 
uint position = 0; 

var natOverlap0 = new NativeOverlapped(); 
COMFileOps.WriteFile(hFile, new byte[] {(byte) 'T'}, 1, out written, ref natOverlap0); 

position += written; 
var natOverlap1 = new NativeOverlapped {OffsetLow = (int) position}; 
COMFileOps.WriteFile(hFile, new byte[] { (byte)'e' }, 1, out written, ref natOverlap1); 

position += written; 
var natOverlap2 = new NativeOverlapped { OffsetLow = (int)position }; 
COMFileOps.WriteFile(hFile, new byte[] { (byte)'s' }, 1, out written, ref natOverlap2); 

position += written; 
var natOverlap3 = new NativeOverlapped { OffsetLow = (int)position }; 
COMFileOps.WriteFile(hFile, new byte[] { (byte)'t' }, 1, out written, ref natOverlap3); 

COMFileOps.CloseHandle(hFile); 

谢谢。

回答

3

WriteFileEx只能异步运行,您必须为每个挂起的调用提供OVERLAPPED的SEPARATE实例,并且您必须设置OVERLAPPED成员,例如作为文件偏移量,那么在所有的操作完成之前你不能调用CloseHandle,并且使用一个局部变量来覆盖范围,并让它超出范围?你的数据被覆盖的是可能出错的东西的至少你显示的代码是

所以这就是为什么你的代码不起作用,我不知道你为什么从WriteFile切换到WriteFileEx,另外,从C#调用Win32 API是非常不方便的,尽管偶尔具完整。但首先看看.NET File API是否能满足你的需求。由于.NET File API倾向于使用字符串(在textmode中,注意换行符等)或字节数组,因此您需要将其他变量转换为byte []。 BitConverter班是你的朋友在这里。

0

看看System.IO.FileSystem.IO.FileInfo类他们都提供您正在寻找的方法。

3

你没有解释你想要处理什么样的格式,但不是File.WriteAllText足够吗?

File.WriteAllText("someFile.txt", "some format"); 

对于二进制文件,你可以使用File.WriteAllBytes

File.WriteAllText("someFile.bin", new byte[] { 0x1, 0x2, 0x3 }); 
1

没有什么特别之处的原始API调用。只需获得System.IO.FileStream并在其上调用写入。 (获取FileStream的一种方法是首先获取System.IO.File

+5

实际上,原始的API调用I/O比功能强大得多。例如,Win32函数可以与控制台,命名管道,邮筒,串行端口一起工作(并且可以通过其真实设备名称打开所述串行端口),真正漫长而奇怪的文件名等。但是这些似乎都不适用于此。 – 2010-03-22 17:54:31