Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > BlockRead & BlockWrite


Автор: artemiy 29.3.2007, 22:49
Использую BlockRead & BlockWrite для записи динамического массива записей в файл.
Вот код:
Код

type
  TOptions = record
    line1,line2:string;
    value:boolean;
  end;

var
  data:array of TOptions;
  f:file;

procedure SaveAll;
var i,x:integer;
begin
 AssignFile(f,'test-save.sav');
 Rewrite(f);
 x:=Length(data);
 BlockWrite(f,x,4);
 for i:=0 to x-1 do
      begin
        x:=SizeOf(data[i]);
        BlockWrite(f,x,4);
        BlockWrite(f,data[i],SizeOf(data[i]));
      end;
 CloseFile(f);
end;

procedure RestoreAll;
var i,x:integer;
begin
 AssignFile(f,'test-save.sav');
 Reset(f);
 BlockRead(f,x,4);
 SetLength(data,x);
 for i:=0 to x-1 do
      begin
        BlockRead(f,x,4);
        BlockRead(f,data[i],x);
      end;
 CloseFile(f);
end;

И у меня вылетает ошибка на выходе из процедуры RestoreAll. Почему - не знаю :( Может кто подскажет где ошибка?

Автор: VICTAR 29.3.2007, 22:52
А где размер записи? По умолчанию он 128 байт
Код

Rewrite(f,1);


Добавлено через 3 минуты и 50 секунд
Плюс при чтении указывай параметр, в который будет возвращаться кол-во прочитанных записей. Если ты не указываешь этот параметр, а кол-во прочтенных записей будет меньше размера буфера получишь исключение.

Код

var count: integer;
BlockRead(f,x,4,count);

Автор: artemiy 29.3.2007, 22:58
Добавил... Теперь у меня следующее:
Код

type
  TOptions = record
    line1,line2:string;
    value:boolean;
  end;
var
  data:array of TOptions;
  f:file;
procedure SaveAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Rewrite(f,1);
 x:=Length(data);
 BlockWrite(f,x,4,count);
 for i:=0 to Length(data)-1 do
      begin
        x:=SizeOf(data[i]);
        BlockWrite(f,x,4,count);
        BlockWrite(f,data[i],SizeOf(data[i]),count);
      end;
 CloseFile(f);
 SetLength(data,0);
end;

procedure RestoreAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Reset(f,1);
 BlockRead(f,x,4,count);
 SetLength(data,x);
 for i:=0 to Length(data)-1 do
      begin
        BlockRead(f,x,4,count);
        BlockRead(f,data[i],x,count);
      end;
 CloseFile(f);
end;

Работает почти без ошибок (на этот раз ошибка при закрытиии программы), но читает неправильно... 
З.Ы. Это мой первый опыт работы с BlockRead & BlockWrite. 

Автор: VICTAR 29.3.2007, 23:34
Можно работать с ShortString, например так
Код

type
  TOptions = record
    line1,line2: ShortString;
    value:boolean;
  end;
var
  data:array of TOptions;
  f:file;

procedure SaveAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Rewrite(f,1);
 x:=Length(data);
 BlockWrite(f,x,4,count);
 for i:=0 to Length(data)-1 do
  BlockWrite(f,data[i],SizeOf(TOptions));
 CloseFile(f);
 SetLength(data,0);
end;

procedure RestoreAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Reset(f,1);
 BlockRead(f,x,4,count);
 SetLength(data,x);
 for i:=0 to Length(data)-1 do
  BlockRead(f,data[i],SizeOf(TOptions),count);
 CloseFile(f);
end;

Автор: MetalFan 30.3.2007, 08:52
опять циклы... зачем? если размер записи заранее известен...

Автор: artemiy 30.3.2007, 10:56
Цитата(VICTAR)
Можно работать с ShortString
 Так а чем этот ShortString помог?

У меня проблема вообще вот в чем: надо записать несколько массивов рекордов в файл. Это динамические массивы разных рекордов, причем размер одинаковых рекордов не всегда совпадает. Решение я вижу таким: записывать в файл сначала размерность первого массива, затем записывать размер каждого элемента массива(размер рекорда) и собственно сам элемент(рекорд). Затем записывать размерность второго массива и его элементы с размерами. И т.д. Считывать я собираюсь так же: считал размерность массива, потом все его элементы...

Записывать вроде бы получается, а вот считывать - нет (считывает фигню какую-то, см. скриншот). Где проблема - я не знаю :(

Автор: MetalFan 30.3.2007, 11:49
Цитата(artemiy @  30.3.2007,  10:56 Найти цитируемый пост)
динамические массивы разных рекордов

эт как это на делфи такое сделать можно?!  smile

Автор: VICTAR 30.3.2007, 12:22
Цитата(MetalFan @  30.3.2007,  08:52 Найти цитируемый пост)
опять циклы... зачем? если размер записи заранее известен... 

MetalFan, злой ты человек  smile, это задумка автора(если эта реплика была не ко мне звиняй  smile )

Цитата(artemiy @  30.3.2007,  10:56 Найти цитируемый пост)
Так а чем этот ShortString помог?

Тем, что выравнял "рекорд". Мое дело предложить.


Цитата(artemiy @  30.3.2007,  10:56 Найти цитируемый пост)
Решение я вижу таким: записывать в файл сначала размерность первого массива, затем записывать размер каждого элемента массива(размер рекорда) и собственно сам элемент(рекорд). 

только не забудь тогда записывать еще размер каждого эл-та записи(для строк)  smile 

Автор: artemiy 30.3.2007, 12:51
Цитата(MetalFan)

Цитата(artemiy @  30.3.2007,  10:56 Найти цитируемый пост)
динамические массивы разных рекордов

эт как это на делфи такое сделать можно?!  smile
Это в смысле что один массив состоит из одних рекордов, другой массив - из других smile
Цитата(VICTAR)

только не забудь тогда записывать еще размер каждого эл-та записи(для строк)  smile

Ну так я так и делаю ))
Вот код с комментами:
Код

type
  TOptions = record
    line1,line2:string;
    value:boolean;
  end;
var
  data:array of TOptions;
  f:file;

procedure SaveAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Rewrite(f,1);
 x:=Length(data);
 BlockWrite(f,x,4,count);   //Записываем размерность массива
 for i:=0 to Length(data)-1 do
      begin
        x:=SizeOf(data[i]);
        BlockWrite(f,x,4,count);     //Записываем размер записи
        BlockWrite(f,data[i],SizeOf(data[i]),count);    //Записываем саму запись
      end;
 CloseFile(f);
 SetLength(data,0);
end;

procedure RestoreAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Reset(f,1);
 BlockRead(f,x,4,count);
 SetLength(data,x);        //Считываем размерность массива
 for i:=0 to Length(data)-1 do
      begin
        BlockRead(f,x,4,count);    //Считываем размер записи
        BlockRead(f,data[i],x,count);    //Считываем саму запись
      end;
 CloseFile(f);
end;

Но вот только я не пойму почему оно неправильно считывается...  MetalFan, или ты имеешь в виду записывать еще и размерность каждого элемента записи? Т.е. записывать каждый элемент по отдельности, а не всю запись сразу... Если да, то, блин, геморно получается...

Может быть стоит использовать вообще другой алгоритм?

Автор: MetalFan 30.3.2007, 13:12
а! ну дык понятно...
код и не будет работать, если использовать длинные строки. да и вообще код написан с грубейщими ошибками.
а записывать размерность каждой записи - это лишнее, они всегда одинаковые будут)

Автор: artemiy 30.3.2007, 13:25
Цитата(MetalFan)
да и вообще код написан с грубейщими ошибками.

А где именно? Буду исправлять.

Цитата(MetalFan)
а записывать размерность каждой записи - это лишнее, они всегда одинаковые будут)

А если елементами рекорда будут STringList'ы?

Автор: MetalFan 30.3.2007, 13:35
Цитата(artemiy @  30.3.2007,  13:25 Найти цитируемый пост)
Цитата(MetalFan)
да и вообще код написан с грубейщими ошибками.

А где именно? Буду исправлять.

беру слова обратно. просто есть некторые недочеты. эт с первого взгляда не так понял)

Цитата(artemiy @  30.3.2007,  13:25 Найти цитируемый пост)

А если елементами рекорда будут STringList'ы? 

и что? 4 байта в записи займет. как и любой другой наследник от TObject

Автор: artemiy 30.3.2007, 14:29
Цитата(MetalFan @  30.3.2007,  13:35 Найти цитируемый пост)
4 байта в записи займет. как и любой другой наследник от TObject

Даже если в этом TStringList'е будет текста на несколько килобайт?

Автор: artemiy 30.3.2007, 16:28
Немного переделал код:
Код

type
  TOptions = record
    line1,line2:string;
    text:TStringList;
    value:boolean;
  end;
var
  data:array of TOptions;
  f:file;

procedure SaveRecord(rec:TOptions);
var size,count:integer;
begin
 with rec do
 begin
   size:=SizeOf(Line1);
   BlockWrite(f,size,4,count);
   BlockWrite(f,Line1,size,count);

   size:=SizeOf(line2);
   BlockWrite(f,size,4,count);
   BlockWrite(f,line2,size,count);

   size:=SizeOf(text);
   BlockWrite(f,size,4,count);
   BlockWrite(f,text,size,count);

   BlockWrite(f,value,1,count);
 end;
end;

procedure ReadRecord(var rec:TOptions);
var size,count:integer;
begin
 with rec do
 begin
   BlockRead(f,size,4,count);
   BlockRead(f,line1,size,count);

   BlockRead(f,size,4,count);
   BlockRead(f,line2,size,count);

   text:=TStringList.Create;
   BlockRead(f,size,4,count);
   BlockRead(f,text,size,count);

   BlockRead(f,value,1,count);
 end;
end;

procedure SaveAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Rewrite(f,1);
 x:=Length(data);
 BlockWrite(f,x,4,count);   //Записываем размерность массива
 for i:=0 to Length(data)-1 do
      begin
         SaveRecord(data[i]);
      end;
 CloseFile(f);
 SetLength(data,0);
end;

procedure RestoreAll;
var i,x,count:integer;
begin
 AssignFile(f,'test-save.sav');
 Reset(f,1);
 BlockRead(f,x,4,count);
 SetLength(data,x);        //Считываем размерность массива
 for i:=0 to Length(data)-1 do
      begin
        ReadRecord(data[i]);
      end;
 CloseFile(f);
end;

И все равно считывается неправильно...  smile  Может быть мне и TStringList построчно записывать? smile 

Автор: VICTAR 30.3.2007, 17:46
Не знаю, стоит ли игра свеч  smile... Наверное нужно поискать более оптимальный вариант.
Код

type
  TOptions = record
    line1,line2:string;
    text:TStringList;
    value:boolean;
  end;
var
  data:array of TOptions;
  f:file;

procedure SaveRecord(rec:TOptions);
var size,count:integer;
begin
 with rec do
 begin
   size:=length(Line1);
   BlockWrite(f,size,4);
   BlockWrite(f,Line1[1],size);
   size:=length(line2);
   BlockWrite(f,size,4);
   BlockWrite(f,line2[1],size);
   size:=length(text.Text);
   BlockWrite(f,size,4);
   BlockWrite(f,text.Text[1],size);
   BlockWrite(f,value,1,count);
 end;
end;

procedure ReadRecord(var rec:TOptions);
var size,count:integer;
    tmp: string;
begin
 with rec do
 begin
   BlockRead(f,size,4,count);
   SetLength(line1, size);
   BlockRead(f,line1[1],size,count);
   BlockRead(f,size,4,count);
   SetLength(line2, size);
   BlockRead(f,line2[1],size,count);
   text:=TStringList.Create;
   BlockRead(f,size,4,count);
   SetLength(tmp, size);
   BlockRead(f,tmp[1],size,count);
   text.Text:=tmp;
   BlockRead(f,value,1,count);
 end;
end;

procedure SaveAll;
var i,x,count:integer;
begin
 AssignFile(f,'C:\test-save.sav');
 Rewrite(f,1);
 x:=Length(data);
 BlockWrite(f,x,4,count);   //Записываем размерность массива
 for i:=0 to Length(data)-1 do
      begin
         SaveRecord(data[i]);
      end;
 CloseFile(f);
 SetLength(data,0);
end;

procedure RestoreAll;
var i,x,count:integer;
begin
 AssignFile(f,'C:\test-save.sav');
 Reset(f,1);
 BlockRead(f,x,4,count);
 SetLength(data,x);        //Считываем размерность массива
 for i:=0 to Length(data)-1 do
      begin
        ReadRecord(data[i]);
      end;
 CloseFile(f);
end;


Автор: artemiy 31.3.2007, 19:27
Спасибо!  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)