Резервное копирование чертежей

Дата последнего обновления: 25.09.2014

    Как правило, файлы проекта располагаются в пределах одного общего каталога, будучи распределёнными по его подкаталогам. Для каждого dwg-файла AutoCAD может создавать одну его резервную копию (bak-файл), который сохраняется в том же каталоге, что и оригинал. 

    Обычно для того, чтобы такое резервное копирования происходило нормально, следует в диалоговом окне "Options" (Настройки), на вкладке "Open and Save" (Открытие и сохранение) выставить значение поля "Incremental save percentage" равным нулю, установить галочку для поля "Automatic Save" и указать наиболее подходящий временной интервал между автоматическими сохранениями. Так же следует установить галочку для поля "Create backup copy wich each save" (создавать резервную копию файла при каждом сохранении).

    Но может возникнуть ситуация, при которой файл чертежа будет сохранён, будучи уже в испорченном состоянии - в этом случае бэкап так же будет содержать испорченную информацию. В подобных ситуациях хотелось бы иметь возможность откатиться на какой-то определённый момент времени. Стандартными средствами AutoCAD это не делается. 

Задача

    Предоставить пользователю возможность управлять резервным копированием чертежей, сохраняя бэкапы в определённые моменты, которые он посчитает для себя важными. В таком случае у проектировщика появится выбор, к какой версии резервной копии откатиться в случае неисправности чертежа. При этом файлы бэкапов должны находиться рядом с оригиналом, но не мозолить глаза - например в подкаталоге "QuickCopy".

    Поскольку в одном каталоге невозможно хранить несколько файлов с одинаковыми именами - имена резервных копий должны формироваться по принципу "ИмяИсходногоФайла" + "ДатаВремяРезервногоКопирования". 

    Обозначенный мною каталог бэкапов должен создаваться автоматически (в случае его отсутствия). Резервные копии файлов должны создаваться только по требованию пользователя (запуск команды DwgQuickCopy).

Решение

Для решения данной задачи написал такой код:

   1:  //**************************************
   2:  // DrawingQuickCopy.cs
   3:  // DrawingQuickCopy. © Andrey Bushman, 2012
   4:  // Quick creating of the drawing's backup file into the some subdirectory.
   5:  // https://sites.google.com/site/bushmansnetlaboratory/sendbox/lab/backupfiles
   6:  //**************************************
   7:  using System;
   8:  using System.Collections.Generic;
   9:  using System.Linq;
  10:  using System.Text;
  11:  using System.IO;
  12:  using System.Xml.Linq;
  13:   
  14:  // Autodesk
  15:  using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  16:  using App = Autodesk.AutoCAD.ApplicationServices;
  17:  using Db = Autodesk.AutoCAD.DatabaseServices;
  18:  using Ed = Autodesk.AutoCAD.EditorInput;
  19:  using Rtm = Autodesk.AutoCAD.Runtime;
  20:   
  21:  [assembly: Rtm.CommandClass(typeof(Bushman.CAD.Commands.DwgQuickCopy
  22:      .DrawingQuickCopy))]
  23:   
  24:  namespace Bushman.CAD.Commands.DwgQuickCopy {
  25:      /// <summary>
  26:      /// Класс содержит метод резервного копирования файлов чертежей
  27:      /// </summary>
  28:      public sealed class DrawingQuickCopy : Rtm.IExtensionApplication {
  29:   
  30:          const String xmlSettingsFileName = "DrawingQuickCopy.Settings.xml";
  31:          const String cmdNamespace = "Bushman"; // Command's namespace
  32:          const String helpFileName = "DrawingQuickCopyHelp.chm"; // Help file name
  33:          const String topicName = "DwgQuickCopy"; // Topic's name in the CHM file
  34:   
  35:          //--- XML tags ---
  36:          const String rootXmlTag = "Settings";
  37:          const String backupDirectoryXmlTag = "BackupDirectoryName";
  38:          const String modSuffixXmlTag = "ModSuffix";
  39:          //----------------
  40:   
  41:          String assemblyLocation;
  42:          String backupDirectoryName;
  43:          String modSuffix;
  44:   
  45:          /// <summary>
  46:          /// Инициализация переменных нужными значениями
  47:          /// </summary>
  48:          void Initialize() {
  49:              assemblyLocation = Path.GetDirectoryName(GetType().Assembly
  50:                  .Location);
  51:              assemblyLocation = assemblyLocation.EndsWith(@"\") ?
  52:                  assemblyLocation.Substring(0,
  53:                  assemblyLocation.Length - 1) : assemblyLocation;
  54:   
  55:              String xmlFileFullName = Path.Combine(assemblyLocation,
  56:                  xmlSettingsFileName);
  57:   
  58:              if (!File.Exists(xmlFileFullName)) {
  59:                  CreateSettingsFile(xmlFileFullName);
  60:              }
  61:   
  62:              XElement xml = XElement.Load(xmlFileFullName);
  63:   
  64:              if (xml == null) {
  65:                  CreateSettingsFile(xmlFileFullName);
  66:              }
  67:   
  68:              backupDirectoryName = xml.Element(backupDirectoryXmlTag).Value
  69:                  .Trim();
  70:              modSuffix = xml.Element(modSuffixXmlTag).Value.Trim();
  71:          }
  72:   
  73:          /// <summary>
  74:          /// Создание и сохранение файла настроек
  75:          /// </summary>
  76:          /// <param name="fileName">Полное имя файла</param>
  77:          void CreateSettingsFile(String fileName) {
  78:              XElement xml = new XElement(rootXmlTag);
  79:              xml.Add(new XComment(Resources.BackupDirectoryName));
  80:              xml.Add(new XElement(backupDirectoryXmlTag, "QuickSaves"));
  81:              xml.Add(new XComment(Resources.ModSuffix));
  82:              xml.Add(new XElement(modSuffixXmlTag, "(modified)"));
  83:              xml.Save(fileName);
  84:          }
  85:   
  86:          /// <summary>
  87:          /// Сохранение резервной копии файла в специальном подкаталоге каталога
  88:          /// текущего чертежа. 
  89:          /// Если искомый каталог резервного копирования отсутствует, то он 
  90:          /// автоматически создаётся. Если не удаётся создать каталог резервного
  91:          /// копирования, то операция отменяется, а на консоль автокада выводится
  92:          /// сообщение о невозможности создания резервной копии файла.
  93:          /// </summary>
  94:          [Rtm.CommandMethod(cmdNamespace, "DwgQuickCopy",
  95:              "localNameIdDwgQuickCopy",
  96:              Rtm.CommandFlags.Modal, null, helpFileName, topicName)]
  97:          public void BackupFileSave() {
  98:              Initialize();
  99:              const String separator1 = "-";
 100:              const String separator2 = "_";
 101:   
 102:              App.Document doc = cad.DocumentManager.MdiActiveDocument;
 103:              Db.Database db = doc.Database;
 104:              Ed.Editor ed = doc.Editor;
 105:   
 106:              StringBuilder sb = new StringBuilder();
 107:              String docLocation = (String)cad.GetSystemVariable("DwgPrefix");
 108:              docLocation = docLocation.EndsWith(@"\") ? docLocation.Substring(0,
 109:                  docLocation.Length - 1) : docLocation;
 110:              String backupDirectoryFullName = String.Empty;
 111:   
 112:              if (String.Equals(docLocation, assemblyLocation,
 113:                  StringComparison.CurrentCultureIgnoreCase)) {
 114:                  backupDirectoryFullName = Environment.GetFolderPath(
 115:                      Environment.SpecialFolder.MyDocuments);
 116:              }
 117:              else {
 118:                  backupDirectoryFullName = docLocation;
 119:              }
 120:   
 121:              backupDirectoryFullName = Path.Combine(backupDirectoryFullName,
 122:                  backupDirectoryName);
 123:   
 124:              DirectoryInfo backupDirectory = new DirectoryInfo(Environment
 125:                  .ExpandEnvironmentVariables(backupDirectoryFullName));
 126:   
 127:              if (!Directory.Exists(backupDirectoryFullName)) {
 128:                  try {
 129:                      Directory.CreateDirectory(backupDirectoryFullName);
 130:                  }
 131:                  catch (Exception ex) {
 132:                      ed.WriteMessage(ex.Message);
 133:                      return;
 134:                  }
 135:              }
 136:   
 137:              backupDirectory = new DirectoryInfo(backupDirectoryFullName);
 138:              String dwgName = (String)cad.GetSystemVariable("DwgName");
 139:   
 140:              // Если выполняется попытка резервного копирования файла, который 
 141:              // расположен не в каталоге резервного копирования, то создаём его 
 142:              // (файла) копию в каталоге резервного копирования
 143:              if (new DirectoryInfo(docLocation).Name != backupDirectory.Name) {
 144:                  try {
 145:                      // Если каталога резервного копирования ещё нет - создаём 
 146:                      // его.
 147:                      if (!backupDirectory.Exists) {
 148:                          backupDirectory.Create();
 149:                      }
 150:   
 151:                      //Формируем имя файла резервной копии чертежа...
 152:                      sb.Append(Path.Combine(backupDirectory.FullName, dwgName
 153:                          .Substring(0, dwgName.Length - 4)));
 154:                      DateTime time = DateTime.Now;
 155:   
 156:                      //Версия бэкапа
 157:                      String x = String.Format(
 158:                          "{1}{2}{0}{3}{0}{4}{1}{5}{0}{6}{0}{7}.dwg", separator1,
 159:                          separator2, time.Year, time.Month.ToString("D2"),
 160:                          time.Day.ToString("D2"), time.Hour.ToString("D2"),
 161:                          time.Minute.ToString("D2"), time.Second.ToString("D2"));
 162:                      sb.Append(x);
 163:                  }
 164:                  catch (System.Exception ex) {
 165:                      ed.WriteMessage(String.Format("\n{0}: \"{1}\".\n{2}\n",
 166:                          Resources.CantCreateQuickSaveDir, backupDirectoryName,
 167:                          ex.Message));
 168:                      ed.WriteMessage(String.Format(Resources.QuickCopyNotCreated,
 169:                          Environment.NewLine));
 170:                      return;
 171:                  }
 172:              }
 173:              // Если выполняется попытка создания резервной копии файла, который
 174:              // уже находится в каталоге резервного копирования, то в этом же 
 175:              // каталоге создать файл с тем же именем, но помеченым в конце 
 176:              // атрибутом, обозначенным в переменной modifyLabel
 177:              else {
 178:                  sb.Append(Path.Combine(docLocation, dwgName.Substring(0,
 179:                      dwgName.Length - 4) +
 180:                      separator2 + modSuffix));
 181:              }
 182:   
 183:              using (Db.Database db2 = db.Wblock()) {
 184:                  db2.SaveAs(sb.ToString(), Db.DwgVersion.Current);
 185:              }
 186:              ed.WriteMessage("\n{0}: \"{1}\"\n", Resources.QuickCopyCreated,
 187:                  sb.ToString());
 188:          }
 189:   
 190:          #region IExtensionApplication Members
 191:   
 192:          void Rtm.IExtensionApplication.Initialize() {
 193:              App.Document doc = cad.DocumentManager.MdiActiveDocument;
 194:              if (null == doc)
 195:                  return;
 196:              Ed.Editor ed = doc.Editor;
 197:              ed.WriteMessage("\n{0}. {1}\n\n", Resources.ApplicationName,
 198:                  Resources.Copyright);
 199:          }
 200:   
 201:          public void Terminate() {
 202:              // is empty
 203:          }
 204:          #endregion
 205:      }
 206:  }

Дополнительно к этому коду прилагается файл настроек DrawingQuickCopy.Settings.xml, содержимое которого следующее:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <Settings>
   3:    <!--Каталог, в котором следует сохранить копию текущего чертежа. Можно указывать как 
   4:    относительные, так и абсолютные пути.-->
   5:    <BackupDirectoryName>QuickCopy</BackupDirectoryName>
   6:    <!--Если чертёж был сохранён в каталоге быстрого сохранения и затем был модифицирован 
   7:    - к его имени будет добавлен указанный в этом поле суффикс.-->
   8:    <ModSuffix>(modified)</ModSuffix>  
   9:  </Settings>

     Файл справочной системы DrawingQuickCopyHelp.chm:


Результат работы команды DwgQuickCopy может выглядеть например так:



Системные требования и информацию о загрузке следует читать в файле справки (DrawingQuickCopyHelp.chm).

Код откомпилирован для AutoCAD 2009-2015. Результат здесь.
Исходники здесь (MS Visual Studio 2012; Help & Manual 6).
Comments