private void MergeUp(long start, long number1, long number2, KeyString keyfunction) { if (number1 == 0 || number2 == 0) { return; } PTypeSequence pts = (PTypeSequence)typ; int size = pts.ElementType.HeadSize; // Заведем файл для верхнего массива string tmp_name = "../../../Databases/temp.bin"; System.IO.FileStream tmp = new System.IO.FileStream(tmp_name, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None, 10000); // Cкопируем нужное число байтов int buff_size = 8192; byte[] buffer = new byte[buff_size]; PxEntry entry1 = this.Element(start); long pointer = entry1.offset; this.fis.SetOffset(pointer); long bytestocopy = number1 * size; while (bytestocopy > 0) { int nb = this.fis.fs.Read(buffer, 0, bytestocopy < buff_size ? (int)bytestocopy : buff_size); tmp.Write(buffer, 0, nb); bytestocopy -= nb; } // Вычислим и запомним во временной ячейке ключи массива 1. // сначала тип ячейки и ячейка: PType tp_tmp = new PType(PTypeEnumeration.sstring); string tmp_cell_name = "../../../Databases/tmp.pac"; PaCell tmp_cell = new PaCell(tp_tmp, tmp_cell_name, false); // теперь заполним ее значениями //tmp_cell.StartSerialFlow(); //tmp_cell.S(); //for (long ii=0; ii<number1; ii++) //{ // string key = keyfunction(entry1); // tmp_cell.V(key); // entry1.offset += size; //} //tmp_cell.Se(); //tmp_cell.EndSerialFlow(); tmp_cell.Fill(new object[0]); for (long ii = 0; ii < number1; ii++) { string key = keyfunction(entry1); tmp_cell.Root.AppendElement(key); entry1.offset += size; } tmp_cell.Flush(); // теперь будем сливать массивы tmp.Position = 0L; // в файле tmp long pointer2 = pointer + number1 * size; long tmp_offset = tmp_cell.Root.Element(0).offset; tmp_cell.SetOffset(tmp_offset); PType tp_sstring = new PType(PTypeEnumeration.sstring); string key1 = (string)tmp_cell.ScanObject(tp_sstring); long cnt1 = 1; // число прочитанных элементов первой подпоследовательности PxEntry entry2 = this.Element(start + number1); string key2 = keyfunction(entry2); long cnt2 = 1; // число прочитанных элементов второй подпоследовательности byte[] buff_el = new byte[size * 8192]; int buff_pos = 0; while (cnt1 > number1 || cnt2 > number2) { if (key1.CompareTo(key2) < 0) { // Продвигаем первую подпоследовательность tmp.Read(buff_el, buff_pos, size); buff_pos += size; key1 = (string)tmp_cell.ScanObject(tp_sstring); cnt1++; } else { // Продвигаем вторую последовательность entry2.fis.SetOffset(entry2.offset); entry2.fis.fs.Read(buff_el, buff_pos, size); buff_pos += size; entry2.offset += size; key2 = keyfunction(entry2); cnt2++; } } // Теперь надо переписать остатки }
private void MergeUp <T>(long start, long number1, long number2, Func <PxEntry, T> keyfunction) { if (number1 == 0 || number2 == 0) { return; } PTypeSequence pts = (PTypeSequence)typ; int size = pts.ElementType.HeadSize; string tmp_name = "../../../Databases/temp.bin"; System.IO.FileStream tmp = new System.IO.FileStream(tmp_name, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None, 10000); // Cкопируем нужное число байтов int buff_size = 8192; byte[] buffer = new byte[buff_size]; PxEntry entry1 = this.Element(start); long pointer = entry1.offset; this.fis.SetOffset(pointer); long bytestocopy = number1 * size; while (bytestocopy > 0) { int nb = this.fis.fs.Read(buffer, 0, bytestocopy < buff_size ? (int)bytestocopy : buff_size); tmp.Write(buffer, 0, nb); bytestocopy -= nb; } // Вычислим и запомним во временной ячейке ключи массива 1. // сначала тип ячейки и ячейка: PxEntry entry2 = this.Element(start + number1); // Это понадобится в будущем, а пока используем для определения типа ключа IComparable key2 = (IComparable)keyfunction(entry2); PType tp_key = key2 is string?new PType(PTypeEnumeration.sstring) : (key2 is int?new PType(PTypeEnumeration.integer) : (key2 is long?new PType(PTypeEnumeration.longinteger) : (key2 is byte?new PType(PTypeEnumeration.@byte) : (key2 is double?new PType(PTypeEnumeration.real) : null)))); PType tp_tmp = new PTypeSequence(tp_key); string tmp_cell_name = "../../../Databases/tmp.pac"; //TODO: Надо имя файла генерировать, а то могут быть коллизии PaCell tmp_cell = new PaCell(tp_tmp, tmp_cell_name, false); // теперь заполним ее значениями //tmp_cell.StartSerialFlow(); //tmp_cell.S(); //for (long ii = 0; ii < number1; ii++) //{ // var key = keyfunction(entry1); // tmp_cell.V(key); // entry1.offset += size; //} //tmp_cell.Se(); //tmp_cell.EndSerialFlow(); tmp_cell.Fill(new object[0]); for (long ii = 0; ii < number1; ii++) { var key = keyfunction(entry1); tmp_cell.Root.AppendElement(key); entry1.offset += size; } tmp_cell.Flush(); // теперь будем сливать массивы tmp.Position = 0L; // в файле tmp long pointer2 = pointer + number1 * size; long tmp_offset = tmp_cell.Root.Element(0).offset; tmp_cell.SetOffset(tmp_offset); //PType tp_sstring = new PType(PTypeEnumeration.sstring); IComparable key1 = (IComparable)tmp_cell.ScanObject(tp_key); long cnt1 = 0; // число переписанных элементов первой подпоследовательности //PxEntry entry2 = this.Element(start + number1); //var key2 = keyfunction(entry2); // Уже прочитан long cnt2 = 0; // число переписанных элементов второй подпоследовательности byte[] buff = new byte[size * 8192]; int buff_pos = 0; while (cnt1 == number1 || cnt2 == number2) { if (key1.CompareTo(key2) < 0) { // Продвигаем первую подпоследовательность tmp.Read(buff, buff_pos, size); buff_pos += size; cnt1++; if (cnt1 < number1) { key1 = (IComparable)tmp_cell.ScanObject(tp_key); // Возможен конец } } else { // Продвигаем вторую последовательность entry2.fis.SetOffset(pointer2); pointer2 += size; entry2.fis.fs.Read(buff, buff_pos, size); buff_pos += size; cnt2++; if (cnt2 < number2) { key2 = (IComparable)keyfunction(entry2); // Возможен конец } } // Если буфер заполнился, его надо сбросить if (buff_pos == buff.Length) { this.fis.SetOffset(pointer); this.fis.fs.Write(buff, 0, buff_pos); pointer += buff_pos; buff_pos = 0; } } // Теперь надо переписать остатки if (cnt1 < number1) { this.fis.SetOffset(pointer); // Здесь запись ведется подряд, без перемещений головки чтения/записи bytestocopy = (number1 - cnt1) * size; while (bytestocopy > 0) { int nbytes = buff.Length - buff_pos; if (bytestocopy < nbytes) { nbytes = (int)bytestocopy; } tmp.Read(buff, buff_pos, nbytes); buff_pos += nbytes; this.fis.fs.Write(buff, 0, buff_pos); buff_pos = 0; } } else if (cnt2 < number2) { bytestocopy = (number2 - cnt2) * size; while (bytestocopy > 0) { int nbytes = buff.Length - buff_pos; if (bytestocopy < nbytes) { nbytes = (int)bytestocopy; } this.fis.SetOffset(pointer2); //TODO: Здесь вроде я не то беру, надо разобраться (2 строчки ниже!) pointer2 += nbytes; tmp.Read(buff, buff_pos, nbytes); buff_pos += nbytes; this.fis.SetOffset(pointer); this.fis.fs.Write(buff, 0, buff_pos); pointer += buff_pos; buff_pos = 0; } } }