C#类用于恢复已删除的文件?

15

可能是重复问题:
如何使用C#从回收站还原文件?
在Windows上恢复已删除的文件

我正在开发一个应用程序,旨在从系统中恢复已删除的文件(包括回收站中的文件和已经清空回收站但仍可理解的文件)以及格式化的驱动器。我选择了C#作为编程语言,但我找不到处理这个问题的类。有人知道任何查找已删除文件、检索它们或有关此事的教程或帮助的类/方法吗?我对这个主题的经验很少,所以任何帮助都将受到高度赞赏。


1
我的猜测是,您最终将得到一个带有命令行界面的许多未删除应用程序之一。 - CodingBarfield
我不确定C#是否能够做到这一点,因为您可能需要使用一些低级API从特定位置读取磁盘数据。您可能需要使用C或C++来完成这个任务。 - oleksii
2
@kev,他们有一个非常酷的图形用户界面并不意味着他们使用了C#。 - Orentet
1个回答

49

没有内置的类可以完成您所要求的操作

实际上,恢复已删除的文件是一个很难的过程,需要对您的文件系统有非常低级别的了解。因此,首先要做的是获取包含您想要恢复的文件的驱动器的信息。基本上,您首先需要知道它的文件系统。

您将需要大量使用P/Invoke。首先获取到您要定位的驱动器的句柄:

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

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

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GetVolumeInformationByHandleW(
    IntPtr hDisk,
    StringBuilder volumeNameBuffer,
    int volumeNameSize,
    ref uint volumeSerialNumber,
    ref uint maximumComponentLength,
    ref uint fileSystemFlags,
    StringBuilder fileSystemNameBuffer,
    int nFileSystemNameSize);

// Gets a handle to the drive
// Note: use CloseHandle to close the handle you opened once work is done
IntPtr hDrive = NativeMethods.CreateFile(
    string.Format("\\\\.\\{0}:", DriveLetter)
    GenericRead,
    Read | Write,
    IntPtr.Zero,
    OpenExisting,
    0,
    IntPtr.Zero);

// Then gets some information about the drive
// The following function requires Vista+
// Use GetVolumeInformation for older systems
const int VolumeNameSize = 255;
const int FileSystemNameBufferSize = 255;
StringBuilder volumeNameBuffer = new StringBuilder(VolumeNameSize);
uint volumeSerialNumber = 0;
uint maximumComponentLength = 0;
uint fileSystemFeatures;
StringBuilder fileSystemNameBuffer = new StringBuilder(FileSystemNameBufferSize);

GetVolumeInformationByHandleW(
    hDrive,
    volumeNameBuffer,
    VolumeNameSize,
    ref volumeSerialNumber,
    ref maximumComponentLength,
    ref fileSystemFeatures,
    fileSystemNameBuffer,
    FileSystemNameBufferSize);

// Now you know the file system of your drive
// NTFS or FAT16 or UDF for instance
string FileSystemName = fileSystemNameBuffer.ToString();

一旦您获得了文件系统的名称,就需要手动从驱动器中读取原始数据。您将完全根据驱动器的文件系统来读取数据。无论如何,您都需要获取与硬盘相关联的句柄:
// Gets a handle to the physical disk
IntPtr hDisk = CreateFile(string.Format("\\\\.\\PhysicalDrive{0}", diskNumber),
    GenericRead,
    Read | Write,
    0,
    OpenExisting,
    0,
    IntPtr.Zero);

现在你需要了解很多关于文件系统的知识......对于NTFS文件系统,你需要了解主文件表的概念。实际上,这相当困难。对于FAT文件系统来说,那就不那么复杂了,但你仍需要花一些时间学习该文件系统。可以从维基百科开始。
使用CreateFile获取的句柄,您现在将通过使用ReadFile逐字节(实际上是逐扇区)读取磁盘上的信息以获得所需信息。
// Used to read in a file
[DllImport("kernel32.dll")]
public static extern bool ReadFile(
    IntPtr hFile,
    byte[] lpBuffer,
    uint nNumberOfBytesToRead,
    ref uint lpNumberOfBytesRead,
    IntPtr lpOverlapped);

// Used to set the offset in file to start reading
[DllImport("kernel32.dll")]
public static extern bool SetFilePointerEx(
    IntPtr hFile,
    long liDistanceToMove,
    ref long lpNewFilePointer,
    uint dwMoveMethod);

// Set offset
int bufferSize = 512;
byte[] buffer = new byte[bufferSize];
SetFilePointerEx(
    hDisk,
    offset,
    ref pt,
    FileBegin);

// Read a whole sector
// Note that you can't read less than a whole sector of your physical disk. Usually it's 512 bytes,
// but you'll have to retrieve this information from the disk geometry. If you're interested, I can provide you
// some code. It requires the use of the IOCTL_DISK_GET_DRIVE_GEOMETRY control code.
uint read = 0;
ReadFile(
    hDisk,
    buffer,
    bufferSize,
    ref read,
    IntPtr.Zero);

对于NTFS,首先需要获取MFT的起始扇区...然后你将不得不“解析”MFT并查找已删除的文件...
我不会在这里解释整个过程。请参见此链接进行示例。
所以祝你好运 :)
现在,您可能想要使用第三方应用程序,它已经完成了所有这些操作,并从自己的程序中使用它(如评论中所述的命令行工具)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接