在现代操作系统中,文件历史功能为用户提供了一种方便的方式来追踪和恢复文件的旧版本。然而,随着时间的推移,这些历史记录可能会迅速累积,导致存储空间的浪费。本文介绍的是一个简单的工具,它可以帮助用户定期清理文件历史记录,只保留最新的几个版本。
这个工具的设计理念是尽可能减少用户的干预,实现一个相对复杂的多代文件历史记录清理机制。默认情况下,Windows 10的“备份文件”设置为每小时备份一次,这会导致频繁更新的文件数量迅速增加。这个小工具可以让定期修剪文件历史记录,只保留最后n个文件。
本文旨在提供一个实用的工具,而不是展示任何复杂的编码技巧。这是第一次提交代码,必须说,想到其他人会查看代码,这让更加专注于把事情做得“正确”,进行一些错误检查,甚至偶尔添加注释。
有一个特性需要解释。直观的方法是找到要清除的文件,对文件进行排序,然后扫描查找原始文件名的重复项,即“(归档日期)”之前的部分。问题是,后缀(例如“.txt”)没有被考虑在内,具有相同基本名称但不同后缀的文件将被归为一组,以决定存在多少个。通过创建一个排序数组来解决这个问题,数组包括:
然后,数组被排序成降序,这样最新的文件就排在最前面。'比较名称'是最后一个'('之前的文本,原始路径/文件名是'*'之后的文本。这种技术在后缀包含括号的相当罕见的情况下会失败——总会有限制。
想添加一个功能,除了或作为文件历史的一个版本,比如说,一个至少一个月大的文件,一个至少一周大的文件,和一个至少一天大的文件。任何有空闲时间的聪明的年轻人都可以尝试去做。
非常欢迎评论,也许可以提出一些建议,告诉这个老家伙做事的方式。
以下是用于从Windows 10文件历史中删除旧文件的命令行参数:
请注意,Windows设置的只读属性将被忽略并覆盖,以允许删除。
该程序旨在以批处理模式运行,因此错误会在没有干预的情况下列出。
using System;
using System.IO;
using System.Text;
using System.Collections;
public class RecursiveFileProcessor
{
public static void Main(string[] args)
{
int MaxRetain;
if (args.Length != 2 || !int.TryParse(args[1], out MaxRetain))
{
Console.WriteLine("Usage - " + System.AppDomain.CurrentDomain.FriendlyName + " Path NumberOfGenerations");
Console.WriteLine("For example " + System.AppDomain.CurrentDomain.FriendlyName + " C:\\FileHistory 2");
return;
}
if (Directory.Exists(args[0]))
{
ProcessDirectory(args[0], MaxRetain);
}
else
{
Console.WriteLine("{0} is not available or is not a valid directory.", args[0]);
}
}
public static void ProcessDirectory(string targetDirectory, int MaxRetain)
{
string[] fileEntries = Directory.GetFiles(targetDirectory);
string[] SortEntries = new string[fileEntries.Length];
if (SortEntries.Length > 0)
{
int x = 0;
foreach (string fileName in fileEntries)
{
int LastClose = fileName.LastIndexOf(')');
int LenSuffix = fileName.Length - LastClose - 1;
SortEntries[x] = "";
if (LastClose > 0 && LenSuffix > 0)
{
SortEntries[x] = fileName.Substring(fileName.Length - LenSuffix);
}
SortEntries[x] += '*';
SortEntries[x] += fileName;
x++;
}
Array.Sort(SortEntries);
Array.Reverse(SortEntries);
string PrevName = "";
int CountDup = 0;
foreach (string SortFile in SortEntries)
{
if (SortFile == null) continue;
string OriginalName = SortFile.Substring(SortFile.IndexOf('*') + 1);
int OpenPos = SortFile.LastIndexOf('(');
string CompareName = SortFile;
if (OpenPos > 0)
{
CompareName = SortFile.Substring(0, SortFile.LastIndexOf('('));
}
if (CompareName == PrevName)
{
CountDup++;
}
else
{
CountDup = 0;
PrevName = CompareName;
}
if (CountDup >= MaxRetain)
{
try
{
FileAttributes attributes = File.GetAttributes(OriginalName);
File.SetAttributes(OriginalName, attributes & ~FileAttributes.ReadOnly);
File.Delete(OriginalName);
Console.WriteLine("{0} deleted", OriginalName);
}
catch (Exception e)
{
Console.WriteLine("Unable to delete {0} because {1}", OriginalName, e);
continue;
}
}
}
}
string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
{
ProcessDirectory(subdirectory, MaxRetain);
}
}
}