http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/ntfs5.asp
这篇文章早在两年前,我高一的时候就读过,那时懵懵懂懂的,看了也不明白。两年以后重读,感悟很多,便用 C# 实现了一个对 NTFS 命名流访问的程序。以下是核心代码,注释来不及写了,自己看看吧。
再有两天就高考了,祝我好运吧。
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
namespace MultiFileStream
{
/// <summary>
/// NamedStreamDataHandler 指定一个 NTFS 文件及文件流并提供对该文件流的访问。
/// </summary>
public class NamedStreamDataHandler
{
#region 常量声明
const uint GENERIC_READ = 0x80000000;
const uint OPEN_EXISTING = 3;
const uint CREATE_NEW = 1;
const uint CREATE_ALWAYS = 2;
const uint GENERIC_WRITE = 0x40000000;
const string L_InvalidFile = "文件系统无效或文件路径无效。";
const char STREAM_SEP = ':';
#endregion
#region 变量声明
private string m_FileName;
private string m_StreamName;
private byte[] m_StreamData=null;
#endregion
#region Win32 API 所必须的数据结构
/// <summary>
/// 用于 BackupRead 的 WIN32_STREAM_ID 结构。
/// </summary>
[StructLayout(LayoutKind.Sequential)] public struct WIN32_STREAM_ID
{
public int dwStreamID;
public int dwStreamAttributes;
public LARGE_INTEGER Size;
public int dwStreamNameSize;
}
/// <summary>
/// 用于 WIN32_STREAM_ID 的 LARGE_INTEGER 结构
/// </summary>
[StructLayout(LayoutKind.Sequential)] public struct LARGE_INTEGER
{
public int Low;
public int High;
public long ToInt64()
{
return (long)High * 4294967296 + (long)Low;
}
}
#endregion
#region Win32 API 声明
[DllImport("kernel32.dll", SetLastError=true)]
private static extern IntPtr CreateFile(
string FileName, // file name
uint DesiredAccess, // access mode
uint ShareMode, // share mode
uint SecurityAttributes, // Security Attributes
uint CreationDisposition, // how to create
uint FlagsAndAttributes, // file attributes
int hTemplateFile // handle to template file
);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool CloseHandle(
IntPtr hObject // handle to object
);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool DeleteFile(
string lpFileName
);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool BackupRead(
IntPtr handle,
IntPtr pBuffer,
int lBytes,
ref int lRead,
bool bAbort,
bool bSecurity,
ref int Context);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool BackupRead(
IntPtr handle,
ref WIN32_STREAM_ID pBuffer,
int lBytes,
ref int lRead,
bool bAbort,
bool bSecurity,
ref int Context);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern bool BackupSeek(
IntPtr handle,
int dwLowBytesToSeek,
int dwHighBytesToSeek,
ref int dwLow,
ref int dwHigh,
ref int Context);
[DllImport("kernel32.dll", SetLastError=true)]
private static extern int GetLastError();
#endregion
#region NamedStreamDataHandler 类的构造函数
/// <summary>
/// 初始化 NamedStreamDataHandler 类的新实例。
/// </summary>
/// <param name="FileName">目标文件完整路径名称</param>
/// <param name="StreamName">目标文件流名称</param>
public NamedStreamDataHandler(string FileName,string StreamName)
{
//
// TODO: 在此处添加构造函数逻辑
//
m_FileName = FileName;
m_StreamName = StreamName;
}
/// <summary>
/// 初始化 NamedStreamDataHandler 类的新实例。
/// </summary>
/// <param name="FileName">目标文件完整路径名称</param>
public NamedStreamDataHandler(string FileName)
{
m_FileName = FileName;
}
/// <summary>
/// 初始化 NamedStreamDataHandler 类的新实例。
/// </summary>
public NamedStreamDataHandler()
{
}
#endregion
#region 对文件及文件流的基本访问字段成员
/// <summary>
/// 获取或设置目标文件的完整路径名称。
/// </summary>
public string FileName
{
get{return m_FileName;}
set{m_FileName = value;}
}
/// <summary>
/// 获取或设置目标文件的文件流名称。
/// </summary>
public string StreamName
{
get{return m_StreamName;}
set{m_StreamName = value;}
}
/// <summary>
/// 获取或设置写入命名流的数据。
/// </summary>
public byte[] StreamData
{
get
{return m_StreamData;}
set
{m_StreamData=value;}
}
#endregion
#region NamedStreamDataHandler 类的方法成员
/// <summary>
/// 清理所有资源。
/// </summary>
public void Close()
{
//throw new NotImplementedException();
this.Dispose();
}
/// <summary>
/// 将数据写入目标命名流。
/// </summary>
/// <param name="StreamData">需要写入的数据</param>
public void WriteStreamData(byte[] StreamData)
{
m_StreamData=StreamData;
IntPtr handle = CreateFile(m_FileName+":"+m_StreamName,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
if(handle==IntPtr.Zero)
throw new Exception(L_InvalidFile);
using(FileStream fs = new FileStream(handle,FileAccess.ReadWrite))
{
fs.Write(m_StreamData,0,m_StreamData.Length);
fs.Close();
}
}
/// <summary>
/// 读取指定命名流的数据。
/// </summary>
/// <param name="StreamData">将被写入读取数据的缓冲区</param>
public void ReadStreamData(ref byte[] StreamData)
{
IntPtr handle = CreateFile(m_FileName+":"+m_StreamName,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
if(handle==IntPtr.Zero)
throw new Exception(L_InvalidFile);
using(FileStream fs = new FileStream(handle,FileAccess.ReadWrite))
{
m_StreamData = new Byte[fs.Length];
fs.Read(m_StreamData,0,(int)fs.Length);
fs.Close();
StreamData=m_StreamData;
}
}
/// <summary>
/// 枚举当前文件的所有命名流。
/// </summary>
/// <returns></returns>
public ArrayList EnumNamedStream()
{
ArrayList arr=new ArrayList();
IntPtr handle = CreateFile(m_FileName,GENERIC_READ,0,0,OPEN_EXISTING,0,0);
if (handle ==IntPtr.Zero) return arr;
try
{
WIN32_STREAM_ID sid = new WIN32_STREAM_ID();
int dwStreamHeaderSize = Marshal.SizeOf(sid);
int Context = 0;
bool Continue = true;
while (Continue)
{
int lRead = 0;
Continue = BackupRead(handle, ref sid, dwStreamHeaderSize, ref lRead, false, false, ref Context);
if (Continue && lRead == dwStreamHeaderSize)
{
if (sid.dwStreamNameSize>0)
{
lRead = 0;
IntPtr pName = Marshal.AllocHGlobal(sid.dwStreamNameSize);
try
{
Continue = BackupRead(handle, pName, sid.dwStreamNameSize, ref lRead, false, false, ref Context);
char[] bName = new char[sid.dwStreamNameSize];
Marshal.Copy(pName,bName,0,sid.dwStreamNameSize);
string sName = new string(bName);
int i = sName.IndexOf(STREAM_SEP, 1);
if (i>-1) sName = sName.Substring(1, i-1);
else
{
i = sName.IndexOf('\0');
if (i>-1) sName = sName.Substring(1, i-1);
}
arr.Add(sName);
}
finally
{
Marshal.FreeHGlobal(pName);
}
}
int l = 0; int h = 0;
Continue = BackupSeek(handle, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context);
}
else break;
}
}
finally
{
CloseHandle(handle);
}
return arr;
}
/// <summary>
/// 删除指定流。
/// </summary>
public void DeleteStream()
{
if(DeleteFile(m_FileName+":"+m_StreamName)==false)
throw new Exception(L_InvalidFile);
}
#endregion
}
}