Finally, I got around to updating my database backup utility! I started by creating a MySQL connection library and a “Backup Engine” library, which I hooked up to a test console app. This approach will allow me to have two different applications that use the same back end. One application will be a windows client and the there will be a command line utility as well.
The original version was created over a year ago and hasn’t been worked on until now.
The new project consists of:
- Database connection library
- Database Backup engine
- Commandline app
- Windows forms app
It saves backup into .sql files of predefined size. I created a DynamicFile class which saves text data into multiple files and allows the programmer to get the list of filenames afterwards:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
namespace BackupEngine { /// <summary> /// DynamicFile is a file spread into multiple files of predefined size /// by Michal Dabski /// </summary> public class DynamicFile { string baseFileName, path, extension; int maxSize; StreamWriter streamWriter; public int TotalSize { get; private set; } public int CurrentSize { get; private set; } public int CurrentFileId { get; private set; } public string CurrentFile { get; private set; } public List<string> FileNames {get; private set;} public string FolderPath { get { return this.path; } } public string BaseFileName { get { return this.baseFileName; } } /// <summary> /// Creates new file /// </summary> /// <param name="path">Path to the file</param> /// <param name="baseFileName">Base name without extension</param> /// <param name="extension">File extension</param> /// <param name="maxSize">Max size in bytes</param> public DynamicFile(string path, string baseFileName, string extension, int maxSize) { this.FileNames = new List<string>(); this.TotalSize = 0; this.CurrentSize = 0; this.CurrentFileId = 0; this.baseFileName = baseFileName; this.path = path; this.extension = extension; this.maxSize = maxSize; if (Directory.Exists(path) == false) Directory.CreateDirectory(path); StartFile(0); } private string getFileName(int id) { if (id == 0) return String.Format("{0}.{1}", baseFileName, extension); else return String.Format("{0}({2}).{1}", baseFileName, extension, id); } private void StartFile(int id) { CurrentFileId = id; CurrentFile = getFileName(id); streamWriter = new StreamWriter(Path.Combine(path, CurrentFile)); FileNames.Add(CurrentFile); } /// <summary> /// Closes file and starts writing to the next file /// </summary> public void NextFile() { EndFile(); StartFile(CurrentFileId + 1); } private void EndFile() { streamWriter.Flush(); streamWriter.Close(); streamWriter = null; TotalSize += CurrentSize; CurrentSize = 0; } public void Close() { EndFile(); } public DynamicFile Write(string contents) { int size = contents.Length; if (CurrentSize + size >= maxSize) NextFile(); CurrentSize += size; streamWriter.Write(contents); return this; } public DynamicFile WriteLine(string contents) { return Write(contents+Environment.NewLine); } } } |
Actually, I extended this class into DynamicSqlFile and created some methods useful for writing SQL files:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
namespace BackupEngine { /// <summary> /// Spreads SQL code into multiple files. /// By Michal Dabski /// </summary> class DynamicSqlFile : DynamicFile { public const char LINE_SEPARATOR = '\n'; public DynamicSqlFile(string path, string baseName, int maxSize) : base(path, baseName, "sql", maxSize) { } public DynamicSqlFile WriteComment(string text) { return (DynamicSqlFile) WriteLine("-- " + text); } public DynamicSqlFile WriteComment() { return WriteComment(""); } public DynamicSqlFile WriteMultilineComment(string [] text) { foreach (string line in text) WriteComment(line); return this; } public DynamicSqlFile WriteMultilineComment(string text) { return WriteMultilineComment(text.Split(LINE_SEPARATOR)); } } } |
It has a handful of useful methods, like WriteComment(), which automatically appends “– ” before the text and ends it with a NewLine character. It also returns and instance of itself, making this possible:
1 2 3 4 5 |
outputFile = new DynamicSqlFile(backupPreferences.backupPath, baseFilename, backupPreferences.MaxFileSize) .WriteComment() .WriteComment("Backup of " + database) .WriteComment("Commenced on " + DateTime.UtcNow + " UTC") .WriteComment(); |
Which makes for very compact and readable code. It ends up looking like this in the SQL file:
1 2 3 4 |
-- -- Backup of 8959_convoy on 198.24.160.66 -- Commenced on 06/05/2013 16:38:24 UTC -- |
Commandline interface: