Dmytry
Гость
|
|
« : 24-11-2009 18:39 » |
|
Всем привет!У меня возникла такая проблема. Мне нужно написать программу в Visual studio 2008, которая выполняет поиск дублирующихся файлов в каталоге или на логическом диске. программа должна предоставлять следующие возможности: · выполнение поиска файлов, которые дублируются, в заданном пользователем адресном пространстве (логическом диске или каталоге); · сообщение пользователя о найденных дубликатах; возможность навигации между ними; · сжатие файлов-дубликатов за алгоритмом GZIP. Общие требования интерфейса программы (обязательные элементы): · поле введения адресного пространства, в котором будет выполняться поиск дубликатов; · форма с перечнем найденных файлов, которые дублируются, с возможностью их открытия прямо из дополнения (например, двойным нажатием левой кнопки мыши); · если несколько текстовых файлов имеют дубликаты, то они должны каким-то образом группироваться; например, на диске присутствуют два одинаковых файла - С:\doc\text1.txt но C:\temp\my\text11.txt, а также на этом диске есть еще три файла, которые дублируются, - С:\doc\text2.txt, C:\temp\text.txt но C:\temp\my\text2.txt; тогда пользователю должны представиться две группы файлов, которые дублируются, - text1.txt и text2.txt (названия групп могут быть любые); причем пользователь должен иметь возможность самому избрать из группы файл-оригинал и файл(и) -дублікати; · у пользователя должна быть возможность сжатия дубликатов за алгоритмом GZIP (за его желанием). На данном этапе у меня имеется следующее: Есть исходник написанного мной куска программы на С#: вот он http://files.mail.ru/LC6PT7На данном этапе моя программа по задающемуся пользователем пути отыскивает в каталогах текстовые файлы (*.txt), находит по алгоритму md5 хэш каждого файла сводя их в массив строк и выводя в отдельном текстовом поле формы программы(listbox1). Так вот у меня возникла проблема с тем ,что б потом из полученного масcива из хэшов найти одинаковые строки, свести их в новый массив и вывести в другое строковое поле listbox2. Может кто-нибудь подскажет как решить мою проблему?...буду премного благодарен. Дело в том что я застрял даже на том ,что не могу получить элементарный контроль над массивом - пытался вывести первую строку...ничего не получилось -почему то выводило все строки сразу.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #1 : 24-11-2009 21:44 » |
|
Бегло глянул код. Мне кажется, ты слегка забегаешь вперёд. Скажем, я не вижу оснований для того, чтобы сразу помещать значения в listbox - очевидно же, с ними потом будет неудобно работать. Поскольку listbox предназначен не для работы с данными, а для предоставления интерфейса. Поэтому функционально он сильно ограничен: ведь главное, что от него требуется, - рисовать список и реагировать на всякие клики в нём.
Если хочешь удобно работать с данными - изолируй собственно обработку от интерфейса. И выводи уже конкретные полученные результаты - хоть в тот же listbox - но уже после того, как все необходимые манипуляции произведены.
В твоём случае для первичной группировки хорошо подошла бы ассоциативная коллекция. Не знаю, есть ли в C# аналог multimap - но это было бы то, что надо для данной задачи. Если такого нет, можно взять Hashtable и использовать md5 в качестве ключа и какой-нибудь ArrayList для хранения списка значений. Ну и потом уже простеньким вложенным foreach можно хоть просто в столбик вывести значения, хоть разбив по группам.
|
|
« Последнее редактирование: 24-11-2009 21:46 от Вад »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #2 : 25-11-2009 06:51 » |
|
Вад, и еще надо сассоциировать строки в ListBox с идентификаторами map или напрямую с указателями. Опять же - не в курсе, как это в .NET реализовано. Иначе будут трудности с одноименными строками, если искать в map по ним.
|
|
« Последнее редактирование: 26-11-2009 17:00 от Sel »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dmytry
Гость
|
|
« Ответ #3 : 25-11-2009 12:13 » |
|
Спасибо огромное за советы!!!....Я вот тут нашел ссылку http://msdn.microsoft.com/ru-ru/libr...hashtable.aspxПытался вникнуть но не совсем уловил смысл: я так понял что у тебя будет список ключей md5 и список имен файлов ,которые принадлежат этим md5...То есть между ними образуется взаимосвязь и я смогу задавая например md5 сразу выводить имя файла ,что ему принадлежит?...но я не совсем понимаю, того как я буду забывать md5 именно массив ключей?....то есть мне сначала нужно будет найти md5 и потом занести их в массив ключей?..а как же потом они будут распознавать какому md5 соотвецтвует имя файла?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #4 : 25-11-2009 12:57 » |
|
Смотри. У тебя есть таблица, в которой хранятся пары "ключ-значение". Ключ - это вычисленный хэш. Для файлов-дубликатов хэш одинаковый. Стало быть, для одного вычисленного значения хэша существует один или более файлов (иначе откуда вообще взялось такое значение, как не из обсчёта функции для файла?).
Тогда возникает вопрос: как хранить список файлов, у которых одинаковый хэш? Самое простое решение, которое я вижу, - это хранить список файлов именно что в виде списка. Например, ArrayList<string>. И тогда можно для каждого значения md5 завести такой список. А организовать хранение списков - в ассоциативном массиве.
В общем, получается что-то вроде Hashtable<string, ArrayList<string> > - то есть, в таблице мы храним пары "<md5-строка>-<список путей к файлам>". Тогда при вычислении очередного хэша для очередного файла требуется лишь найти вычисленный хэш в таблице. Если есть - то добавить путь к значению (списку путей). Если нет - создать новый список, содержащий путь к файлу, и добавить в hashtable.
Соответственно, файлы сразу оказываются сгруппированы по дубликатам. В каждой ячейке таблицы хранится список эквивалентных между собой файлов.
Как я уже говорил, более удобной структурой был бы аналог multimap - там группировать не надо, поскольку позволяется хранить несколько значений с одинаковым ключом непосредственно в контейнере. Поэтому нет нужды надстраивать массив, и делать поиск по имени файла в такой структуре попроще.
|
|
« Последнее редактирование: 25-11-2009 13:00 от Вад »
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #5 : 25-11-2009 14:56 » |
|
Спасибо огромное буду разбираться ...Тока вот у меня еще парочка вопросиков: 1) Я так понял что мой алгоритм - кусок клда по нахождению хэша файла я оставляю..потом создаю Hashtable<string, ArrayList<string> >...в string записываю результаты нахождения хеша. А в ArrayList<string записываю список путей к файлам? Я просто не очень если честно понял вот это(извините за мою не отесаность просто у меня не такие серьезные и большие познания в программировании): "Тогда при вычислении очередного хэша для очередного файла требуется лишь найти вычисленный хэш в таблице. Если есть - то добавить путь к значению (списку путей). Если нет - создать новый список, содержащий путь к файлу, и добавить в hashtable. "
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #6 : 25-11-2009 15:10 » |
|
1) Я так понял что мой алгоритм - кусок клда по нахождению хэша файла я оставляю..потом создаю Hashtable<string, ArrayList<string> >...в string записываю результаты нахождения хеша. А в ArrayList<string записываю список путей к файлам? Да, всё так: в hashtable ключом служит md5-хэш, а в списках хранятся пути к файлам. А дальше всё просто. Hashtable - это, если брать совсем грубо, просто такая таблица, в которой каждому ключу-идентификатору соответствует значение (в нашем случае - список путей). Hashtable предоставляет возможность доступа к значению по ключу. Поиск при этом занимает сравнительно мало времени. Лучше я на грубом примере. Вот, скажем, у меня есть hashtable, где ключ - некоторая строка, а значение - другая строка (для простоты. на её месте может быть хоть массив, хоть что угодно). Код схематический, так что 100% корректность не гарантирую, просто общая идея: Hashtable <string, string> myhash; // добавляем значения: myhash.Add("sunday", "7"); myhash.Add("monday", "1"); // ... и так далее
string number = myhash["sunday"]; // - получаем значение по ключу
Если в качестве значения хранился бы массив - можно было бы получать к нему доступ абсолютно аналогично, и затем вызывать нужные методы. Например, что-то вот такое: Hashtable <string, ArrayList<string> > myhash2; // как-то заполняем myhash2.Add("key", new ArrayList<string>()); // допустим, как-то так создаём новый список для нового ключа // ... // добавляем элемент к существующему массиву myhash2["key"].Add("c:/temp/1.txt");
В общем, смотри примеры манипулирования. Как проверить, существует ли элемент. Как добавить элемент. Как получить доступ к существующему элементу.
|
|
« Последнее редактирование: 25-11-2009 15:20 от Вад »
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #7 : 25-11-2009 15:35 » |
|
Понял тебя. Буду вникать. Cпасибо!!! А вот еще вопросик (может , он , конечно , покажется глупым , но все же): Что будет лежать конкретно в массиве listarray?? Что реальные пути к файлам??? То есть , ну допустим , D:\file\.... во т у меня просто в прог рамме есть массив типа FileInfo[] files, в который хранит список файлов в каталоге. С помощью foreach я получаю доступ к , насколько я понял , подма Ссиву file.Name , который содержит имена файлов. Потом , используя этот массив , я читаю файлы и нахожу ИХ хэши. Так , а здесь тогда получается , тоже будет он - file.Name или весь массив FileInfo[] files???
|
|
« Последнее редактирование: 26-11-2009 17:04 от Sel »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #8 : 25-11-2009 18:55 » |
|
Ну, я бы складывал абсолютные пути к файлам. Группировать их по каталогам и хранить относительные пути, конечно, лучше с точки зрения эффективности расхода памяти. Но для удобства лучше не делать лишних связей. Но если ты работаешь только в рамках конкретного каталога - то можно хранить пути относительно этого каталога.
То есть, берёшь список файлов в каталоге и сразу считаешь хэши и добавляешь результат в таблицу.
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #9 : 25-11-2009 18:59 » |
|
Понял..спасибо за ответ!!!
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #10 : 26-11-2009 06:40 » |
|
Блин , у меня появилась реальная проблема.... Мой алгоритм вычисления хэша н екорректно работает Получается , он работае ,т если текстовые файлы лежат в том каталоге, что я задаю непосредственно.... Если же в задан Ном мною каталоге лежат еще , допустим , 2 каталога и в них потом уже - искомые мною файлы - то все , программа не работает... Не могу никак понять ,что мне нужно подправить , что б все заработало вот код: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Security.Cryptography; using System.IO; using System.Collections; namespace kursovoy { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
}
static string getMd5Hash(string input) { // Create a new instance of the MD5CryptoServiceProvider object. MD5 md5Hasher = MD5.Create();
// Convert the input string to a byte array and compute the hash. byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes // and create a string. StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data // and format each one as a hexadecimal string. for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("x2")); }
// Return the hexadecimal string. return sBuilder.ToString(); }
// Verify a hash against a string. static bool verifyMd5Hash(string input, string hash) { // Hash the input. string hashOfInput = getMd5Hash(input);
// Create a StringComparer an comare the hashes. StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash)) { return true; } else { return false; } }
//Create a new hash table. Hashtable myhash = new Hashtable();
private void button1_Click(object sender, EventArgs e) {
// Каталог для створення файлів проекту string ProjDir = textBox1.Text;
//Отображение файлов в каталоге string searchPattern = @"*.txt";
DirectoryInfo di = new DirectoryInfo(ProjDir); DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.AllDirectories);
FileInfo[] files = di.GetFiles(searchPattern, SearchOption.AllDirectories);
foreach (DirectoryInfo dir in directories) { listBox2.Items.Add(dir.FullName); } //Объявление переменных string source2; string hash2; List<string> fileHashes = new List<string>();
//string[] array1=new string[100]; int j ; int c = files.Length; ;//длина массива из файлов в заданном каталоге то есть количество файлов int d = directories.Length;//длина массива из путей директорий то есть количество каталогов
foreach (FileInfo file in files) { for (j = 0; j < d; j++) { // Ім'я нового файлу string nameFileLab2 = @file.Name;
// Шлях до файлу string pathFileLab2 = System.IO.Path.Combine(ProjDir, nameFileLab2);
// Читання файлу string contents2 = System.IO.File.ReadAllText(pathFileLab2);
source2 = contents2; hash2 = getMd5Hash(source2);
fileHashes.Add(hash2);
listBox2.Items.Add(hash2); } }
listBox1.Items.Add(c); listBox1.Items.Add(d); for (j = 0; j < c; j++) { myhash.Add(fileHashes[j], files[j]); } listBox1.Items.Add(myhash[fileHashes[0]]); }
private void button2_Click(object sender, EventArgs e) { }
private void textBox1_TextChanged(object sender, EventArgs e) {
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e) {
}
private void Form1_Load(object sender, EventArgs e) {
} } }
|
|
« Последнее редактирование: 26-11-2009 17:00 от Sel »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #11 : 26-11-2009 07:48 » |
|
Ты берёшь файлы только из текущей директории. Чтобы обработать вложенные - нужно взять эти директории и спуститься в них рекурсивно.
Лучше выделить обработку файлов в директории в отдельную функцию и передавать в неё путь к директории в качестве параметра. А внутри вызывать для всех поддиректорий ту же самую функцию рекурсивно. Разумеется, при каждом новом вызове функция должна накапливать получаемые данные в одном и том же месте. То есть, список файлов придётся либо сделать полем класса, либо передавать в качестве параметра функции.
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #12 : 26-11-2009 17:56 » |
|
Спасибо за совет ...Но я тут пошарил и с помощью оссобеностей С шарпа сделала намного проще: вот код: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Security.Cryptography; using System.IO; using System.Collections; namespace kursovoy { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
}
static string getMd5Hash(string input) { // Create a new instance of the MD5CryptoServiceProvider object. MD5 md5Hasher = MD5.Create();
// Convert the input string to a byte array and compute the hash. byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes // and create a string. StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data // and format each one as a hexadecimal string. for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("x2")); }
// Return the hexadecimal string. return sBuilder.ToString(); }
// Verify a hash against a string. static bool verifyMd5Hash(string input, string hash) { // Hash the input. string hashOfInput = getMd5Hash(input);
// Create a StringComparer an comare the hashes. StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash)) { return true; } else { return false; } }
//Create a new hash table.
private void button1_Click(object sender, EventArgs e) {
//Объявление переменных string source2; string hash2; List<string> fileHashes = new List<string>(); List<string> pathtodir = new List<string>(); //string[] array1=new string[100]; // Каталог для створення файлів проекту string ProjDir = textBox1.Text;
//Отображение файлов в каталоге string searchPattern = "*.txt";
DirectoryInfo di = new DirectoryInfo(@ProjDir); DirectoryInfo[] directories = di.GetDirectories("*", SearchOption.AllDirectories);
FileInfo[] files = di.GetFiles(searchPattern, SearchOption.AllDirectories); int j; int c = files.Length; int d = directories.Length; foreach (DirectoryInfo dir in directories) { //listBox2.Items.Add(dir.FullName); pathtodir.Add(dir.FullName); }
foreach (FileInfo file in files) { // Ім'я нового файлу string nameFileLab2 = file.Name; string pathoffile = file.DirectoryName; // Шлях до файлу string pathFileLab2 = System.IO.Path.Combine(pathoffile, nameFileLab2);
// Читання файлу string contents2 = System.IO.File.ReadAllText(pathFileLab2); source2 = contents2; hash2 = getMd5Hash(source2);
fileHashes.Add(hash2); //listBox2.Items.Add(hash2); }
listBox3.Items.Add(c); listBox4.Items.Add(d); //fileHashes.Sort(); string[] keyarray = new string[c]; fileHashes.CopyTo(keyarray); for (j = 0; j < c; j++) { listBox2.Items.Add(files[j]); listBox1.Items.Add(keyarray[j]); }
Hashtable myhash = new Hashtable(); for (j = 0; j < c; j++) { myhash.Add(keyarray[j], files[j]); listBox1.Items.Add(myhash[fileHashes[j]]); } //listBox1.Items.Add(myhash[fileHashes[0]]); }
private void button2_Click(object sender, EventArgs e) { }
private void textBox1_TextChanged(object sender, EventArgs e) {
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e) {
}
private void Form1_Load(object sender, EventArgs e) {
}
private void listBox3_SelectedIndexChanged(object sender, EventArgs e) {
}
private void listBox4_SelectedIndexChanged(object sender, EventArgs e) {
} } }
Теперь перехожу непосредственно к составлению таблицы хэшей как ты и сказал...создал метод Hashtable...начал заполнять его масивом который хранит ключи и списком который хранит список файлов...Попытался по ключу найти соотвецтвующий ему файл...а оно мне выдало ошибку мол значение ключа уже забито в словарь массива ключей таблицы, то есть я так понял я пытаюсь добавить ключи в таблицу, которая их уже содержит.Посмотрел по коду - вроде как нигде до этого не заносил значения этих ключей.пробовал вывести файл по ключу не добавляя предварительно их в таблицу(то есть без строчки myhash.Add(keyarray, files[j])) -пишет что нет что выводить...что массив , как я понял из файлов пуст...в чем может быть проблема ,что ключи уже есть в словаре таблицы...может его нужно очистить сначала а потом заполнить по новому?
|
|
|
Записан
|
|
|
|
Sel
Злобный
Администратор
Offline
|
|
« Ответ #13 : 26-11-2009 18:43 » |
|
Dmytry, ты обратил внимание, что я правлю почти каждый твой пост?? Почини, наконец, свою клавиатуру, чтобы многоточия не лепила где попало, и научись расставлять знаки препинания (это "точки" и "запятые", если тебе не говорили об этом в школе). Будешь продолжать писать, как сейчас, буду удалять твои посты.
|
|
|
Записан
|
Слово не воробей. Всё не воробей, кроме воробья.
|
|
|
Dmytry
Гость
|
|
« Ответ #14 : 26-11-2009 19:01 » |
|
Хорошо,без вопросов
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #15 : 26-11-2009 19:09 » |
|
Dmytry, путанно пишешь. Не совсем понимаю, что происходит. Твоя проблема - в том, что ты громоздишь всё в одну кучу, и уже сложно разобраться, откуда ползёт ошибка. Программирование - это, в том числе, структурирование задачи. Возьми отдельно хэш-таблицу. Возьми пару пробных значений хэша и пару-тройку тестовых имён файлов. Попробуй добавить в хэш так, чтобы тестовые имена добавлялись для разных ключей. Потом для одного и того же ключа добавь два файла. Убедись, что всё организованно так, как задумано: пути хранятся в списках, списки хранятся в хэш-таблице, по одному экземпляру списка для одного ключа-хэша.
А уже потом прикручивай оттестированный код, который заведомо работает на тестовых данных, к основному коду. Попутно подумав, не стоит ли сделать как-нибудь так, чтобы этот оттестированный код как можно меньше соприкасался с окружающим кодом: ведь он решает свою отдельную задачу, и если его просто втыкать копипастом везде, где надо, в проекте будет каша.
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #16 : 26-11-2009 19:14 » |
|
Хорошо.Попробую
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #17 : 27-11-2009 14:31 » |
|
Я вот еще о чем думал (забегая немножко вперед): когда я, допустим, найду массив из моих дублированных файлов, то мне потом нужно будет выполнить следующее условие: "- форма с перечнем найденных файлов, которые дублируются, с возможностью их открытия прямо из дополнения (например, двойным нажатием левой кнопки мыши);". Так вот, меня волнует, какого типа у меня должен будет быть массив из моих дубликатов, чтобы потом я смог, кликнув мишкой по любому файлу, открыть его (думаю, что он будет открываться с помощью блокнота). И как вообще это можно реализовать будет - открытие файла с помощью блокнота двойным щелчком мыши???
|
|
« Последнее редактирование: 27-11-2009 17:21 от Sel »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #18 : 27-11-2009 15:11 » |
|
Чтобы открыть файл, нужен его полный путь. Чтобы открыть файл в блокноте, достаточно запустить блокнот с путём к файлу в качестве аргумента командной строки (например, "notepad C:\path_to_file\file.txt"). Для запуска внешних приложений есть масса способов. Например, есть WinAPI-функция ShellExecute - можно её импортировать в C#-код и использовать для запуска блокнота.
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #19 : 27-11-2009 15:52 » |
|
Спасибо! Теперь я еще лучше понимаю , зачем в хэш-таблице в паре "ключ-значение" значением должен быть путь к файлу
|
|
« Последнее редактирование: 27-11-2009 17:21 от Sel »
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #20 : 28-11-2009 11:50 » |
|
Пробовал твой совет"Попробуй добавить в хэш так, чтобы тестовые имена добавлялись для разных ключей. Потом для одного и того же ключа добавь два файла. Убедись, что всё организованно так, как задумано: пути хранятся в списках, списки хранятся в хэш-таблице, по одному экземпляру списка для одного ключа-хэша." -не все так гладко как хотелось...добавь для одного и того же ключа д файла не получается и скорее всего не возможно...так как ключи должны быть уникальны ну и соотвецтвенно значения тоже.Не знаю , может это у меня руки дырявые, но все что получилось сделать - создать хеш-таблицу , заполнить ее так как ты сказал(пути хранятся в списках, списки хранятся в хэш-таблице, по одному экземпляру списка для одного ключа-хэша.) //запис до хеш-таблиці//
Hashtable myhash = new Hashtable();//створення хеш-таблиці for (j = 0; j < c; j++) { myhash[keyarray[j]]=pathpathtodir[j];//заповнення таблиці ключами і відповідними їм значеннями listBox1.Items.Add(myhash[keyarray[j]]);//вивід результату пошуку значешь за заданими ключами }
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #21 : 28-11-2009 20:08 » |
|
Вот опять вперёд забегаешь. Что такое keyarray[j], что такое pathpathtodir[j]? Когда я говорю "тестовые данные", я говорю вот о чём: Hashtable myhash = new Hashtable(); // добавляем лист для ключа key1, если его ещё нет if (!myhash.Contains("key1")){ myhash.Add("key1", new ArrayList()); } // добавляем значение пути в ключ myhash["key1"].Add("C:\\file1.txt");
if (!myhash.Contains("key2"){ myhash.Add("key2", new ArrayList()); } myhash["key2"].Add("C:\\file2.txt"); // и ещё один файл myhash["key2"].Add("C:\\file3.txt");
и т.п. И вот когда "на пальцах" будет понятно, что всё работает как задумано (и что вообще понятно, как именно всё задумано) - тогда можно смело интегрировать этот код. Я вот пока не понимаю, откуда у тебя вдруг готовые списки берутся - по моей задумке, неоткуда им браться Их на месте создавать надо (что и отражает мой код)
|
|
« Последнее редактирование: 28-11-2009 20:21 от Вад »
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #22 : 29-11-2009 06:02 » |
|
"Что такое keyarray[j], что такое pathpathtodir[j]?" - отвечаю. В keyarray[j], хранятся уже все хэши файлов в указанной мною директории, а в pathpathtodir[j] - пути к файлам, что принадлежат этим хэшам.
Попробую немного объяснить ход своих мыслей: в начале нам не известно ни количество ключей, ни количество файлов, ни количествО дубликатов для заданного ключа. Я ввожу путь к директории, выполняется поиск файлов в этой директории, и находится хэш каждого файла. Потом эти хэши складываются в массив keyarray[j] в том порядке, в котором были найдены файлы в каталоге. А pathpathtodir[j] - это список путей к этим файлам, который был извлечен с помощью foreach из массива files[j], который имеет тип fileInfo, потому только с помощью foreach можно извлечь пути к файлам из массива files[j].
Я, вроде как, уловил ход твоих мыслей - Ты хочешь для каждого ключа создать свой список файлов, которые ему принадлежат. Твой пример это наглядно показывает. Но я все же не могу понять, как узнать, какие файлы добавлять к ключу, который им равен, то есть, то, что я и говорил - с начала не известно, какие файлы именно принадлежат ключу и сколько вообще этих ключей. Хотя твоя фраза "тогда можно смело интегрировать этот код" прольет свет и разгонит темные и густые облака моих раздумий и гаданий.
|
|
« Последнее редактирование: 29-11-2009 07:27 от Sel »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #23 : 29-11-2009 10:24 » |
|
"Что такое keyarray[j], что такое pathpathtodir[j]?" - отвечаю. В keyarray[j], хранятся уже все хэши файлов в указанной мною директории, а в pathpathtodir[j] - пути к файлам, что принадлежат этим хэшам.
Ты отвечаешь на вопрос, что в нём хранится, а не что такое pathpathtodir Это тоже нужная информация, но не вся. Нужна ещё важная информация: какой тип имеет элемент списка pathpathtodir? Допустим, что pathpathtodir представляет собой список списков путей. А список ключей-хэшей к нему хранится отдельно (в keyarray). Но в таком случае это дублирует подход, который я предлагал, просто вместо одного объекта (Hashtable) используется два (список ключей и список списков), и хэши хранятся просто в порядке поступления. Но я все же не могу понять, как узнать, какие файлы добавлять к ключу, который им равен, то есть, то, что я и говорил - с начала не известно, какие файлы именно принадлежат ключу и сколько вообще этих ключей.
Всё предельно просто. Сначала имеем пустой хэш. В этот момент мы ещё не начали вычислять хэши для содержимого файлов. Затем приступаем к вычислению хэшей для файлов и сразу, непосредственно добавляем пути файлов в хэш-таблицу. Для этого нужно выполнить следующие действия: 1. Проверить, существует ли уже запись в таблице для текущего хэша (myhash.Contains(<ключ>)) 2. Если ключа в таблице нет - это означает, что ранее для такого ключа значений не добавляли, и нужно создать пару "ключ-значение" для дальнейшего хранения списков: myhash.Add(<ключ>, new ArrayList()); 3. Добавить значение (путь к файлу) к списку путей для данного ключа: myhash[<ключ>].Add(<путь>); Вот и всё. Не надо узнавать, какие файлы добавлять к ключу: ты уже знаешь ключ для данного файла, и тебе всего лишь нужно добавить путь в таблицу по ключу, убедившись предварительно, что для данного ключа создан список путей.
|
|
« Последнее редактирование: 29-11-2009 10:27 от Вад »
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #24 : 29-11-2009 10:32 » |
|
"Ты отвечаешь на вопрос, что в нём хранится, а не что такое pathpathtodir Это тоже нужная информация, но не вся. Нужна ещё важная информация: какой тип имеет элемент списка pathpathtodir?" - как ты понял, это список списков путей. Тип у него string. Насчет "Затем приступаем к вычислению хэшей для файлов и сразу, непосредственно добавляем пути файлов в хэш-таблицу." - у меня алгоритм вычисления хэша работает только для строки . C массивом не работает(насколько я понял) . Я с помощью foreach брал из массива files[j] типа fileInfo имена файлов, читал их и сразу же находил их хэш. То есть , в результате у меня в переменной hash2 string хранятся хэши этих файлов. Потом я добавлял их в список fileHashes типа string для того , чт об получить контроль над каждым хэшем (кстати , keyarray -это просто копия списка fileHashes типа string[])
|
|
« Последнее редактирование: 29-11-2009 14:24 от Sel »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #25 : 29-11-2009 10:58 » |
|
Правильно. Хэши считаются по одному. Берём файл. Считаем хэш. Затем, если пользоваться хэш-таблицей, кладём имя файла в нужное место в хэш-таблице. По одному. Зачем тут какой-то массив?
Ведь ты же, когда группируешь файлы по хэшам в своём pathpathtodir - ты ведь всё равно как-то ищешь, в какой список тебе нужно положить файл? (иначе зачем нужны списки) А хэштаблица просто делает поиск проще и быстрее.
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #26 : 29-11-2009 11:06 » |
|
Так вроде понял сейчас буду корректировать и потом выложу код.Спасибо за разъяснение!!
|
|
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #27 : 29-11-2009 11:29 » |
|
Вот отредактировал и постарался сделать как можно больше разъяснений, что б тебе было ясно: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Security.Cryptography; using System.IO; using System.Collections; namespace kursovoy { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
}
static string getMd5Hash(string input) { // Create a new instance of the MD5CryptoServiceProvider object. MD5 md5Hasher = MD5.Create();
// Convert the input string to a byte array and compute the hash. byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes // and create a string. StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data // and format each one as a hexadecimal string. for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("x2")); }
// Return the hexadecimal string. return sBuilder.ToString(); }
// Verify a hash against a string. static bool verifyMd5Hash(string input, string hash) { // Hash the input. string hashOfInput = getMd5Hash(input);
// Create a StringComparer an comare the hashes. StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash)) { return true; } else { return false; } }
private void button1_Click(object sender, EventArgs e) {
listBox1.Items.Clear(); listBox2.Items.Clear(); //Объявление переменных string hash2;//объявление переменой ч тобудет хранить хэши List<string> fileHashes = new List<string>();//переменная списка хешей List<string> pathpathtodir = new List<string>();//переменная списка путей(по твоей рекомендации пока не использовал) // Каталог для створення файлів проекту string ProjDir = textBox1.Text;
//Отображение файлов в каталоге string searchPattern = "*.txt";
DirectoryInfo di = new DirectoryInfo(@ProjDir); DirectoryInfo[] directories = di.GetDirectories("*", SearchOption.AllDirectories);
FileInfo[] files = di.GetFiles(searchPattern, SearchOption.AllDirectories); //об`ява змінних та визначення довжини масивів файлів та директорій int j;//переменная для работы с масивами int c = files.Length;//количество файлов int d = directories.Length;//количество директорий
//занесення шляхів директорій у список pathtodir foreach (DirectoryInfo dir in directories) { pathpathtodir.Add(dir.FullName);//заношу пути в список путей(на будущее , вдруг понадобится) } //Читання масиву файлів та знаходження хешів цих файлів і додавання його у новій список fileHashes foreach (FileInfo file in files) { // Ім'я нового файлу string nameFileLab2 = file.Name;// переменная хранящая имя фалйов string pathoffile = file.DirectoryName;//переменная хранящая пути к файлам // Шлях до файлу string pathFileLab2 = System.IO.Path.Combine(pathoffile, nameFileLab2); // Читання файлу string contents2 = System.IO.File.ReadAllText(pathFileLab2); hash2 = getMd5Hash(contents2);///беру хэш файла fileHashes.Add(hash2);// это заносил в список хеэши , но по твое рекомендации ее не применял а только использовал для проверки работы вычисления хэша
//запис до хеш-таблиці// Hashtable myhash = new Hashtable();//створення хеш-таблиці // добавляем лист для ключа key1, если его ещё нет if (!myhash.Contains(hash2)) { myhash.Add(hash2, new ArrayList()); } // добавляем значение пути в ключ myhash[hash2] =file.DirectoryName; listBox2.Items.Add(file.DirectoryName);//Вывод путей для ключей
} //відображення кількості файлів та підкаталогів у заданому користувачем каталозі listBox3.Items.Add(c);//вывод кроличества файлов listBox4.Items.Add(d);//вывод количества каталогов в заданой мною директории for (j=0;j<c;j++) { listBox1.Items.Add(fileHashes[j]);//вывод списка хэшей тольк одля проверки работы нахождения хэша } }
private void button2_Click(object sender, EventArgs e) { }
private void textBox1_TextChanged(object sender, EventArgs e) {
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e) {
}
private void Form1_Load(object sender, EventArgs e) {
}
private void listBox3_SelectedIndexChanged(object sender, EventArgs e) {
}
private void listBox4_SelectedIndexChanged(object sender, EventArgs e) {
}
private void listBox5_SelectedIndexChanged(object sender, EventArgs e) {
} } }
|
|
« Последнее редактирование: 29-11-2009 11:32 от Dmytry »
|
Записан
|
|
|
|
Dmytry
Гость
|
|
« Ответ #28 : 29-11-2009 12:05 » |
|
Вроде сделал все ка ты сказал...откомпилировал и получил по сути то что до этого тоже получалось - список неупорядоченный путей к файлам. Вывод : либо это еще только вершина айсберга и дальше нудно еще что то сделать что б при сортировании ключей выводились отсортированные пути, либо - у меня руки вообще из не того места растут и я вывожу в форму ну совсем не то что нужно:( (нужно сгруппированные пути к файлам, то есть что бы дубликаты выводились рядом один с одним)
|
|
« Последнее редактирование: 29-11-2009 12:11 от Dmytry »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #29 : 29-11-2009 12:23 » |
|
Чтобы дубликаты выводились рядом, нужно всего лишь отделить сбор информации от её вывода. То есть, сначала в отдельном цикле заносить результат в хэш-таблицу. А затем в другом цикле выводить содержимое этой таблицы. (заодно можно будет, например, вставлять какие-нибудь разделители между элементами, чтобы было видно, какие именно файлы принадлежат к одной группе дубликатов). Второй цикл будет чем-то вроде foreach(DictionaryEntry d in myhash) { // Заносим все элементы из списка d.Value в ListBox } вот тогда всё будет сгруппировано
|
|
|
Записан
|
|
|
|
|