Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.91/11: Рейтинг темы: голосов - 11, средняя оценка - 4.91
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
1

Как архивировать Dictionary<string, Dictionary<string, decimal[,]>>

11.10.2018, 16:45. Просмотров 1977. Ответов 16
Метки нет (Все метки)

Программа периодически создает Dictionary<string, Dictionary<string, decimal[,]>> большого размера. Как сжать gzip такой словарь перед его записью на диск?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.10.2018, 16:45
Ответы с готовыми решениями:

Dictionary<Tuple<string,string>, Dictionary<int,int>> dict - возможно ли?
Собственно вопрос в заголовке. Возможно ли использовать объект вида...

Как выдернуть данные из Dictionary<string,string>.Enumerator?
Есть библиотека xNet. Когда делаешь http запрос вот так: var ss =...

Как преобразовать Dictionary<string, int> в Dictionary<object, int>
Есть метод с сигнатурой public KeyValuePair&lt;string, int&gt; MyMethod(Dictionary&lt;string, int&gt; dic,...

Сложный Dictionary<MyClass, Dictionary<List<MyClass2>, List<string>>> MyDictionary
Здравствуйте. Помогите plz реализовать обращения к словарю вида : Dictionary&lt;MyClass,...

16
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
11.10.2018, 16:49 2
Passerby, как сейчас делается запись? Интересует код.
0
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
11.10.2018, 18:35  [ТС] 3
Создан класс с атрибутом [Serializable], в котором объявлен Dictionary<string, Dictionary<string, decimal[,]>>. В объекте этого класса объявленный словарь приравнивается к словарю, который надо сохранить. И сериализация.
Но код могу как угодно изменять (программу пишу для себя).
0
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
11.10.2018, 19:54 4
Лучший ответ Сообщение было отмечено Passerby как решение

Решение

Passerby, вот так можно:
C#
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
void Main()
{
    Test t1 = new Test();
    t1.dict = new Dictionary<string, Dictionary<string, decimal[,]>>();
    t1.dict.Add("aaa", new Dictionary<string, decimal[,]> {
        {"11", new decimal[,] { {1,2,3}, {4,5,6} } }
    });
    t1.dict.Add("bbb", new Dictionary<string, decimal[,]> {
        {"22", new decimal[,] { {1,2}, {3,4}, {5,6} } },
        {"33", new decimal[,] { {10,20}, {30,40}, {50,60} } },
    });
    
    // Сериализация
    using (var fstream = File.Create(@"d:\temp\cyberforum\dict.bin"))
    using(var gzipStream = new GZipStream(fstream, CompressionMode.Compress))
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(gzipStream, t1);
    }
 
    // Десериализация
    Test t2;
    using (var fstream = File.OpenRead(@"d:\temp\cyberforum\dict.bin"))
    using(var gzipStream = new GZipStream(fstream, CompressionMode.Decompress))
    {
        var formatter = new BinaryFormatter();
        t2 = (Test)formatter.Deserialize(gzipStream);
    }
    
    t2.Dump();
}
 
[Serializable]
class Test
{
    public Dictionary<string, Dictionary<string, decimal[,]>> dict;
}
Пример написан в LINQPad
2
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
28.04.2019, 02:00  [ТС] 5
Есть несколько таких словарей, которые надо записывать. Т.к. запись на HDD происходит последовательно (сначала один сжатый словарь, затем другой), хотелось бы отделить сжатие разных словарей (каждый в своем потоке) от последующей последовательной их записи. Можно ли это сделать?
0
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
28.04.2019, 18:17 6
Passerby, можно, но я не уверен что в этом есть смысл. В текущей реализации данные сжимаются и сразу записываются в файл. С потоками придется все данные держать целиком в памяти перед записью.
0
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
28.04.2019, 20:34  [ТС] 7
Цитата Сообщение от OwenGlendower Посмотреть сообщение
С потоками придется все данные держать целиком в памяти перед записью.
Памяти достаточно. Как можно сжать данные в память?
0
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
28.04.2019, 20:39 8
Passerby, пиши в MemoryStream
1
Модератор
8272 / 5646 / 1630
Регистрация: 21.04.2018
Сообщений: 16,863
Записей в блоге: 2
28.04.2019, 20:53 9
Цитата Сообщение от Passerby Посмотреть сообщение
Памяти достаточно. Как можно сжать данные в память?
Вы не получите ускорение по сравнению с последовательной записью данных в обычный файл.

Если сжатие данных это медленный процесс, то есть сопоставимый с записью файла, то Вам нужно в разных параллельных методах сжимать и записывать данные. А не вызывать их последовательно друг за другом.

Добавлено через 3 минуты
При параллельной сериализации нескольких объектов в MemoryStream Вы получите несколько этих MemoryStream.
Следовательно Вам надо продумать как эти несколько MemoryStream сохранить в один общий файл данных.
0
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
28.04.2019, 21:02 10
Passerby, сколько всего у тебя словарей? Сколько в них элементов? Какой размер итогового файла?
1
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
28.04.2019, 22:02  [ТС] 11
Как исправить десериализацию, чтобы не было ошибки?
C#
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
Dictionary<string, decimal> dict = new Dictionary<string, decimal>() { { "a", 10m }, { "b", 9 }, { "c", 8 }, { "d", 11 }, { "e", 12 }, { "f", 3 } };
                       
            MemoryStream mstream = new MemoryStream(); 
            Task task1 = new Task(() =>
                                     {
                                         using (var gzipStream = new GZipStream(mstream, CompressionMode.Compress))
                                         {
                                             var formatter = new BinaryFormatter();
                                             formatter.Serialize(gzipStream, dict);
                                         }
                                     });
            task1.Start();
            await Task.WhenAll(task1/*, task2, task3, task4, task5, task6*/);
            using (Stream fStream = new FileStream("dict" + ".dat",
                                                                FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
            {
                BinaryFormatter binFormat = new BinaryFormatter();
                binFormat.Serialize(fStream, mstream);
            }
            mstream.Dispose();
 
            Dictionary<string, decimal> dict1;
            using (var fstream = File.OpenRead("dict.dat"))
            using (var gzipStream = new GZipStream(fstream, CompressionMode.Decompress))
            {
                var formatter = new BinaryFormatter();
                dict1 = (Dictionary<string, decimal>)formatter.Deserialize(gzipStream);
            }
Добавлено через 2 минуты
Цитата Сообщение от OwenGlendower Посмотреть сообщение
сколько всего у тебя словарей? Сколько в них элементов? Какой размер итогового файла?
Словарей 6, создаю 6 файлов общим размером около 123 мбайт.

Добавлено через 8 минут
В каждом словарей разное количество элементов. Пар от 100 до более 600, где Value это decimal[,] размером 2000 x 3.
0
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
28.04.2019, 22:39 12
Лучший ответ Сообщение было отмечено Passerby как решение

Решение

Passerby, во-первых, всегда следует приводить текст ошибки. Во-вторых, каждый Task должен писать в свой MemoryStream. Иначе данные перепутаются или придется синхронизировать доступ к общему MemoryStream что лишит смысла применение Task. В третьих, сериализация через BinaryFormatter здесь не нужна.
C#
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
Dictionary<string, decimal> dict = new Dictionary<string, decimal>() { { "a", 10m }, { "b", 9 }, { "c", 8 }, { "d", 11 }, { "e", 12 }, { "f", 3 } };
           
Task<MemoryStream> task1 = new Task<MemoryStream>(() =>
                         {
                            MemoryStream mstream = new MemoryStream(); 
                             using (var gzipStream = new GZipStream(mstream, CompressionMode.Compress, leaveOpen:true))
                             {
                                 var formatter = new BinaryFormatter();
                                 formatter.Serialize(gzipStream, dict);
                             }
                             mstream.Position = 0;
                             return mstream;
                         });
                         
task1.Start();
await Task.WhenAll(task1/*, task2, task3, task4, task5, task6*/);
//using (Stream fStream = new FileStream("dict" + ".dat",
//                                                    FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
using (Stream fStream = File.Create(@"c:\my\dict" + ".dat"))
{
    var mstream = task1.Result;
    mstream.CopyTo(fStream);
    mstream.Dispose();
}
 
Dictionary<string, decimal> dict1;
using (var fstream = File.OpenRead("dict.dat"))
using (var gzipStream = new GZipStream(fstream, CompressionMode.Decompress))
{
    var formatter = new BinaryFormatter();
    dict1 = (Dictionary<string, decimal>)formatter.Deserialize(gzipStream);
}
Добавлено через 9 минут
И еще лучше бы убрать FileShare.Write.
2
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
28.04.2019, 22:58  [ТС] 13
Спасибо. А в чем была ошибка?
0
Миниатюры
Как архивировать Dictionary<string, Dictionary<string, decimal[,]>>  
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
28.04.2019, 23:21 14
Passerby, из-за бинарной сериализации. Она записывает в поток не только данные, но и служебную информацию.
1
Модератор
8272 / 5646 / 1630
Регистрация: 21.04.2018
Сообщений: 16,863
Записей в блоге: 2
28.04.2019, 23:33 15
Цитата Сообщение от Passerby Посмотреть сообщение
А в чем была ошибка?
Вы сериализуете в файл тип MemoryStream
C#
3
           MemoryStream mstream = new MemoryStream();
C#
18
               binFormat.Serialize(fStream, mstream);
А хотите из файла десериализовать тип Dictionary<string, decimal>
C#
31
    dict1 = (Dictionary<string, decimal>)formatter.Deserialize(gzipStream);
Добавлено через 3 минуты
В каком порядке какие типы и как друг в друга сохраняете в таком же порядке надо и восстанавливать.

Ну, а в целом OwenGlendower, конечно, прав - сериализация через BinaryFormatter здесь не нужна.
1
-7 / 3 / 1
Регистрация: 22.09.2017
Сообщений: 242
29.04.2019, 01:04  [ТС] 16
Хотелось бы разобраться с ошибкой.
Если создаю поток в памяти в который помещаю сжатые данные и затем поток копирую в файл, то затем я смогу в обратном порядке из файла сделать поток в памяти и сосчитать его в словарь.
Но при десериализации та же ошибка. Почему?
C#
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
 Dictionary<string, decimal> dict = new Dictionary<string, decimal>() { { "a", 10m }, { "b", 9 }, { "c", 8 }, { "d", 11 }, { "e", 12 }, { "f", 3 } };
            MemoryStream mstream = new MemoryStream();
            Task task1 = new Task(() =>
                                     {
                                         using (var gzipStream = new GZipStream(mstream, CompressionMode.Compress))
                                         {
                                             var formatter = new BinaryFormatter();
                                             formatter.Serialize(gzipStream, dict);
                                         }
                                     });
            mstream.Position = 0;
            task1.Start();
            await Task.WhenAll(task1/*, task2, task3, task4, task5, task6*/);
 
            using (Stream fStream = new FileStream("dict" + ".dat",
                                                                FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
            {
                BinaryFormatter binFormat = new BinaryFormatter();
                binFormat.Serialize(fStream, mstream);
            }
            mstream.Dispose();
            Dictionary<string, decimal> dict1;
            using (var fstream = File.OpenRead("dict.dat"))
            using (var gzipStream = new GZipStream(fstream, CompressionMode.Decompress))
            {
                var formatter = new BinaryFormatter();
               var mstream1 = (MemoryStream)formatter.Deserialize(gzipStream);
               //уже ошибка
            }
0
Супер-модератор
Эксперт .NET
12690 / 10392 / 4323
Регистрация: 17.03.2014
Сообщений: 20,941
Записей в блоге: 1
29.04.2019, 09:35 17
Passerby, нет времени отвечать подробно. Закоментируй строку №24, 26 и выполняй десериализацию из fstream.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.04.2019, 09:35

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Обработать словарь типа Dictionary<string, string> и на выходе получить ступенчатый массив
Всем здравствуйте! Я только начинаю познавать программирование (около месяца).Поэтому прошу...

Данные загрузить в коллекцию Dictionary<string,string> скопировать в списки, перемешать и сформировать ключ
здравствуйте) в файле есть вопросы и ответы. данные из файла нужно загрузить в коллекцию...

Заполнить Dictionary<string, list<string>> из файла ресурсов
Всем привет! У меня появилась проблема, мне нужно заполнить Dictionary&lt;string, list&lt;string&gt;&gt; из...

Dictionary<string, List<string>> получить все подэлементы
Всем привет! Есть словарь Dictionary&lt;string, List&lt;string&gt;&gt; Dictionary&lt;string,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.