65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 10 文件历史记录/备份中限制世代

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (2投票s)

2017 年 8 月 15 日

CPOL

2分钟阅读

viewsIcon

8326

downloadIcon

5

防止新的 Windows 备份机制臃肿

引言

新的 Windows 文件历史记录实现了其目标,成为一种易于设置的存档和备份机制,无需过多干预即可实现相当复杂的多世代文件历史记录。 唯一的问题是,使用默认的“备份我的文件”设置(一小时),对于不断更新的文件,项目数量会迅速增加。 这个小工具允许您定期修剪并仅保留文件历史记录/备份集中的最后 n 个文件。

代码

本文旨在提供一个有用的工具,而不是展示任何花哨的编码技巧。 这是我第一次提交代码。 我必须说,想到其他人会查看你的代码会集中注意力。 我没有采用通常的快速而粗糙的方法,而是努力做到“正确”,进行一些错误检查,甚至偶尔添加一些注释。

一个功能需要一些解释。 找到要清除的文件的一种直观方法是对文件进行排序,然后扫描查找原始文件名(即括号“(存档日期)”之前的部分)的重复项。 问题是后缀(例如“.txt”)没有被考虑在内,具有相同基本名称但不同后缀的文件都会被组合在一起,以确定有多少个文件存在。 我通过创建一个排序数组来解决这个问题,该数组由

  • 后缀
  • 一个占位符 '*'(使用是因为它永远不能是文件名或目录名的一部分)
  • 完整路径

然后,该数组按降序排序,以便将最新文件放在最前面。 “比较名称”是最后一个 '(' 之前的文本,而原始路径/文件名是 '*' 之后的文本。 在后缀包含括号的相当晦涩的情况下,此技术将失败 - 总是会有局限性。

我想添加功能,以便除了或加上世代数量外,文件历史记录由例如,一个至少一个月前的文件,一个至少一周前的文件和一个至少一天前的文件组成。 任何有空闲时间的聪明年轻人都可以尝试一下。

我非常重视评论,以及对这位老家伙做事方式的建议替代方案。

// Eliminate old files from Windows 10 File History

//The command line parameters are:
//1 Root directory of target
//2 Number of generations to retain

// Note that the Read-only attribute set by Windows is ignored & overridden to allow deletion

// The program is intended to run in batch mode and so errors are listed without intervention

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]))
        {
            // This path is a directory
            ProcessDirectory(args[0], MaxRetain);
        }
        else
        {
            Console.WriteLine("{0} is not available or is not a valid directory.", args[0]);
        }
    }

    // Process all files in the directory passed in, recurse on any directories
    // that are found, and process the files they contain.
    public static void ProcessDirectory(string targetDirectory, int MaxRetain)
    {
        string[] fileEntries = Directory.GetFiles(targetDirectory);
        string[] SortEntries = new string[fileEntries.Length]; // copy entries but prepend with
            // suffix (e.g. .txt) and a placemarker '*' This character was chosen because it cannot be part of filename
                // all this is to prevent files with same name but different suffixes from being treated
                // as if they form part of the same history set
        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] + '*';
                SortEntries[x] = SortEntries[x] + fileName;
                x++;
            }
            Array.Sort(SortEntries);
            Array.Reverse(SortEntries); // newest files first within set
            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); // remove Read Only
                        File.Delete(OriginalName);
                        Console.WriteLine("{0} deleted", OriginalName);
                    }
                    catch(Exception e) // this will handle sharing violations and permission issues
                    {
                        Console.WriteLine( "Unable to delete {0} because {1}", OriginalName, e);
                        continue;
                    }
                }

            }
        }
        // Recurse into subdirectories of this directory.
        string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
        foreach (string subdirectory in subdirectoryEntries)
            ProcessDirectory(subdirectory, MaxRetain);
    }
}

© . All rights reserved.