在现代软件开发中,文件版本控制是一个重要的功能,它允许开发者跟踪文件的变更历史。尽管Windows NTFS文件系统提供了一定程度的版本控制,但本文将介绍一个不依赖于NTFS版本控制的Win32类,该类可以轻松实现文件的版本控制功能。
在软件开发过程中,经常需要对文件进行版本控制,以便在开发过程中跟踪文件的变更。虽然可以使用版本控制系统如Git,但对于某些特定场景,如文本编辑器中的文件快照,可能需要更简单的解决方案。本文介绍的Win32类提供了一种简单的方式来实现文件的版本控制,而不需要依赖于Windows NTFS的版本控制功能。
要使用这个Win32类,需要以下工具和库:
此外,还提供了一个示例Notepad应用程序,展示了如何在文本编辑器中使用这个库。
以下是Win32类FILESNAP的基本结构和使用方法:
class FILESNAP {
public:
struct alignas(8) FSITEM {
CLSID cid = FILESNAP::GUID_HEADER;
unsigned long long DiffAt = 0;
FILETIME created = ti();
FILETIME updated = ti();
unsigned long long i = 0;
unsigned long long at = 0;
unsigned long long sz = 0;
unsigned long long extradatasize = 0;
};
inline bool BuildMap(vector& fsx);
FILESNAP(const wchar_t* fi);
inline bool SetSnap(size_t idx, int CommitForce = 0);
inline bool Create(DWORD Access= GENERIC_READ | GENERIC_WRITE, DWORD Share = 0, LPSECURITY_ATTRIBUTES Atrs = 0, DWORD Disp = CREATE_NEW, DWORD Flags = 0);
inline unsigned long long Size();
inline bool Finalize();
inline bool Commit(size_t At, int Mode);
inline HANDLE GetH();
inline BOOL Write(const char* d, unsigned long long sz2);
inline BOOL Read(char* d, unsigned long long sz2);
inline unsigned long long SetFilePointer(unsigned long long s, DWORD m = FILE_BEGIN);
inline BOOL SetEnd();
inline void Close();
};
要创建一个新文件,只需将文件名传递给FILESNAP构造函数。使用Create()函数并设置CreateFile标志CREATE_NEW来创建文件。使用Write()函数向文件写入数据。当需要保存当前版本时,调用Commit(0,0)。对于第一次保存,Commit()函数会忽略这两个参数。继续使用Write()函数向文件写入数据。下一次调用Commit()时,将当前内容保存为差异备份。如果Mode参数为0,则Commit()函数始终将差异备份保存到第一个提交。如果Mode参数为1,则Commit()函数将差异备份保存到指定的提交编号,由At参数指定。这允许使用差异备份或增量备份。继续使用Read()、Write()、SetEnd()、SetFilePointer()、Size()和GetH()函数操作当前句柄。如果想回退到特定的保存点,使用SetSnap。CommitForce可以是0、1或2:0表示如果文件已存在,则函数失败。1表示如果文件已存在,则在回退前先进行提交。2表示在回退前不进行提交。使用SetSnap()后,Read()/Write()/GetH()等操作将作用于回退的数据。Close()函数将关闭文件(不提交),并删除类使用的临时文件。当打开一个现有文件时,类会自动调用SetSnap()找到文件中的最后一个快照。可以调用BuildMap()函数返回包含文件中所有快照的FSITEM数组。如果构建的文件主要是与第一个快照相关的差异备份,则文件会更大,但打开速度更快,因为只需要执行一个操作(比较第一个和打开的快照)。如果构建的文件主要是与最后一个快照相关的增量备份,则文件会更小,但打开速度更慢,因为加载快照时必须处理所有快照。使用GetH()时要谨慎,因为当调用Commit()或SetSnap()时,它返回的HANDLE将不再有效。