/// <summary> /// Создание дерева списка копий для всех режимов сравнения /// </summary /// <param name="bw">Экземплар фонового обработчика класса BackgroundWorker</param> /// <param name="e">Экземпляр класса DoWorkEventArgs</param> /// <param name="ht">Заполненная хеш-таблица списками книг</param> /// <returns>Признак непрерывности обработки файлов</returns> public bool makeTreeOfBookCopies(BackgroundWorker bw, DoWorkEventArgs e, Label StatusLabel, ProgressBar ProgressBar, ListView listViewFB2Files, ref StatusView sv, HashtableClass ht) { StatusLabel.Text += "Создание списка (псевдодерево) одинаковых fb2-файлов...\r"; ProgressBar.Maximum = ht.Values.Count; ProgressBar.Value = 0; // сортировка ключей (групп) List <string> keyList = makeSortedKeysForGroups(ht); int i = 0; foreach (string key in keyList) { ++sv.Group; // число групп одинаковых книг // формирование представления Групп с их книгами makeBookCopiesView((FB2FilesDataInGroup)ht[key], listViewFB2Files, ref sv); bw.ReportProgress(++i); if (bw.CancellationPending) { e.Cancel = true; return(false); } } return(true); }
/// <summary> /// Заполнение хеш таблицы данными о fb2-книгах в контексте Авторов /// </summary> /// <param name="fb2">объект класса FictionBook</param> /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param> /// <param name="SrcPath">путь к fb2-файлу</param> /// <param name="Encoding">кодировка текщего файла в fb2</param> /// <param name="sAuthor">Фамилия и 1-я буква Имени текущего автора</param> /// <param name="htFB2ForAuthorFIO">Хеш Таблица с книгами одинаковых Авторов</param> private void FB2AuthorFIOSetHashTable(FictionBook fb2, string ZipPath, string SrcPath, string Encoding, string sAuthor, ref HashtableClass htFB2ForAuthorFIO) { // данные о книге BookData fb2BookData = new BookData( fb2.TIBookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, fb2.DIID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding ); if (ZipPath != null) { fb2BookData.Path = ZipPath; } if (!htFB2ForAuthorFIO.ContainsKey(sAuthor)) { // этого Автора sAuthor в Группе еще нет FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, sAuthor); fb2f.Group = sAuthor; htFB2ForAuthorFIO.Add(sAuthor, fb2f); } else { // этот Автор sAuthor в Группе уже есть FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForAuthorFIO[sAuthor]; fb2f.Add(fb2BookData); //htFB2ForBT[sAuthor] = fb2f; //ИЗБЫТОЧНЫЙ КОД } }
/// <summary> /// Заполнение хеш таблицы данными о fb2-книгах в контексте Авторов с одинаковой Фамилией и инициалами /// </summary> /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param> /// <param name="SrcPath">путь к fb2-файлу</param> /// <param name="htFB2ForAuthorFIO">Хеш Таблица с книгами одинаковых Авторов</param> /// <param name="WithMiddleName">Учитывать ли отчество Авторов (true) или нет (false) при поиске</param> private void MakeFB2AuthorFIOHashTable(string ZipPath, string SrcPath, ref HashtableClass htFB2ForAuthorFIO, bool WithMiddleName) { FictionBook fb2 = null; try { fb2 = new FictionBook(SrcPath); } catch (Exception ex) { Debug.DebugMessage( SrcPath, ex, "Дубликатор.CompareForm.MakeFB2AuthorFIOHashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте Авторов с одинаковой Фамилией и инициалами." ); _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath); return; } string Encoding = fb2.getEncoding(); if (string.IsNullOrWhiteSpace(Encoding)) { Encoding = "?"; } IList <Author> AuthorsList = fb2.TIAuthors; string sAuthor = "<Автор книги отсутствует>"; if (AuthorsList != null) { foreach (Author a in AuthorsList) { if (a.LastName != null && !string.IsNullOrEmpty(a.LastName.Value)) { sAuthor = a.LastName.Value; } if (a.FirstName != null && !string.IsNullOrEmpty(a.FirstName.Value)) { sAuthor += " " + a.FirstName.Value.Substring(0, 1); } if (WithMiddleName) { if (a.MiddleName != null && !string.IsNullOrEmpty(a.MiddleName.Value)) { sAuthor += " " + a.MiddleName.Value.Substring(0, 1); } } if (a.NickName != null && !string.IsNullOrWhiteSpace(a.NickName.Value)) { sAuthor += a.NickName.Value; } sAuthor = sAuthor.Trim(); // Заполнение хеш таблицы данными о fb2-книгах в контексте Авторов FB2AuthorFIOSetHashTable(fb2, ZipPath, SrcPath, Encoding, sAuthor, ref htFB2ForAuthorFIO); } } else { // Заполнение хеш таблицы данными о fb2-книгах в контексте Авторов FB2AuthorFIOSetHashTable(fb2, ZipPath, SrcPath, Encoding, sAuthor, ref htFB2ForAuthorFIO); } }
/// <summary> /// Заполнение хеш таблицы данными о fb2-книгах в контексте их md5 /// </summary> /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param> /// <param name="SrcPath">путь к fb2-файлу;</param> /// <param name="htFB2ForMd5">Хеш Таблица с книгами с одинаковыми значениями Md5</param> private void MakeFB2Md5HashTable(string ZipPath, string SrcPath, ref HashtableClass htFB2ForMd5) { string md5 = ComputeMD5Checksum(SrcPath); FictionBook fb2 = null; try { fb2 = new FictionBook(SrcPath); } catch (Exception ex) { Debug.DebugMessage( SrcPath, ex, "Дубликатор.CompareForm.MakeFB2Md5HashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте их md5." ); _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath); return; } string Encoding = fb2.getEncoding(); if (string.IsNullOrWhiteSpace(Encoding)) { Encoding = "?"; } string ID = fb2.DIID; if (ID == null) { return; } if (ID.Trim().Length == 0) { ID = "Тег <id> в этих книгах \"пустой\""; } // данные о книге BookData fb2BookData = new BookData( fb2.TIBookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, ID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding ); if (ZipPath != null) { fb2BookData.Path = ZipPath; } if (!htFB2ForMd5.ContainsKey(md5)) { // такой книги в числе дублей еще нет FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, md5); htFB2ForMd5.Add(md5, fb2f); } else { // такая книга в числе дублей уже есть FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForMd5[md5]; fb2f.Add(fb2BookData); //htFB2ForMd5[md5] = fb2f; //ИЗБЫТОЧНЫЙ КОД } }
/// <summary> /// Заполнение хеш таблицы данными о fb2-книгах в контексте их Названия /// </summary> /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param> /// <param name="SrcPath">путь к fb2-файлу;</param> /// <param name="htFB2ForBT">Хеш Таблица с книгами с одинаковыми Названиями</param> private void MakeFB2BTHashTable(string ZipPath, string SrcPath, HashtableClass htFB2ForBT) { FictionBook fb2 = null; try { fb2 = new FictionBook(SrcPath); } catch (Exception ex) { Debug.DebugMessage( SrcPath, ex, "Дубликатор.CompareForm.MakeFB2BTHashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте их Названия." ); _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath); return; } string Encoding = fb2.getEncoding(); if (string.IsNullOrWhiteSpace(Encoding)) { Encoding = "?"; } BookTitle bookTitle = fb2.TIBookTitle; string BT = "<Название книги отсутствует>"; if (bookTitle != null && !string.IsNullOrWhiteSpace(bookTitle.Value)) { BT = bookTitle.Value.Trim(); } // данные о книге BookData fb2BookData = new BookData( bookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, fb2.DIID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding ); if (ZipPath != null) { fb2BookData.Path = ZipPath; } if (!htFB2ForBT.ContainsKey(BT)) { // такой книги в числе дублей еще нет FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, BT); htFB2ForBT.Add(BT, fb2f); } else { // такая книга в числе дублей уже есть FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForBT[BT]; fb2f.Add(fb2BookData); //htFB2ForBT[sBT] = fb2f; //ИЗБЫТОЧНЫЙ КОД } }
/// <summary> /// Сортировка ключей (групп) /// </summary> /// <param name="htBookGroups">Хэш-таблица Групп</param> /// <returns>Список List объектов типа string значений отсортированных ключей хэш-таблицы</returns> public List <string> makeSortedKeysForGroups(HashtableClass htBookGroups) { List <string> keyList = new List <string>(); foreach (string key in htBookGroups.Keys) { keyList.Add(key); } keyList.Sort(); return(keyList); }
/// <summary> /// Заполнение хеш таблицы данными о fb2-книгах в контексте их ID /// </summary> /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param> /// <param name="SrcPath">путь к fb2-файлу;</param> /// <param name="htFB2ForID">Хеш Таблица с книгами с одинаковыми ID</param> private void MakeFB2IDHashTable(string ZipPath, string SrcPath, ref HashtableClass htFB2ForID) { FictionBook fb2 = null; try { fb2 = new FictionBook(SrcPath); } catch (Exception ex) { Debug.DebugMessage( SrcPath, ex, "Дубликатор.CompareForm.MakeFB2IDHashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте их ID." ); _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath); return; } string Encoding = fb2.getEncoding(); if (string.IsNullOrWhiteSpace(Encoding)) { Encoding = "?"; } string ID = fb2.DIID; if (string.IsNullOrEmpty(ID) || string.IsNullOrWhiteSpace(ID)) { ID = _compComm.NoOrEmptyBookIDString; } // данные о книге BookData fb2BookData = new BookData( fb2.TIBookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, ID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding ); if (ZipPath != null) { fb2BookData.Path = ZipPath; } if (!htFB2ForID.ContainsKey(ID)) { // такой книги в числе дублей еще нет FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, ID); htFB2ForID.Add(ID, fb2f); } else { // такая книга в числе дублей уже есть FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForID[ID]; fb2f.Add(fb2BookData); //htFB2ForID[sID] = fb2f; //ИЗБЫТОЧНЫЙ КОД } }
/// <summary> /// Удаление элементов таблицы, value (списки) которых состоят из 1-го элемента (это не копии) /// </summary> /// <param name="ht">Хеш Таблица, в которой производится удаление элементов по заданному алгоритму</param> public void removeNotCopiesEntryInHashTable(HashtableClass ht) { List <DictionaryEntry> notCopies = new List <DictionaryEntry>(); foreach (DictionaryEntry entry in ht) { FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)entry.Value; if (fb2f.Count == 1) { notCopies.Add(entry); } } foreach (var ent in notCopies) { ht.Remove(ent.Key); } }
/// <summary> /// Хэширование по одинаковым Авторам в пределах сгенерированных групп книг по одинаковым названиям /// </summary /// <param name="bw">Экземплар фонового обработчика класса BackgroundWorker</param> /// <param name="e">Экземпляр класса DoWorkEventArgs</param> /// <param name="htFB2ForBT">Заполненная хеш-таблица списками книг по критерию одинакового Названия книг</param> /// <param name="htBookTitleAuthors">Заполняемая хеш-таблица списками книг по критерию ( Название книги (Авторы) )</param> /// <param name="WithMiddleName">Учитывать ли отчество Авторов (true) или нет (false) при поиске</param> /// <returns>Признак непрерывности обработки файлов</returns> public bool FilesHashForAuthorsParser(BackgroundWorker bw, DoWorkEventArgs e, Label StatusLabel, ProgressBar ProgressBar, HashtableClass htFB2ForBT, HashtableClass htBookTitleAuthors, bool WithMiddleName) { StatusLabel.Text += "Хеширование по Авторам книг...\r"; ProgressBar.Maximum = htFB2ForBT.Values.Count; ProgressBar.Value = 0; // генерация списка ключей хеш-таблицы (для удаления обработанного элемента таблицы) List <string> keyList = _compComm.makeSortedKeysForGroups(htFB2ForBT); // группировка книг по одинаковым Авторам в пределах сгенерированных Групп книг по одинаковым Названиям int i = 0; foreach (string key in keyList) { // разбивка на группы для одинакового Названия по Авторам Hashtable htGroupAuthors = FindDupForAuthors((FB2FilesDataInGroup)htFB2ForBT[key], WithMiddleName); foreach (FB2FilesDataInGroup fb2List in htGroupAuthors.Values) { if (!htBookTitleAuthors.ContainsKey(fb2List.Group)) { htBookTitleAuthors.Add(fb2List.Group, fb2List); } else { FB2FilesDataInGroup fb2ListInGroup = (FB2FilesDataInGroup)htBookTitleAuthors[fb2List.Group]; fb2ListInGroup.AddRange(fb2List); } } // удаление обработанной группы книг, сгруппированных по одинаковому названию htFB2ForBT.Remove(key); bw.ReportProgress(++i); if (bw.CancellationPending) { e.Cancel = true; return(false); } } return(true); }
/// <summary> /// Хэширование fb2-файлов по ID книги в пределах одинаковых Авторов Книги /// 10. Автор(ы), Одинаковый Id Книги /// </summary /// <param name="bw">Экземплар фонового обработчика класса BackgroundWorker</param> /// <param name="e">Экземпляр класса DoWorkEventArgs</param> /// <param name="htAuthors">Хэш Таблица с книгами по критерию одинаковости их Авторов</param> /// <param name="htWorkingBook">Хэш Таблица с книгами по критерию одинаковости их ID</param> /// <returns>Признак непрерывности обработки файлов</returns> public bool FilesHashForAuthorsBookIDParser(ref BackgroundWorker bw, ref DoWorkEventArgs e, Label StatusLabel, ProgressBar ProgressBar, ref HashtableClass htBookTitleAuthors, ref HashtableClass htWorkingBook) { StatusLabel.Text += "Хэширование по ID книги в пределах одинаковых Авторов...\r"; ProgressBar.Maximum = htBookTitleAuthors.Count; ProgressBar.Value = 0; // генерация списка ключей хеш-таблицы (для удаления обработанного элемента таблицы) List <string> keyList = _compComm.makeSortedKeysForGroups(htBookTitleAuthors); // группировка книг по одинаковым Id Книги в пределах сгенерированных Групп книг одинаковых Авторов int i = 0; foreach (string key in keyList) { // разбивка на группы для одинакового Id книги по Названию и по Авторам Hashtable AuthorsTitleBookID = FindDupForAuthorsID((FB2FilesDataInGroup)htBookTitleAuthors[key]); foreach (FB2FilesDataInGroup fb2List in AuthorsTitleBookID.Values) { if (!htBookTitleAuthors.ContainsKey(fb2List.Group)) { htWorkingBook.Add(fb2List.Group, fb2List); } else { FB2FilesDataInGroup fb2ListInGroup = (FB2FilesDataInGroup)htBookTitleAuthors[fb2List.Group]; fb2ListInGroup.AddRange(fb2List); } } // удаление обработанной группы книг, сгруппированных по одинаковому Автору htBookTitleAuthors.Remove(key); bw.ReportProgress(++i); if (bw.CancellationPending) { e.Cancel = true; return(false); } } return(true); }
/// <summary> /// Хеширование файлов в контексте Id книг: /// Одинаковый Id Книги (копии и/или разные версии правки одной и той же книги) /// </summary> /// <param name="FilesList">Список файлов для сканированияl</param> /// <param name="htFB2ForID">Хеш Таблица с книгами с одинаковыми ID</param> /// <returns>Признак непрерывности обработки файлов</returns> public bool FilesHashForIDParser(BackgroundWorker bw, DoWorkEventArgs e, Label StatusLabel, ProgressBar ProgressBar, string TempDir, List <string> FilesList, HashtableClass htFB2ForID) { StatusLabel.Text += "Хэширование по Id книг...\r"; ProgressBar.Maximum = FilesList.Count; ProgressBar.Value = 0; List <string> FinishedFilesList = new List <string>(); for (int i = 0; i != FilesList.Count; ++i) { if (FilesWorker.isFB2File(FilesList[i])) { // заполнение хеш таблицы данными о fb2-книгах в контексте их ID MakeFB2IDHashTable(null, FilesList[i], ref htFB2ForID); // обработанные файлы FinishedFilesList.Add(FilesList[i]); } else { if (FilesWorker.isFB2Archive(FilesList[i])) { try { if (_sharpZipLib.UnZipFB2Files(FilesList[i], TempDir) != -1) { string[] files = Directory.GetFiles(TempDir); if (files.Length > 0) { if (FilesWorker.isFB2File(files[0])) { // заполнение хеш таблицы данными о fb2-книгах в контексте их ID MakeFB2IDHashTable(FilesList[i], files[0], ref htFB2ForID); // обработанные файлы FinishedFilesList.Add(FilesList[i]); } } } } catch (Exception ex) { Debug.DebugMessage( FilesList[i], ex, "Дубликатор.CompareForm.FilesHashForIDParser(): Хеширование файлов в контексте Id книг." ); } FilesWorker.RemoveDir(TempDir); } } bw.ReportProgress(i); // отобразим данные в контролах if (bw.CancellationPending) { // удаление из списка всех файлов обработанных книг WorksWithBooks.removeFinishedFilesInFilesList(ref FilesList, ref FinishedFilesList); e.Cancel = true; return(false); } } // удаление элементов таблицы, value (списки) которых состоят из 1-го элемента (это не копии) _compComm.removeNotCopiesEntryInHashTable(htFB2ForID); // удаление из списка всех файлов обработанных книг WorksWithBooks.removeFinishedFilesInFilesList(ref FilesList, ref FinishedFilesList); return(true); }
// ============================================================================================= // СОХРАНЕНИЕ РЕЗУЛЬТАТА ПОИСКА КОПИЙ В XML-ФАЙЛЫ // ============================================================================================= #region Сохранение результата поиска копий в xml-файлы /// <summary> /// Сохранение результата сразу в xml-файлы без построения визуального списка /// </summary> /// <param name="bw">Ссылка на объект класса BackgroundWorker</param> /// <param name="e">Ссылка на объект класса DoWorkEventArgs</param> /// <param name="GroupCountForList">Число Групп в Списке Групп</param> /// <param name="CompareMode">Вид сравнения при поиске копий</param> /// <param name="CompareModeName">Название вида сравнения при поиске копий</param> /// <param name="ht">Хэш-таблица данных на Группы (копии fb2 книг по Группам)</param> /// <returns>Признак непрерывности обработки файлов</returns> public bool saveCopiesListToXml(BackgroundWorker bw, DoWorkEventArgs e, int GroupCountForList, int CompareMode, string CompareModeName, Label StatusLabel, ProgressBar ProgressBar, ref StatusView sv, string SourceDir, bool ScanSubDirs, int GroupCountForListIndex, bool IsSaveGroupToXMLWithoutTree, HashtableClass ht) { // блокировка отмены сохранения результата в файлы StatusLabel.Text += "Сохранение результата поиска в xml-файлы (папка '_Copies') без построения дерева копий...\r"; ProgressBar.Maximum = ht.Values.Count; ProgressBar.Value = 0; const string ToDirName = "_Copies"; if (!Directory.Exists(ToDirName)) { Directory.CreateDirectory(ToDirName); } // "сквозной" счетчик числа групп для каждого создаваемого xml файла копий int ThroughGroupCounterForXML = 0; // счетчик (в границых CompareModeName) числа групп для каждого создаваемого xml файла копий int GroupCounterForXML = 0; // номер файла - для формирования имени создаваемого xml файла копий int XmlFileNumber = 0; // копии fb2 книг по группам if (ht.Values.Count > 0) { XDocument doc = createXMLStructure(CompareMode, CompareModeName, SourceDir, ScanSubDirs, GroupCountForListIndex, IsSaveGroupToXMLWithoutTree); int BookInGroups = 0; // число книг (books) в Группах (Groups) int GroupCountInGroups = 0; // число Групп (Group count) в Группах (Groups) int i = 0; // прогресс bool one = false; // сортировка ключей (групп) List <string> keyList = makeSortedKeysForGroups(ht); foreach (string key in keyList) { ++sv.Group; // число групп одинаковых книг // формирование представления Групп с их книгами addAllBookInGroup(bw, e, doc, (FB2FilesDataInGroup)ht[key], ref BookInGroups, ref GroupCountInGroups, ref sv); ++GroupCounterForXML; ++ThroughGroupCounterForXML; doc.Root.Element("SelectedItem").SetValue("0"); if (GroupCountForList <= ht.Values.Count) { if (GroupCounterForXML >= GroupCountForList) { string FileNumber = StringProcessing.makeNNNStringOfNumber(++XmlFileNumber) + ".dup_lbc"; setDataForNode(doc, GroupCountInGroups, BookInGroups); doc.Save(Path.Combine(ToDirName, FileNumber)); StatusLabel.Text += "Файл: '_Copies\\" + FileNumber + "' создан...\r"; doc.Root.Element("Groups").Elements().Remove(); GroupCountInGroups = 0; GroupCounterForXML = 0; BookInGroups = 0; } else { // последний диаппазон Групп if (ThroughGroupCounterForXML == ht.Values.Count) { string FileNumber = StringProcessing.makeNNNStringOfNumber(++XmlFileNumber) + ".dup_lbc"; setDataForNode(doc, GroupCountInGroups, BookInGroups); doc.Save(Path.Combine(ToDirName, FileNumber)); StatusLabel.Text += "Файл: '_Copies\\" + FileNumber + "' создан...\r"; } } } else { setDataForNode(doc, GroupCountInGroups, BookInGroups); one = true; } bw.ReportProgress(i++); if (bw.CancellationPending) { e.Cancel = true; return(false); } } // по всем Группам if (one) { StatusLabel.Text += @"Файл: '_Copies\001.dup_lbc' ...\r"; doc.Save(Path.Combine(ToDirName, "001.dup_lbc")); } } return(true); }