public static void Main303() { Console.WriteLine("Start Main303"); // Создадим типы записи и последовательности записей PType tp_rec = new PTypeRecord( new NamedType("id", new PType(PTypeEnumeration.integer)), new NamedType("name", new PType(PTypeEnumeration.sstring)), new NamedType("age", new PType(PTypeEnumeration.integer))); PType tp_seq = new PTypeSequence(tp_rec); // ======== Универсальная последовательность ========== Stream stream = File.Open(datadirectory_path + "data303.bin", FileMode.OpenOrCreate); UniversalSequenceBase sequence = new UniversalSequenceBase(tp_rec, stream); Random rnd = new Random(); int nelements = 10_000_000; // При заполнении массива, сохраним офсеты элементов в массиве long[] offsets = new long[nelements]; int[] keys = new int[nelements]; bool toload = true; if (toload) { sw.Restart(); sequence.Clear(); for (int i = 0; i < nelements; i++) { int key = nelements - i - 1; offsets[i] = sequence.AppendElement(new object[] { key, "Иванов" + key, rnd.Next(1, 110) }); keys[i] = key; } // отсортируем пару массивов keys, offsets по ключам Array.Sort(keys, offsets); sw.Stop(); Console.WriteLine($"Load of {nelements} elements. duration={sw.ElapsedMilliseconds}"); } else { int ind = 0; sequence.Scan((off, obj) => { offsets[ind] = off; keys[ind] = (int)((object[])obj)[0]; ind++; return(true); }); // отсортируем пару массивов keys, offsets по ключам Array.Sort(keys, offsets); } // Будем делать выборку элементов по ключу sw.Restart(); int ntests = 1000; for (int j = 0; j < ntests; j++) { int key = rnd.Next(nelements); int nom = Array.BinarySearch(keys, key); long off = offsets[nom]; object[] fields = (object[])sequence.GetElement(off); if (key != (int)fields[0]) { throw new Exception("1233eddf"); } //Console.WriteLine($"key={key} {fields[0]} {fields[1]} {fields[2]}"); } sw.Stop(); Console.WriteLine($"duration of {ntests} tests is {sw.ElapsedMilliseconds} ms."); }
public static void Demo101() { Console.WriteLine("Start Demo101"); // === Демонстрация базовых действий со структурами === // Создаем тип персоны PType tp_person = new PTypeRecord( new NamedType("id", new PType(PTypeEnumeration.integer)), new NamedType("name", new PType(PTypeEnumeration.sstring)), new NamedType("age", new PType(PTypeEnumeration.integer))); // делаем персону в объектном представлении object ivanov = new object[] { 7001, "Иванов", 20 }; // интерпретируем объект в контексте типа Console.WriteLine(tp_person.Interpret(ivanov, true)); // то же, но без имен полей Console.WriteLine(tp_person.Interpret(ivanov)); Console.WriteLine(); // Создадим поток байтов. Это мог бы быть файл: MemoryStream mstream = new MemoryStream(); // Поработаем через текстовый интерфейс TextWriter tw = new StreamWriter(mstream); TextFlow.Serialize(tw, ivanov, tp_person); tw.Flush(); // Прочитаем то что записали TextReader tr = new StreamReader(mstream); mstream.Position = 0L; string instream = tr.ReadToEnd(); Console.WriteLine($"======== instream={instream}"); Console.WriteLine(); // Теперь десериализуем ivanov = null; mstream.Position = 0L; ivanov = TextFlow.Deserialize(tr, tp_person); // проинтерпретируем объект и посмотрим Console.WriteLine(tp_person.Interpret(ivanov)); Console.WriteLine(); // ===== Последовательности ===== // Создаем тип последовательности персон PType tp_persons = new PTypeSequence(tp_person); // Сделаем генератор персон Random rnd = new Random(); Func <int, IEnumerable <object> > GenPers = nper => Enumerable.Range(0, nper) .Select(i => new object[] { i, "Иванов_" + i, rnd.Next(130) }); // Сгенерируем пробу и проинтерпретируем object sequobj = GenPers(20).ToArray(); Console.WriteLine(tp_persons.Interpret(sequobj)); Console.WriteLine(); // Чем плохо такое решение? Тем, что весь большой объект (последовательность записей) разворачивается в ОЗУ // Более экономным, как правило, является использование последовательностей string dbpath = @"D:/Home/data/GetStarted/"; Stream filestream = new FileStream(dbpath + "db0.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite); UniversalSequenceBase usequence = new UniversalSequenceBase(tp_person, filestream); // Последовательность можно очистить, в нее можно добавлять элементы, в конце добавлений нужно сбросить буфер int npersons = 1_000_000; usequence.Clear(); foreach (object record in GenPers(npersons)) { usequence.AppendElement(record); } usequence.Flush(); // Теперь можно сканировать последовательность int totalages = 0; usequence.Scan((off, ob) => { totalages += (int)((object[])ob)[2]; return(true); }); Console.WriteLine($"total ages = {totalages}"); //// Можно прочитать i-ый элемент //int ind = npersons * 2 / 3; //object ores = usequence.GetByIndex(ind); //Console.WriteLine($"element={tp_person.Interpret(ores)}"); //// Но нет - облом: Размер элемента не фиксирован (есть строка), к таким элементам по индексу обращаться не надо }