Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > .NET > C#.NET > VisualBasic.Net 2003实现NTFS文件附加数据流的读写类
【标  题】:VisualBasic.Net 2003实现NTFS文件附加数据流的读写类
【关键字】:VisualBasic.Net,2003,NTFS
【来  源】:http://blog.csdn.net/jamesjia/archive/2007/02/17/1511364.aspx

VisualBasic.Net 2003实现NTFS文件附加数据流的读写类

Your Ad Here

VisualBasic.Net 2003实现NTFS文件

附加数据流的读写类

中国人民解放军91515部队 贾文博(海南三亚 572016

摘要:NTFSMicrosoft公司开发的一种有着良好安全性和稳定性的高性能文件系统,NTFS的文件或文件夹中附加多个额外的数据流,但是其访问一直没有很好的解决办法,本文使用VB2003实现NTFS文件附加数据流的读写类,提供.Net框架下NTFS文件附加数据流的完整解决方案。

关键词VB.Net NTFS 数据流 类

1        导言

NTFSNew Technology File System)是Microsoft公司开发的一种有着良好安全性和稳定性的高性能文件系统,广泛用于WindowsNTWindows2000WindowsXPWindows2003等操作系统中。为了使NTFS能访问Macintosh文件服务器的HFSHierarchical File System),MicrosoftNTFS中引入了交换数据流ADSAlternate Data Streams),并提供了访问ADS的命令方式和编程APIApplication Programming Interface)。这种机制允许在一个基于NTFS的文件或文件夹中附加多个额外的数据流,但其中只有一个是主数据流(Main Data Stream),其余为附加数据流,每个数据流都可以看作一个独立的文件,其内容可以是任何数据或程序代码,并能通过相应的接口访问,这种访问包括读写和执行。(图1.1

1.1

MSDN中已经演示了一种使用C++MFC访问NTFS文件附加数据流的方法,由于对数据流的访问需要借助API函数,因此到目前为止,尚未有VB.Net程序能够完整地解决操作数据流的问题,为了跨越APIVB.Net的鸿沟,特写了此类访问NTFS文件附加数据流,提供.Net框架下文件附加数据流的完整解决方案。

2        设计方案

NTFS文件附加数据流的访问类,应具有如下功能:

2.1 读取/写入文件的特定数据流、获取其文件流FileStream(流文件名已知)

对流文件访问需要已知流文件的完整文件名,其完整文件名为:

主文件名:流文件名

声明如下:

Dim sFileStreamName As String = FileName & “:” & sStreamName

相对于.Net,获取文件名后我们需要借助于API函数CreateFile()创建流文件的操作句柄,然后串接到FileStream类进行数据的读取,其关键代码如下:

声明CreateFile函数:

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA"

(ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer,     

ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Integer,

ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As Integer) As Integer

获得文件操作句柄:

    Dim hfile As Integer 定义文件操作句柄

    Dim tmpfilename As String = sFileStreamName ‘传递完整流文件名

    hfile = CreateFile(tmpfilename, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)

由文件操作句柄串接至FileStream类:

    Dim sFile As New FileStream(IntPtr.op_Explicit(hfile), FileAccess.ReadWrite)

其中IntPtr.op_Explicit()函数功能是把API文件操作句柄Integer类型转换为.Net文件操作句柄IntPtr类型。串接之后按照.Net下二进制数据的读取方法操作即可。

对文件写入特定数据流方法与读取特定数据流大体相同,把操作属性改为Write即可。(本文后附完整类代码,可参照实现)

2.2 枚举文件所有附加数据流名称

对所有附加数据流名称的枚举需要借助API函数BackupRead()BackupSeek(),具体功能请查阅《Windows API参考手册完全版》,该函数主要用来在磁带机上读取备份。

Function ReadNTFSStreamsName() As String()

     Dim returnNames() As String

      '获取文件操作句柄

     Dim tmpfilename As String = _str_sfilename ‘待枚举流文件名的NTFS文件

     Dim hfile As Integer = CreateFile(tmpfilename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)

     Try

         Dim Sid As New WIN32_STREAM_ID ‘定义流文件头部的格式,此结构后面介绍

         Dim dwStreamHeaderSize As Integer = Marshal.SizeOf(Sid) ‘获得占用字节大小

         Dim lpContext = 0

         Dim bContinue As Boolean = True 执行成功标志

         Dim num As Integer = -1 ‘附加数据流总数

         Dim sum As Integer

循环读取文件数据流名称,直到全部读取完毕

         While (bContinue)

             Dim lRead As Integer = 0

             bContinue = BackupRead(hfile, Sid, dwStreamHeaderSize, lRead, False, False, lpContext)

             If (bContinue AndAlso lRead = dwStreamHeaderSize) Then

                 sum += 1

                 If (Sid.dwStreamNameSize > 0) Then

                     num += 1

                     lRead = 0

获得数据流名称地址

                     Dim pName As Int32 = Marshal.AllocHGlobal(Sid.dwStreamNameSize).ToInt32

                     Try

                         bContinue = BackupRead(hfile, pName, Sid.dwStreamNameSize, lRead, False, False, lpContext)

                         Dim bName(Sid.dwStreamNameSize - 1) As Char

传递地址数据到字符数组bName

                         Marshal.Copy(IntPtr.op_Explicit(pName), bName, 0, Sid.dwStreamNameSize)

                     Dim sName As String = bName

分析数据流名称

                         Dim i As Integer = sName.IndexOf(STREAM_SEP, 1)

                         If (i > -1) Then

                             sName = sName.Substring(1, i - 1)

                         Else

                             i = sName.IndexOf("\0")

                             If (i > -1) Then

                                 sName = sName.Substring(1, i - 1)

                             End If

                         End If

                         ReDim Preserve returnNames(num)

                         returnNames(num) = sName

                     Catch ex As Exception

                         Marshal.FreeHGlobal(IntPtr.op_Explicit(pName)) ‘释放内存

                     End Try

                 End If

                 Dim l As Integer = 0

                 Dim h As Integer = 0

移动读取指针

                 BackupSeek(hfile, Sid.Size.Low, Sid.Size.High, l, h, lpContext)

             Else

                 Exit While

             End If

         End While

     Catch ex As Exception

         MsgBox(Hex(GetLastError()))

     End Try

     CloseHandle(hfile)

     Return returnNames

End Function

2.3 获取指定数据流大小

    Function GetNTFSStreamSize(ByVal sStreamName As String) As Long

        Try

            Dim returnSize As Long

获取文件操作句柄同上

            Dim sFileStreamName As String = FileName & STREAM_SEP & sStreamName

            Dim hfile As Integer

            Dim tmpfilename As String = sFileStreamName

            Try

                hfile = CreateFile(tmpfilename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)

            Catch ex As Exception

                MsgBox(Hex(GetLastError()))

            End Try

            If hfile = INVALID_HANDLE_VALUE Then

                Return Nothing

            End If

            Dim returnStream As FileStream = New FileStream(IntPtr.op_Explicit(hfile), FileAccess.Read)

            returnSize = returnStream.Length

            CloseHandle(hfile)

            Return returnSize

        Catch ex As Exception

            Return -1

        End Try

    End Function

2.4 删除指定数据流

    Function DeleteNTFSStream(ByVal sStreamName As String) As Boolean

        Try

            Dim sFileStreamName As String = FileName & STREAM_SEP & sStreamName

            Dim hfile, fsuccess As Integer

            fsuccess = DeleteFile(sFileStreamName)

       返回0值时删除失败

            If fsuccess <> 0 Then

                Return True

            Else

                MsgBox(Hex(GetLastError()))

            End If

        Catch ex As Exception

            Return False

        End Try

End Function

3        主要困难及解决方法

3.1 API函数和相关数据结构在VB.Net下的声明

3.1.1 文中主要用到的结构声明如下:

    Private Structure WIN32_STREAM_ID ‘流文件头的格式

        Dim dwStreamId As Integer ‘数据流类型

        Dim dwStreamAttributes As Integer ‘数据流属性

        Dim Size As LARGE_INTEGER

        Dim dwStreamNameSize As Integer ‘数据流名称大小

    End Structure

 

    Private Structure LARGE_INTEGER

        Dim Low As Integer

        Dim High As Integer

    End Structure

3.1.2 用到的常数声明如下:

    Private Const STREAM_SEP = ":" ‘数据流名分隔符

    Private Const INVALID_HANDLE_VALUE = -1 ‘文件句柄获取失败

‘CreateFile()函数参数

    Private Const CREATE_NEW = 1

    Private Const CREATE_ALWAYS = 2

    Private Const OPEN_EXISTING = 3

    Private Const OPEN_ALWAYS = 4

    Private Const TRUNCATE_EXISTING = 5

数据流类型,dwStreamId的值(后面的英文说明请参考文献[4]

    Private Const BACKUP_DATA = 1  'Standard data

    Private Const BACKUP_EA_DATA = 2  'Extended attribute data

    Private Const BACKUP_SECURITY_DATA = 3  'Security descriptor data

    Private Const BACKUP_ALTERNATE_DATA = 4  'Alternative data streams

    Private Const BACKUP_LINK = 5  'Hard link information

    Private Const BACKUP_PROPERTY_DATA = 6  'Property data

    Private Const BACKUP_OBJECT_ID = 7  'Objects identifiers

    Private Const BACKUP_REPARSE_DATA = 8  'Reparse points

    Private Const BACKUP_SPARSE_BLOCK = 9  'Sparse file.

文件属性常数

    Private Const FILE_ATTRIBUTE_READONLY = 1

    Private Const FILE_ATTRIBUTE_HIDDEN = 2

    Private Const FILE_ATTRIBUTE_SYSTEM = 4

    Private Const FILE_ATTRIBUTE_ARCHIVE = 32

    Private Const FILE_ATTRIBUTE_NORMAL = 128

    Private Const FILE_ATTRIBUTE_TEMPORARY = 256

文件读写共享常数

    Private Const FILE_NONE_SHARE = 0

    Private Const FILE_SHARE_READ = 1

    Private Const FILE_SHARE_WRITE = 2

其他

    Private Const FILE_FLAG_NO_BUFFERING = &H20000000

    Private Const FILE_FLAG_WRITE_THROUGH = &H80000000

    Private Const GENERIC_READ = &H80000000

Private Const GENERIC_WRITE = &H40000000

3.1.3 API函数声明如下:

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _

     (ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer,      ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As Integer) As Integer

 

Private Declare Function BackupRead Lib "kernel32" Alias "BackupRead" _

     (ByVal hFile As Integer, ByRef lpBuffer As WIN32_STREAM_ID, ByVal nNumberOfBytesToRead As Integer, ByRef lpNumberOfBytesRead As Integer, ByVal bAbort As Boolean, ByVal bProcessSecurity As Boolean, ByRef lpContext As Integer) As Boolean

 

    Private Declare Function BackupRead Lib "kernel32" Alias "BackupRead" _

 (ByVal hFile As Integer, ByVal hName As Integer, ByVal nNumberOfBytesToRead As Integer,          ByRef lpNumberOfBytesRead As Integer, ByVal bAbort As Boolean, ByVal bProcessSecurity As Boolean, ByRef lpContext As Integer) As Boolean

 

    Private Declare Function BackupSeek Lib "kernel32" Alias "BackupSeek" _

     (ByVal hFile As Integer, ByVal dwLowBytesToSeek As Integer, ByVal dwHighBytesToSeek As Integer, ByRef lpdwLowByteSeeked As Integer, ByRef lpdwHighByteSeeked As Integer, ByRef lpContext As Integer) As Boolean

 

Private Declare Function DeleteFile Lib "kernel32" Alias "DeleteFileA" (ByVal lpFileName As String) As Integer

获取API执行失败代码

Private Declare Function GetLastError Lib "kernel32" Alias "GetLastError" () As Integer

    关闭打开的文件

Private Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Integer) As Integer

3.2 .Net框架下不支持对流文件名“FullFilenameStreamname”的直接访问

.Net框架下不支持对含有“:”字符的流文件名进行直接访问,因此必须使用CreateFile()函数取得文件操作句柄hfileinteger)然后通过IntPtr.op_Explicit()函数转化为.Net可操作的文件句柄IntPtr类型,用FileStream Public Sub New(ByVal handle As System.IntPtr, ByVal access As System.IO.FileAccess)重载函数就可以像正常文件一样操作了。

3.3 附加流文件头的处理

定义头格式WIN32_STREAM_ID(参考文献[4])integer类型占位4字节,long类型占位8字节,WIN32_STREAM_ID总共占位20字节,使用BackupRead()函数的两个变形函数读取数据,再结合Marshal类对其中的数据类型进行处理,得到流名称,之后用BackupSeek()移动指针,循环读取文件头,直到枚举出所有附加数据流的名称。

WIN32_STREAM_ID结构中,dwStreamAttributesinteger)说明了该数据流的类型,具体值所代表的数据类型请参考文献[4],本文不再深入探讨。

3.4 读取附加流文件指针的移动

在每次读取流文件名称成功后,必须BackupSeek()移动读取指针,虽然该函数返回执行结果(布尔值),但是实际使用中发现其返回值为False时仍有数据流名称没有被枚举,因此可忽略它的返回值,根据BackupRead()返回值退出循环即可。

4        类的使用方法

在项目中选择添加引用->浏览->选择“JWBStreamOP.dll”文件->确定,即可成功引用。

4.1 类的声明:

Dim myStreamOP As New ClassJWBStreamOP(“NTFS文件完整路径”)

4.2 属性:

该类共有3个只读属性

属性名

返回值类型

备注

FileName

String

只读,在成功声明后使用

Ready

Boolean

只读,该类可操作时为True

Ver

String

只读,类版本、版权信息

4.3 方法

该类共有6个方法:

4.3.1 OpenNTFSStream(ByVal sStreamName As String) As System.IO.FileStream 打开指定文件(声明时指定)的指定数据流,返回值为指定数据流的FileStream接口。