пятница, 12 июня 2015 г.

Распределенная запись одного набора данных в несколько файлов

Делюсь алгоритмом записи буфера данных любой длины M с любым смещением и авторазбивкой по файлам любой заданной длины. Работать будем с файловыми потоками разумеется...


{ Алгоритм записи буфера данных любой длины M с любым смещением
  и авторазбивкой по файлам любой заданной длины
  Автор: Бадло Сергей Григорьевич
  H-page: http://raxp.radioliga.com }


const size = 1024;          // размер файла-одиночки [0..1023]
      BUF_SIZE = 2000; // размер условного буфера (УБ) [0..m]
      poss = 1000;          // смещение - глобальная позиция начала УБ среди данных 0..N
                                  // количество данных 0..N может быть сколь-угодно большим
      ex = '.bin';
     
var t: tfilestream;
    buf, obuf: array of byte;
    i: integer;
    temp_pos, temp_start, temp_size, start, stop, ostatok: int64;
begin
 // условный буфер для тестов
 setlength(buf, BUF_SIZE);
 for i:= 0 to length(buf)-1 do
  buf[i]:= random(255);
 
 // определяем с какого файла начинать запись
 start:= trunc(poss / size);
 // на каком заканчиваем
 stop := trunc((poss + length(buf)) / size);
 // начальная реальная позиция УБ в cтартовом файле
 temp_pos:= trunc(size* ((poss / size) - trunc(poss / size)));
 temp_start:= 0; // выгребать первый раз начинаем с нулевого байта
 if size - temp_pos < length(buf) then // выгребаем кол-во байт в первый раз
  temp_size:= size - temp_pos
   else temp_size:= length(buf);
 ostatok:= length(buf);

 for i:= start to stop do begin
  t:= tfilestream.Create('File' + inttostr(i+1) + ex, fmOpenReadWrite or fmcreate);

  // устанавливаем размер куска данных для записи
  setlength(obuf, temp_size);
  // копируем temp_size-байт данных с позиции temp_start исходного буфера
  move(buf[temp_start], obuf[0], temp_size);

  t.Position:= temp_pos; // устанавливаем с какой позиции записывать в n-м файле
  t.WriteBuffer(obuf[0], temp_size);
  t.Free;

  // обнуляем данные
  setlength(obuf, 0);
  // с какого байта начинать выборку
  // в исходном условном буфере
  temp_start:= temp_start + size - temp_pos;
  // вычисляем размер следующего куска данных
  ostatok:= ostatok - temp_size;
  if ostatok > size then
   temp_size:= size
    else temp_size:= ostatok;

  temp_pos:= 0; // смысл в том, что если данные переносятся на следующий уровень,
                // то они всегда начинаются с нулевой позиции
 end;
Что до чтения, то тут все проще: по заданной позиции определяем с какого файла начать выгребать данные, а по размеру буфера определяем сколько, далее через copy или move собираем или прямо в лоб - берем все файлы, какие видим (тут ограничение, они должны быть тогда созданы заранее), склеиваем все данные из них и далее просто работаем с глобальным буфером. Ото так.

скачать


Комментариев нет:

Отправить комментарий

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.