MySQL: 从 WinForms 备份、压缩并使用 FTP
备份整个 MySQL 数据库,压缩它,并使用 FTP 将其发送到 FTP 服务器。
引言
在本文中,我们将实现 Windows Forms 应用程序中的两个菜单命令
- 备份整个 MySQL 数据库,压缩它,然后通过 FTP 传输到 FTP 服务器。
- 反向 = 从 FTP 服务器获取,解压缩,恢复到 MySQL。 类似于我的数据库应用程序的打开/保存功能。
为什么? 为了让我更灵活。 在晚上,我希望能够通过在我的主业务应用程序中选择“备份”甚至“保存”来轻松解决我的备份问题。 而在第二天,我可能正在旅行,因此,从我的笔记本电脑上,我希望能够打开最新版本并继续工作。 由于使用我的 30 MB 数据库需要几秒钟的时间才能运行它,因此我选择使用 BackgroundWorker
线程来完成这项工作,并将进度报告回 GUI 中的文本框,以避免完全冻结的 GUI。
背景
我为今年的业务基础设施设定了一些目标。 从 MS SQL Server 迁移到 MySQL 是其中之一; 尝试找到更轻量级的 IDE 替代方案是另一个 - 主要是为了获得更大的灵活性。 因此,虽然我们在这里即将实现的开头概述的任务并非什么高深莫测的东西,通常可以通过几分钟的脚本解决,但我发现将所有这些都放在我的主要业务应用程序中非常方便。
Using the Code
我们需要 VS2008 Express 和 C# 2.0。 我们在这里开发一个 Windows Forms 应用程序,带有两个按钮:一个用于恢复,一个用于备份。 备份始终存储在 <path>\backups 中。 我只允许一代(文件被删除)。 所有设置都在 app.config 文件中完成。 GUI 中没有进行任何覆盖等。
本例中备份的文件名为 testfile.sql,并且根据压缩方法,它可能是 testfile.sql.gz 或 testfile.sql.tar。
最后一个参数“BackupFTPDirectory
”可以是 FTP 服务器上的一个子目录,例如“/mybackups”。 <!-- 'Internal' (gz) or 'path to winrar\rar.exe'.
在 FTP 之前,我们如何压缩 .sql 文件? 正如我所说,我真的不想等待我的 30 MB 备份文件被下载/上传,所以我想要一些压缩。 目前支持内部(GZip)或 rar.exe 的路径。 在 /backups 目录中,您将找到两个 cmd 文件。 Backmysql.cmd
"C:\xampp\mysql\bin\mysqldump.exe"
--no-create-db
--routines
--host localhost
--user root
--password=enterpwhere %1 > "%2"
您需要更改 mysqldump 的路径,并输入正确的用户名和密码。 当然。 该应用程序将调用此 cmd 文件来执行数据库备份。
Restmysql.cmd:
"C:\xampp\mysql\bin\mysql.exe" -u root -penterpwdhere -D %1 < "%2"
您需要更改 MySQL 的路径,并输入正确的用户名和密码。 当然。 该应用程序将调用此 cmd 文件来执行数据库备份。
文件压缩
我的第一个想法是使用内部的 GZipStream
(在命名空间 System.IO.Compression
中可用)。 我认为这对我来说已经足够好了,而且没有任何依赖关系。
sZipped = sLocalDir + "\\" + oParams.FileNameWithoutExt + ".sql.gz";
byte[] buffer = System.IO.File.ReadAllBytes(sLocalDir + "\\" +
oParams.FileNameWithoutExt + ".sql");
Stream fs = File.Create(sZipped);
GZipStream gZip = new GZipStream(fs, CompressionMode.Compress, true);
gZip.Write(buffer, 0, buffer.Length);
gZip.Close();
fs.Close();
但是,我的 33 MB 只被压缩到 9 MB 以上,当我使用 WinRar 运行时,我得到了 7.5 MB 以下。 当使用 FTP 时,2.5 MB 是一笔不小的数目,所以我不得不实现一种更好的压缩方法。 当然,有 ISharpCode zip 库,但我不想在我的应用程序中拖入一个超过 200K 的库依赖项。 但是,由于这是 **我的** 应用程序和 **我的** 盒子,我可以在所有盒子上依赖 WinRar 被安装(这是我选择使用的压缩应用程序)。 所以我为此写了一个丑陋的修复程序。
if (oParams.CompressionMethod == "Internal")
{
..old gz
}
else
{
System.Diagnostics.Process.Start
d:\program\winrar\rar.exe a filename.sql.rar filename.sql
}
FTP
我知道那里有很多现有的 FTP 库,有免费的和商业的。 我从 Jaimon Mathew 的单文件中获取了 FTPFactory.cs,真的很容易使用。
FTPFactory oFTP = new FTPFactory();
oFTP.setRemoteHost(oParams.FTPServer);
oFTP.setRemoteUser(oParams.FTPAccount);
oFTP.setRemotePass(oParams.FTPPassword);
oFTP.login();
if (oParams.FTPDir.Length > 0)
oFTP.setRemotePath(oParams.FTPDir);
oFTP.upload(sLocalFile);
oFTP.close();
GUI 和 BackgroundWorker
正如我所说,整个操作使用我的 6 MB RAR 文件需要几秒钟的时间。 等待它不是什么大问题,因为我早上做一次,晚上做一次,但是一个不会冻结的 GUI 和某种进度指示器是我决定添加的东西。
所以,在代码中,您将看到按钮处理程序有类似这样的代码
WorkerParams oParams = new WorkerParams();
oParams.LocalBackupDir = txtDirectory.Text;
oParams.ZipFTP = chFTP.Checked;
oParams.FTPServer = txtFTPServer.Text;
oParams.FTPAccount = txtFTPLogin.Text;
oParams.FTPPassword = txtFTPPassword.Text;
oParams.FTPDir = txtFTPDir.Text;
oParams.DatabaseName =
System.Configuration.ConfigurationManager.AppSettings["BackupDatabaseName"];
oParams.CompressionMethod =
System.Configuration.ConfigurationManager.AppSettings["BackupCompressionMethod"];
oParams.WType = WorkerParams.WorkType.Backup;
oParams.FileNameWithoutExt =
System.Configuration.ConfigurationManager.AppSettings["BackupFileName"];
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync(oParams);
我们通过 BackgroundWorker
创建一个工作线程,并向其提供一个 WorkerParams
对象(参见 WorkerParams.cs),其中包含所有变量。
工作回调基本是这样的
void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker oWorker = sender as BackgroundWorker;
WorkerParams oParams = e.Argument as WorkerParams;
if (oParams.WType == WorkerParams.WorkType.Backup)
{
//Backup
oWorker.ReportProgress(0, "Starting backup");
RemoveOldFiles(oParams);
oWorker.ReportProgress(10, "Old files removed");
oWorker.ReportProgress(11, "Starting DB Backup");
RunDBBackup(oParams);
oWorker.ReportProgress(50, "DB Backup done");
oWorker.ReportProgress(51, "Starting compression");
string sLocalFile = RunCompress(oParams);
oWorker.ReportProgress(70, "Compression done");
oWorker.ReportProgress(71, "FTP");
RunSendFTP(oParams, sLocalFile);
oWorker.ReportProgress(90, "FTP done");
oWorker.ReportProgress(100, "Done");
}
}
我们一次运行每个步骤,并将进度报告回 GUI 线程。 它只是将文本附加到多行“status”文本框。
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string sWhat = e.UserState as String;
textBox1.Text += sWhat + Environment.NewLine;
if (e.ProgressPercentage == 100)
{
button2.Enabled = true;
button1.Enabled = true;
}
}