gpt4 book ai didi

c# - 将字节插入文件中间(在 Windows 文件系统中)而不读取整个文件(使用文件分配表)?

转载 作者:IT王子 更新时间:2023-10-29 04:12:56 24 4
gpt4 key购买 nike

我需要一种方法将一些文件簇插入到文件中间以插入一些数据。

通常情况下,我会读取整个文件,然后将更改后的文件重新写回,但这些文件的大小为数 GB,仅读取文件并重新写回就需要 30 分钟。

簇的大小并不困扰我;我基本上可以将零写到插入的簇的末尾,并且它仍然可以以这种文件格式工作。

我如何使用 Windows 文件 API(或其他一些机制)修改文件的文件分配表,在文件中间的指定点插入一个或多个未使用的簇?

最佳答案

[编辑:]

废话 - 我要说“这是不可行的,至少不能通过 MFT 修改,没有很多痛苦”;首先,NTFS MFT 结构本身并不是 100%“开放”的,所以我开始深入研究逆向工程领域,这会产生法律后果,我没有心情去处理。此外,在 .NET 中执行此操作是一个基于大量猜测的映射和编码结构的 super 繁琐过程(并且不要让我开始了解大多数 MFT 结构以奇怪的方式压缩的事实)。简而言之,虽然我确实学到了很多关于 NTFS 如何“工作”的知识,但我离解决这个问题还差得很远。

[/编辑]

呃...编码废话太多....

这让我觉得“很有趣”,因此我不得不四处寻找这个问题......它仍然是一个“正在进行的答案”,但我想发布所有我必须帮助其他人提出的问题与某事。 :)

此外,我有一个粗略的感觉,这在 FAT32 上会容易得多,但考虑到我只能使用 NTFS...

所以 - 很多 pinvoking 和编码,所以让我们从那里开始并向后工作:

正如人们可能猜到的那样,标准的 .NET 文件/IO api 在这里不会对您有太大帮助 - 我们需要设备级访问权限:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern SafeFileHandle CreateFile(
string lpFileName,
[MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
[MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
IntPtr lpSecurityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool ReadFile(
SafeFileHandle hFile, // handle to file
byte[] pBuffer, // data buffer, should be fixed
int NumberOfBytesToRead, // number of bytes to read
IntPtr pNumberOfBytesRead, // number of bytes read, provide NULL here
ref NativeOverlapped lpOverlapped // should be fixed, if not null
);

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool SetFilePointerEx(
SafeFileHandle hFile,
long liDistanceToMove,
out long lpNewFilePointer,
SeekOrigin dwMoveMethod);

我们将这样使用这些讨厌的 win32 野兽:

// To the metal, baby!
using (var fileHandle = NativeMethods.CreateFile(
// Magic "give me the device" syntax
@"\\.\c:",
// MUST explicitly provide both of these, not ReadWrite
FileAccess.Read | FileAccess.Write,
// MUST explicitly provide both of these, not ReadWrite
FileShare.Write | FileShare.Read,
IntPtr.Zero,
FileMode.Open,
FileAttributes.Normal,
IntPtr.Zero))
{
if (fileHandle.IsInvalid)
{
// Doh!
throw new Win32Exception();
}
else
{
// Boot sector ~ 512 bytes long
byte[] buffer = new byte[512];
NativeOverlapped overlapped = new NativeOverlapped();
NativeMethods.ReadFile(fileHandle, buffer, buffer.Length, IntPtr.Zero, ref overlapped);

// Pin it so we can transmogrify it into a FAT structure
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
// note, I've got an NTFS drive, change yours to suit
var bootSector = (BootSector_NTFS)Marshal.PtrToStructure(
handle.AddrOfPinnedObject(),
typeof(BootSector_NTFS));

哇,哇哇 - BootSector_NTFS 到底是什么东西?它是一个字节映射的 struct,我认为它最接近 NTFS 结构的样子(也包括 FAT32):

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=0)]
public struct JumpBoot
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.U1, SizeConst=3)]
public byte[] BS_jmpBoot;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
public string BS_OEMName;
}

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 0, Size = 90)]
public struct BootSector_NTFS
{
[FieldOffset(0)]
public JumpBoot JumpBoot;
[FieldOffset(0xb)]
public short BytesPerSector;
[FieldOffset(0xd)]
public byte SectorsPerCluster;
[FieldOffset(0xe)]
public short ReservedSectorCount;
[FieldOffset(0x10)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] Reserved0_MUSTBEZEROs;
[FieldOffset(0x15)]
public byte BPB_Media;
[FieldOffset(0x16)]
public short Reserved1_MUSTBEZERO;
[FieldOffset(0x18)]
public short SectorsPerTrack;
[FieldOffset(0x1A)]
public short HeadCount;
[FieldOffset(0x1c)]
public int HiddenSectorCount;
[FieldOffset(0x20)]
public int LargeSectors;
[FieldOffset(0x24)]
public int Reserved6;
[FieldOffset(0x28)]
public long TotalSectors;
[FieldOffset(0x30)]
public long MftClusterNumber;
[FieldOffset(0x38)]
public long MftMirrorClusterNumber;
[FieldOffset(0x40)]
public byte ClustersPerMftRecord;
[FieldOffset(0x41)]
public byte Reserved7;
[FieldOffset(0x42)]
public short Reserved8;
[FieldOffset(0x44)]
public byte ClustersPerIndexBuffer;
[FieldOffset(0x45)]
public byte Reserved9;
[FieldOffset(0x46)]
public short ReservedA;
[FieldOffset(0x48)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] SerialNumber;
[FieldOffset(0x50)]
public int Checksum;
[FieldOffset(0x54)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1AA)]
public byte[] BootupCode;
[FieldOffset(0x1FE)]
public ushort EndOfSectorMarker;

public long GetMftAbsoluteIndex(int recordIndex = 0)
{
return (BytesPerSector * SectorsPerCluster * MftClusterNumber) + (GetMftEntrySize() * recordIndex);
}
public long GetMftEntrySize()
{
return (BytesPerSector * SectorsPerCluster * ClustersPerMftRecord);
}
}


// Note: dont have fat32, so can't verify all these...they *should* work, tho
// refs:
// http://www.pjrc.com/tech/8051/ide/fat32.html
// http://msdn.microsoft.com/en-US/windows/hardware/gg463084
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Auto, Pack=0, Size=90)]
public struct BootSector_FAT32
{
[FieldOffset(0)]
public JumpBoot JumpBoot;
[FieldOffset(11)]
public short BPB_BytsPerSec;
[FieldOffset(13)]
public byte BPB_SecPerClus;
[FieldOffset(14)]
public short BPB_RsvdSecCnt;
[FieldOffset(16)]
public byte BPB_NumFATs;
[FieldOffset(17)]
public short BPB_RootEntCnt;
[FieldOffset(19)]
public short BPB_TotSec16;
[FieldOffset(21)]
public byte BPB_Media;
[FieldOffset(22)]
public short BPB_FATSz16;
[FieldOffset(24)]
public short BPB_SecPerTrk;
[FieldOffset(26)]
public short BPB_NumHeads;
[FieldOffset(28)]
public int BPB_HiddSec;
[FieldOffset(32)]
public int BPB_TotSec32;
[FieldOffset(36)]
public FAT32 FAT;
}

[StructLayout(LayoutKind.Sequential)]
public struct FAT32
{
public int BPB_FATSz32;
public short BPB_ExtFlags;
public short BPB_FSVer;
public int BPB_RootClus;
public short BPB_FSInfo;
public short BPB_BkBootSec;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
public byte[] BPB_Reserved;
public byte BS_DrvNum;
public byte BS_Reserved1;
public byte BS_BootSig;
public int BS_VolID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=11)]
public string BS_VolLab;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)]
public string BS_FilSysType;
}

所以现在我们可以将整个乱七八糟的字节映射回这个结构:

// Pin it so we can transmogrify it into a FAT structure
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
// note, I've got an NTFS drive, change yours to suit
var bootSector = (BootSector_NTFS)Marshal.PtrToStructure(
handle.AddrOfPinnedObject(),
typeof(BootSector_NTFS));
Console.WriteLine(
"I think that the Master File Table is at absolute position:{0}, sector:{1}",
bootSector.GetMftAbsoluteIndex(),
bootSector.GetMftAbsoluteIndex() / bootSector.BytesPerSector);

此时输出:

I think that the Master File Table is at 
absolute position:3221225472, sector:6291456

让我们确认快速使用 OEM 支持工具 nfi.exe:

C:\tools\OEMTools\nfi>nfi c:
NTFS File Sector Information Utility.
Copyright (C) Microsoft Corporation 1999. All rights reserved.


File 0
Master File Table ($Mft)
$STANDARD_INFORMATION (resident)
$FILE_NAME (resident)
$DATA (nonresident)
logical sectors 6291456-6487039 (0x600000-0x62fbff)
logical sectors 366267960-369153591 (0x15d4ce38-0x1600d637)
$BITMAP (nonresident)
logical sectors 6291448-6291455 (0x5ffff8-0x5fffff)
logical sectors 7273984-7274367 (0x6efe00-0x6eff7f)

太棒了,看起来我们走在正确的轨道上……继续前进!

            // If you've got LinqPad, uncomment this to look at boot sector
bootSector.Dump();

Console.WriteLine("Jumping to Master File Table...");
long lpNewFilePointer;
if (!NativeMethods.SetFilePointerEx(
fileHandle,
bootSector.GetMftAbsoluteIndex(),
out lpNewFilePointer,
SeekOrigin.Begin))
{
throw new Win32Exception();
}
Console.WriteLine("Position now: {0}", lpNewFilePointer);

// Read in one MFT entry
byte[] mft_buffer = new byte[bootSector.GetMftEntrySize()];
Console.WriteLine("Reading $MFT entry...calculated size: 0x{0}",
bootSector.GetMftEntrySize().ToString("X"));

var seekIndex = bootSector.GetMftAbsoluteIndex();
overlapped.OffsetHigh = (int)(seekIndex >> 32);
overlapped.OffsetLow = (int)seekIndex;
NativeMethods.ReadFile(
fileHandle,
mft_buffer,
mft_buffer.Length,
IntPtr.Zero,
ref overlapped);
// Pin it for transmogrification
var mft_handle = GCHandle.Alloc(mft_buffer, GCHandleType.Pinned);
try
{
var mftRecords = (MFTSystemRecords)Marshal.PtrToStructure(
mft_handle.AddrOfPinnedObject(),
typeof(MFTSystemRecords));
mftRecords.Dump();
}
finally
{
// make sure we clean up
mft_handle.Free();
}
}
finally
{
// make sure we clean up
handle.Free();
}

啊,要讨论更多的原生结构——所以 MFT 的安排使得前 16 个左右的条目是“固定的”:

[StructLayout(LayoutKind.Sequential)]
public struct MFTSystemRecords
{
public MFTRecord Mft;
public MFTRecord MftMirror;
public MFTRecord LogFile;
public MFTRecord Volume;
public MFTRecord AttributeDefs;
public MFTRecord RootFile;
public MFTRecord ClusterBitmap;
public MFTRecord BootSector;
public MFTRecord BadClusterFile;
public MFTRecord SecurityFile;
public MFTRecord UpcaseTable;
public MFTRecord ExtensionFile;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public MFTRecord[] MftReserved;
public MFTRecord MftFileExt;
}

MFTRecord 是:

[StructLayout(LayoutKind.Sequential, Size = 1024)]
public struct MFTRecord
{
const int BASE_RECORD_SIZE = 48;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
public string Type;
public short UsaOffset;
public short UsaCount;
public long Lsn; /* $LogFile sequence number for this record. Changed every time the record is modified. */
public short SequenceNumber; /* # of times this record has been reused */
public short LinkCount; /* Number of hard links, i.e. the number of directory entries referencing this record. */
public short AttributeOffset; /* Byte offset to the first attribute in this mft record from the start of the mft record. */
public short MftRecordFlags;
public int BytesInUse;
public int BytesAllocated;
public long BaseFileRecord;
public short NextAttributeNumber;
public short Reserved;
public int MftRecordNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 976)]
public byte[] Data;
public byte[] SetData
{
get
{
return this.Data
.Skip(AttributeOffset - BASE_RECORD_SIZE)
.Take(BytesInUse - BASE_RECORD_SIZE)
.ToArray();
}
}
public MftAttribute[] Attributes
{
get
{
var idx = 0;
var ret = new List<MftAttribute>();
while (idx < SetData.Length)
{
var attr = MftAttribute.FromBytes(SetData.Skip(idx).ToArray());
ret.Add(attr);
idx += attr.Attribute.Length;
// A special "END" attribute denotes the end of the list
if (attr.Attribute.AttributeType == MftAttributeType.AT_END) break;
}
return ret.ToArray();
}
}
}

还有...这是我暂时停止的地方;主要是因为我想吃晚饭之类的。不过,我会回到这个问题上的!

引用资料(一部分是为了自己的内存,一部分是为了帮助其他调查人员)

完整代码转储如下:

我在上面显示的所有原生映射(由于帖子大小限制,不是完全重新哈希):

public enum MftRecordFlags : ushort
{
MFT_RECORD_IN_USE = 0x0001,
MFT_RECORD_IS_DIRECTORY = 0x0002,
MFT_RECORD_IN_EXTEND = 0x0004,
MFT_RECORD_IS_VIEW_INDEX = 0x0008,
MFT_REC_SPACE_FILLER = 0xffff
}
public enum MftAttributeType : uint
{
AT_UNUSED = 0,
AT_STANDARD_INFORMATION = 0x10,
AT_ATTRIBUTE_LIST = 0x20,
AT_FILENAME = 0x30,
AT_OBJECT_ID = 0x40,
AT_SECURITY_DESCRIPTOR = 0x50,
AT_VOLUME_NAME = 0x60,
AT_VOLUME_INFORMATION = 0x70,
AT_DATA = 0x80,
AT_INDEX_ROOT = 0x90,
AT_INDEX_ALLOCATION = 0xa0,
AT_BITMAP = 0xb0,
AT_REPARSE_POINT = 0xc0,
AT_EA_INFORMATION = 0xd0,
AT_EA = 0xe0,
AT_PROPERTY_SET = 0xf0,
AT_LOGGED_UTILITY_STREAM = 0x100,
AT_FIRST_USER_DEFINED_ATTRIBUTE = 0x1000,
AT_END = 0xffffffff
}

public enum MftAttributeDefFlags : byte
{
ATTR_DEF_INDEXABLE = 0x02, /* Attribute can be indexed. */
ATTR_DEF_MULTIPLE = 0x04, /* Attribute type can be present multiple times in the mft records of an inode. */
ATTR_DEF_NOT_ZERO = 0x08, /* Attribute value must contain at least one non-zero byte. */
ATTR_DEF_INDEXED_UNIQUE = 0x10, /* Attribute must be indexed and the attribute value must be unique for the attribute type in all of the mft records of an inode. */
ATTR_DEF_NAMED_UNIQUE = 0x20, /* Attribute must be named and the name must be unique for the attribute type in all of the mft records of an inode. */
ATTR_DEF_RESIDENT = 0x40, /* Attribute must be resident. */
ATTR_DEF_ALWAYS_LOG = 0x80, /* Always log modifications to this attribute, regardless of whether it is resident or
non-resident. Without this, only log modifications if the attribute is resident. */
}

[StructLayout(LayoutKind.Explicit)]
public struct MftInternalAttribute
{
[FieldOffset(0)]
public MftAttributeType AttributeType;
[FieldOffset(4)]
public int Length;
[FieldOffset(8)]
[MarshalAs(UnmanagedType.Bool)]
public bool NonResident;
[FieldOffset(9)]
public byte NameLength;
[FieldOffset(10)]
public short NameOffset;
[FieldOffset(12)]
public int AttributeFlags;
[FieldOffset(14)]
public short Instance;
[FieldOffset(16)]
public ResidentAttribute ResidentAttribute;
[FieldOffset(16)]
public NonResidentAttribute NonResidentAttribute;
}

[StructLayout(LayoutKind.Sequential)]
public struct ResidentAttribute
{
public int ValueLength;
public short ValueOffset;
public byte ResidentAttributeFlags;
public byte Reserved;

public override string ToString()
{
return string.Format("{0}:{1}:{2}:{3}", ValueLength, ValueOffset, ResidentAttributeFlags, Reserved);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct NonResidentAttribute
{
public long LowestVcn;
public long HighestVcn;
public short MappingPairsOffset;
public byte CompressionUnit;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] Reserved;
public long AllocatedSize;
public long DataSize;
public long InitializedSize;
public long CompressedSize;
public override string ToString()
{
return string.Format("{0}:{1}:{2}:{3}:{4}:{5}:{6}:{7}", LowestVcn, HighestVcn, MappingPairsOffset, CompressionUnit, AllocatedSize, DataSize, InitializedSize, CompressedSize);
}
}

public struct MftAttribute
{
public MftInternalAttribute Attribute;

[field: NonSerialized]
public string Name;

[field: NonSerialized]
public byte[] Data;

[field: NonSerialized]
public object Payload;

public static MftAttribute FromBytes(byte[] buffer)
{
var hnd = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
var attr = (MftInternalAttribute)Marshal.PtrToStructure(hnd.AddrOfPinnedObject(), typeof(MftInternalAttribute));
var ret = new MftAttribute() { Attribute = attr };
ret.Data = buffer.Skip(Marshal.SizeOf(attr)).Take(attr.Length).ToArray();
if (ret.Attribute.AttributeType == MftAttributeType.AT_STANDARD_INFORMATION)
{
var payloadHnd = GCHandle.Alloc(ret.Data, GCHandleType.Pinned);
try
{
var payload = (MftStandardInformation)Marshal.PtrToStructure(payloadHnd.AddrOfPinnedObject(), typeof(MftStandardInformation));
ret.Payload = payload;
}
finally
{
payloadHnd.Free();
}
}
return ret;
}
finally
{
hnd.Free();
}
}
}

[StructLayout(LayoutKind.Sequential)]
public struct MftStandardInformation
{
public ulong CreationTime;
public ulong LastDataChangeTime;
public ulong LastMftChangeTime;
public ulong LastAccessTime;
public int FileAttributes;
public int MaximumVersions;
public int VersionNumber;
public int ClassId;
public int OwnerId;
public int SecurityId;
public long QuotaChanged;
public long Usn;
}

// Note: dont have fat32, so can't verify all these...they *should* work, tho
// refs:
// http://www.pjrc.com/tech/8051/ide/fat32.html
// http://msdn.microsoft.com/en-US/windows/hardware/gg463084
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Auto, Pack = 0, Size = 90)]
public struct BootSector_FAT32
{
[FieldOffset(0)]
public JumpBoot JumpBoot;
[FieldOffset(11)]
public short BPB_BytsPerSec;
[FieldOffset(13)]
public byte BPB_SecPerClus;
[FieldOffset(14)]
public short BPB_RsvdSecCnt;
[FieldOffset(16)]
public byte BPB_NumFATs;
[FieldOffset(17)]
public short BPB_RootEntCnt;
[FieldOffset(19)]
public short BPB_TotSec16;
[FieldOffset(21)]
public byte BPB_Media;
[FieldOffset(22)]
public short BPB_FATSz16;
[FieldOffset(24)]
public short BPB_SecPerTrk;
[FieldOffset(26)]
public short BPB_NumHeads;
[FieldOffset(28)]
public int BPB_HiddSec;
[FieldOffset(32)]
public int BPB_TotSec32;
[FieldOffset(36)]
public FAT32 FAT;
}

[StructLayout(LayoutKind.Sequential)]
public struct FAT32
{
public int BPB_FATSz32;
public short BPB_ExtFlags;
public short BPB_FSVer;
public int BPB_RootClus;
public short BPB_FSInfo;
public short BPB_BkBootSec;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] BPB_Reserved;
public byte BS_DrvNum;
public byte BS_Reserved1;
public byte BS_BootSig;
public int BS_VolID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string BS_VolLab;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string BS_FilSysType;
}

和测试工具:

class Program
{
static void Main(string[] args)
{
// To the metal, baby!
using (var fileHandle = NativeMethods.CreateFile(
// Magic "give me the device" syntax
@"\\.\c:",
// MUST explicitly provide both of these, not ReadWrite
FileAccess.Read | FileAccess.Write,
// MUST explicitly provide both of these, not ReadWrite
FileShare.Write | FileShare.Read,
IntPtr.Zero,
FileMode.Open,
FileAttributes.Normal,
IntPtr.Zero))
{
if (fileHandle.IsInvalid)
{
// Doh!
throw new Win32Exception();
}
else
{
// Boot sector ~ 512 bytes long
byte[] buffer = new byte[512];
NativeOverlapped overlapped = new NativeOverlapped();
NativeMethods.ReadFile(fileHandle, buffer, buffer.Length, IntPtr.Zero, ref overlapped);

// Pin it so we can transmogrify it into a FAT structure
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
// note, I've got an NTFS drive, change yours to suit
var bootSector = (BootSector_NTFS)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(BootSector_NTFS));
Console.WriteLine(
"I think that the Master File Table is at absolute position:{0}, sector:{1}",
bootSector.GetMftAbsoluteIndex(),
bootSector.GetMftAbsoluteIndex() / bootSector.BytesPerSector);
Console.WriteLine("MFT record size:{0}", bootSector.ClustersPerMftRecord * bootSector.SectorsPerCluster * bootSector.BytesPerSector);

// If you've got LinqPad, uncomment this to look at boot sector
bootSector.DumpToHtmlString();

Pause();

Console.WriteLine("Jumping to Master File Table...");
long lpNewFilePointer;
if (!NativeMethods.SetFilePointerEx(fileHandle, bootSector.GetMftAbsoluteIndex(), out lpNewFilePointer, SeekOrigin.Begin))
{
throw new Win32Exception();
}
Console.WriteLine("Position now: {0}", lpNewFilePointer);

// Read in one MFT entry
byte[] mft_buffer = new byte[bootSector.GetMftEntrySize()];
Console.WriteLine("Reading $MFT entry...calculated size: 0x{0}", bootSector.GetMftEntrySize().ToString("X"));

var seekIndex = bootSector.GetMftAbsoluteIndex();
overlapped.OffsetHigh = (int)(seekIndex >> 32);
overlapped.OffsetLow = (int)seekIndex;
NativeMethods.ReadFile(fileHandle, mft_buffer, mft_buffer.Length, IntPtr.Zero, ref overlapped);
// Pin it for transmogrification
var mft_handle = GCHandle.Alloc(mft_buffer, GCHandleType.Pinned);
try
{
var mftRecords = (MFTSystemRecords)Marshal.PtrToStructure(mft_handle.AddrOfPinnedObject(), typeof(MFTSystemRecords));
mftRecords.DumpToHtmlString();
}
finally
{
// make sure we clean up
mft_handle.Free();
}
}
finally
{
// make sure we clean up
handle.Free();
}
}
}
Pause();
}

private static void Pause()
{
Console.WriteLine("Press enter to continue...");
Console.ReadLine();
}
}


public static class Dumper
{
public static string DumpToHtmlString<T>(this T objectToSerialize)
{
string strHTML = "";
try
{
var writer = LINQPad.Util.CreateXhtmlWriter(true);
writer.Write(objectToSerialize);
strHTML = writer.ToString();
}
catch (Exception exc)
{
Debug.Assert(false, "Investigate why ?" + exc);
}

var shower = new Thread(
() =>
{
var dumpWin = new Window();
var browser = new WebBrowser();
dumpWin.Content = browser;
browser.NavigateToString(strHTML);
dumpWin.ShowDialog();
});
shower.SetApartmentState(ApartmentState.STA);
shower.Start();
return strHTML;
}

public static string Dump(this object value)
{
return JsonConvert.SerializeObject(value, Formatting.Indented);
}
}

关于c# - 将字节插入文件中间(在 Windows 文件系统中)而不读取整个文件(使用文件分配表)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13430210/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com