将项目文件备份到 Gmail






4.81/5 (38投票s)
一个 WinForms 应用程序,支持命令行执行,可以扫描文件夹树,创建(一个或多个)Zip 文件,并将其连同格式化的消息一起发送到 Gmail 账户。
引言
这是一个简单的应用程序,用于将您的代码备份到 Gmail。它会创建(一个或多个)Zip 文件,其中包含经过过滤的文件列表,排除 obj、bin、exe、SVN 以及其他非必需文件。如果需要,它会分割成多个 Zip 文件,您可以控制 Zip 文件的大小。
背景
像大多数开发者一样,我使用 SVN 作为代码仓库,并尽量频繁地进行备份。我喜欢一个自动化、每日、异地备份的想法,这样我就可以随时随地获取我的代码文件。因此,我开发了这个小工具,以确保我对我的重要文件进行完整、每日异地备份,其中包括所有 .cs、.vb、.proj 等文件。通过备份到 Gmail,即使我不在网络上(例如在客户那里),我也可以访问我所有的源代码。这不是增量备份,尽管您可以轻松修改程序使其区分日期。
通过每天运行此程序,我还可以轻松地恢复给定日期的开发树的快照,这在过去几次派上了用场。(我知道您可以从 SVN 中拉取先前的版本,但相信我,这要容易得多!)
将代码备份到 Gmail 可能看起来是一项微不足道的任务,但它比简单地 Xcopy 一堆文件要复杂一些。关键在于排除大多数重量级文件:我不需要备份任何 obj 文件、本地引用副本、.svn 文件、.EXE 或 PDB 文件。我的文件夹里还有很多第三方文件不需要包含在内。因此,该程序允许您定义包含和排除您需要和不需要的文件模式的列表。您可以指定要排除的文件夹(例如 \bin)或特定的文件模式(例如 *.zip)。您的设置保存在一个 XML 文件中,该文件只是程序中 BackupVars
类的序列化形式。
Gmail 限制
Gmail 是一个了不起的电子邮件服务。我认为它们现在为您提供了大约 15GB 的空间... 这使其非常适合此类任务。但是,它确实有一些限制:您不能将任何 .exe 文件包含在附件中,即使文件在 Zip 文件内。Backup2gmail 程序会将 Zip 文件重命名为 xxx_yymmdd_hhmmss.ziprenamed,以便 Gmail 只将其视为二进制文件。
Gmail 将总消息大小限制为 20MB,这相当大。然而,我的源代码树,加上一些测试数据,压缩后会超过 20MB。因此,该程序将创建多个 Zip 文件,并将每个 Zip 文件作为单独的电子邮件发送。电子邮件的主题将显示消息编号,邮件正文将包含一个格式精美的 HTML 表格,列出文件。
在 Gmail 中,电子邮件看起来是这样的
要恢复您的文件,您需要手动下载附件,将其重命名回 .zip 文件,然后解压缩。当然,文件夹在 Zip 文件中会被保留。
命令行用法
此程序可以从命令行运行,也可以交互式运行。程序代码包含一个命令行解析库。可以使用两种命令行格式:您可以传入文件夹名称、电子邮件账户和密码,或者您可以传入一个 Backup2Gmail 配置文件名。B2G 配置文件是一个包含设置和电子邮件凭据的 XML 文件。
单击“文件”菜单下的“批量命令行”菜单选项以获取命令行格式。
在任务计划程序中安排程序
您可以轻松地在 Windows 任务计划程序中设置计划,以实现夜间自动备份。我通常在凌晨运行作业。程序不包含计划功能... 您需要手动完成。
Using the Code
源代码中有许多有用的项,您可能会发现它们有益
双模式操作 - 命令行或交互式
有一个创建可以从命令行运行的 WinForms 应用程序的技巧。默认情况下,WinForms 应用程序会创建一个主窗口,因此为了避免在使用命令行时出现一个幽灵窗口,您可以在启动时使用以下代码
class Backup2Gmail
{
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
[STAThread]
static void Main(string[] args)
{
if (args.Length == 0)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
frmBackup oBackup = new frmBackup();
oBackup.ShowDialog();
return;
}
AttachConsole(ATTACH_PARENT_PROCESS);
CommandLineParser parser = new CommandLineParser();
Backup2GmailArgs oBackupArgs = new Backup2GmailArgs();
parser.ExtractArgumentAttributes(oBackupArgs);
try
{
parser.ParseCommandLine(args);
}
catch (Exceptions.CommandLineArgumentException exC)
{
Console.Write(exC.ToString());
}
对我来说,另一个挑战是创建一个没有依赖项的单个可执行文件。我选择使用 CodePlex 的 DotNetZip 库(参见 http://dotnetzip.codeplex.com/) 而不是更常用的 SharpZip 库。这个库更容易集成到项目中,并且可以编译成最终的可执行文件。
使用 System.Net.Mail.SmtpClient
库发送电子邮件。以下是发送电子邮件的代码
System.Net.Mail.Attachment mailAttachment =
new System.Net.Mail.Attachment(oBackupVars.Outputfile);
mm.Attachments.Add(mailAttachment);
string smtpHost = "smtp.gmail.com";
//string userName = GmailAccount;//sending Id
//string password = GmailPassword;
System.Net.Mail.SmtpClient mClient = new System.Net.Mail.SmtpClient();
mClient.Port = 587;
mClient.EnableSsl = true;
mClient.UseDefaultCredentials = false;
mClient.Credentials = new System.Net.NetworkCredential(oBackupVars.Userid,
oBackupVars.Password);
mClient.Host = smtpHost;
mClient.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
mClient.Timeout = int.MaxValue;
ShowMessage(oBackupVars, "Sending email to " +
oBackupVars.Userid + " " + mm.Subject);
mClient.Send(mm);
ShowMessage(oBackupVars, "Sent email with backup zip file to " +
oBackupVars.Userid);
请注意,Gmail 使用非标准端口号 (587)。
程序设置和运行时统计信息
可序列化的 BackupVars
类包含所有运行时统计信息、电子邮件设置以及控制哪些文件包含或排除在备份中的过滤器。该类中的值使用 Windows PropertyGrid
控件进行编辑。序列化使用 .NET 序列化器完成。
[TypeConverter(typeof(ExpandableObjectConverter))]
public class BackupVars
{
[XmlIgnore()]
public ZipFile oZipFile = null;
[XmlIgnore()]
public int NumEmailMessages = 0;
[XmlIgnore()]
public long UncompressedLength = 0;
[XmlIgnore()]
public long CompressedFileLength = 0;
[XmlIgnore()]
public Label StatusMessage = null;
[XmlIgnore()]
public bool IsRunning = false;
[XmlIgnore()]
public bool IsCancelled = false;
private string _TempFolderForZipFiles = @"C:\Temp\Backup2Gmail\";
public string TempFolderForZipFiles
{
get { return _TempFolderForZipFiles; }
set { _TempFolderForZipFiles = value; }
}
private string _userid;
public string Userid
{
get { return _userid; }
set { _userid = value; }
}
private string _password;
public string Password
{
get { return _password; }
set { _password = value; }
}
private string _outputfile;
public string Outputfile
{
get { return _outputfile; }
set { _outputfile = value; }
}
private string _SourceCodeFolderBaseName;
public string SourceCodeFolderBaseName
{
get { return _SourceCodeFolderBaseName; }
set { _SourceCodeFolderBaseName = value; }
}
private string _RootPath;
public string RootPath
{
get { return _RootPath; }
set { _RootPath = value; }
}
public StringBuilder sb = new StringBuilder();
private string[] _IncludedFilePattern = new string[] { "*.*" };
public string[] IncludeFilePatterns
{
get { return _IncludedFilePattern; }
set { _IncludedFilePattern = value; }
}
private string[] _ExcludedFilePattern = new string[] { "*.msi*" };
public string[] ExcludedFilePattern
{
get { return _ExcludedFilePattern; }
set { _ExcludedFilePattern = value; }
}
private string[] _ExcludedExtensionStartsWith =
new string[] { ".zip", ".msi" };
public string[] ExcludedExtensionStartsWith
{
get { return _ExcludedExtensionStartsWith; }
set { _ExcludedExtensionStartsWith = value; }
}
private string[] _ExcludedExtensionExactMatch =
new string[] { ".exe", ".dll", ".pdb", ".log" };
public string[] ExcludedExtensionExactMatch
{
get { return _ExcludedExtensionExactMatch; }
set { _ExcludedExtensionExactMatch = value; }
}
private string[] _ExcludedFoldersContains = new string[] {
@"\debug\bin",
@"\release",
@"pro\actmatewebsite\actmate\backup",
@"pro\actmatewebsite\actmate\recovery" };
public string[] ExcludedFoldersContains
{
get { return _ExcludedFoldersContains; }
set { _ExcludedFoldersContains = value; }
}
private string[] _ExcludedExactFolderNames = new string[] {
@"bin",
@"obj",
@"References",
@".svn",
@"RadControls",
@"fckeditor"};
public string[] ExcludedExactFolderNames
{
get { return _ExcludedExactFolderNames; }
set { _ExcludedExactFolderNames = value; }
}
private long _ZipFilesize = 19500000;
public long ZipFilesize
{
get { return _ZipFilesize; }
set { _ZipFilesize = value; }
}
public BackupVars()
{
}
public BackupVars Clone()
{
return DeserializeFromXMLString(SerializeToXMLString(this));
}
public static BackupVars DeserializeFromXMLString(string in_Backup2GmailXML)
{
XmlSerializer s = new XmlSerializer(typeof(BackupVars));
return (BackupVars)s.Deserialize(new StringReader(in_Backup2GmailXML));
}
public static string SerializeToXMLString(BackupVars in_Backup2Gmail)
{
try
{
System.Xml.Serialization.XmlSerializer s =
new System.Xml.Serialization.XmlSerializer(typeof(BackupVars));
StringWriter sw = new StringWriter();
s.Serialize(sw, in_Backup2Gmail);
return sw.ToString();
}
catch (Exception ex)
{
throw new Exception("Could not serialize " +
"Backup2Gmail. Error Msg: " + ex.Message, ex);
}
}
}
如果您不熟悉序列化,您可能想看看我在这个类中使用的技术。您会看到一些属性带有 [XMLIgnore()]
属性 - 这将指示序列化器在 XML 文件中排除该属性。
此类中的关键属性是
- 您要备份的根文件夹
- Gmail 账户
- Gmail 密码
- 包含和排除规则
您可能想在文件中硬编码一些排除和包含规则来处理您的情况。文件过滤是通过包含和排除模式的组合完成的
IncludeFilePatterns
ExcludedFilePattern
ExcludedExactFolderNames
ExcludedFoldersContains
ExcludedExtensionStartsWith
ExcludedExtensionExactMatch
关注点
我最初尝试使用 .NET 中内置的 Zip 工具,但在花费了太多时间试图理解 Redmond 的技术人员的想法之后,我改用了更符合逻辑的 DotNetZip 库。
此程序主要面向需要备份代码的程序员。但是,您也可以将其用于压缩后小于 20MB 的文档和其他文件。它不打算成为一个完整的备份系统,如果您尝试备份大型文件(如 SQL Server 文件),它将无法正常工作。
历史
- 版本 2.0 - CodeProject 上传 - 2009 年 5 月 1 日。