14

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

我正在开发一个应用程序,该应用程序旨在从系统中恢复已删除的文件(包括回收站中的文件和已从回收站中清空但仍然可以理解的文件)和格式化的驱动器。我决定使用 c# 作为语言,但是我很难找到处理这个问题的类。有谁知道查找已删除文件、检索它们的任何类/方法或任何教程或有关此事的帮助。我在这方面的经验很少,因此我们将不胜感激任何帮助。

4

1 回答 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 文件系统,您必须了解Master File Table的概念。其实,这还挺难的。对于 FAT 文件系统,这不那么复杂,但您仍然需要研究 FS 一段时间。从维基百科开始。

从您使用的句柄中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 并查找已删除的文件……

我不会在这里解释整个过程。有关示例,请参见此链接。

祝你好运:)

现在您可能想要使用已经完成所有这些工作的第三方应用程序并从您自己的程序中使用它(如评论中所述的命令行工具)。

于 2012-01-11T13:34:25.580 回答