Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

запись в файл [D5, WinXP]


TButton ©   (2005-07-19 15:03:00) 

Доброго времени суток, господа.
Давно не писАл (разучивал php, работал, вобщем не досуг было).
А вот сейчас пересматривал старые проекты и нашёл проект спрайтового движка (прога для тестирования скорости и сохранения/загрузки). Перекомпилял (старые екзешники вирусом поело), вроде бы работает. И работает исправно. Из праздного любопытства решил глянуть файл с сохранённым спрайтом (32х32х4) и ужаснулся увидев его размер. 521Кб! Не поверил. Вставил в код метода SaveToFile (см. ниже) счётчики записаных байтов. По счётчику получается всё правильно (4168б = 4+4+64+4096). Но файл всё равно получается монструозный. Решил просмотреть его в блокноте (я всегда смотрю в блокноте =)).

       \x4test                                                                       *   PGA     д}B D\x16Њ \x80Њ     \x8  Ђ`       &   L8B D\x16Њ                 шЉB D\x16Њ \x1E   МIA             ь\x19Њ     &   ш\x15Њ \x6   J\x1F\x10џЂ‡      \xF  Ђ        &   ь\x19Њ \x2   e\xF\x10Эcњ      яяя         N   ”ЄC D\x16Њ \x8 d\x2    №\x1          \x1  
      \x14  Ђ\x1                   \x4       N   ”ЄC D\x16Њ \x8 Њ\x1    Q\x1      \x1   \x1  
      \x14  Ђ\x1                   \x4       2   аPA     ¤уC D\x16Њ          \x1      \xC\x1BЊ \x10   \x10   \x1E   „PA \x1                   j   р5B         ђ\x1BЊ ё\x1BЊ     \x4test                                                                       *   PGA     д}B D\x16Њ \x80Њ     \x8  Ђ`       &   L8B D\x16Њ                 шЉB D\x16Њ \x1E   МIA             ь\x19Њ     &   ш\x15Њ \x6   J\x1F\x10џЂ‡      \xF  Ђ        &   ь\x19Њ \x2   e\xF\x10Эcњ      яяя         N   ”ЄC D\x16Њ \x8 d\x2    №\x1          \x1  
      \x14  Ђ\x1                   \x4       N   ”ЄC D\x16Њ \x8 Њ\x1    Q\x1      \x1   \x1  
      \x14  Ђ\x1                   \x4       2   аPA     ¤уC D\x16Њ          \x1      \xC\x1BЊ \x10   \x10   \x1E   „PA \x1                   j   р5B         ђ\x1BЊ ё\x1BЊ Ш\x1BЊ \x4test                                                                       *   PGA     д}B D\x16Њ \x80Њ     \x8  Ђ`       &   L8B D\x16Њ                 шЉB D\x16Њ \x1E   МIA             ь\x19Њ     &   ш\x15Њ \x6   J\x1F\x10џЂ‡      \xF  Ђ        &   ь\x19Њ \x2   e\xF\x10Эcњ      яяя         N   ”ЄC D\x16Њ \x8 d\x2    №\x1          \x1  
      \x14  Ђ\x1                   \x4       N   ”ЄC D\x16Њ \x8 Њ\x1    Q\x1      \x1   \x1  
      \x14  Ђ\x1                   \x4       2   аPA     ¤уC D\x16Њ          \x1      \xC\x1BЊ \x10   \x10   \x1E   „PA \x1                   j   р5B         ђ\x1BЊ ё\x1BЊ Ш\x1BЊ           М                     p‹\x14 яяяя                        D\x16Њ     љ\x5/\x2*   PGA     ґoA (\x1BЊ \x80Њ `\x1BЊ \x8  Ђ`       "   МHA     ФoA (\x1BЊ Р\x14Њ `\x1BЊ \x4   \x1E   МIA     фoA (\x1BЊ  \x1AЊ `\x1BЊ \x16   D\x16Њ             \x16   D\x16Њ             \x12           ьНC ,[Њ tґD р\x10  м\x10          tґD ИKЊ Ш\x10          tґD ИKЊ Д\x10  TForm1  tґD ИKЊ °\x10  ђ\x4  ђ\x4  аeE рЏE tґD ИKЊ ”\x10  \x4\x1DЊ  \x10  ђ\x4  ђ\x4  D\x16Њ D\x16Њ         D\x16Њ                                                                         \x1   ИKЊ tґD \x18\x10  rm1\x5Form1\x4Left\x3Г \x3Top\x2k\x5Width\x3ё\x2\x6Height\x3а\x1\x7Caption\x6\x5Form1\x5Color\x7 clBtnFace\xCFont.Charset\x7\xFRUSSIAN_CHARSET
Font.Color\x7\xCclWindowText\xBFont.Height\x2х Font.Name\x6\x6Tahoma
Font.Style\xB\x6fsBold \xEOldCreateOrder\x8\x8OnCreate\x7
FormCreate
PixelsPerInch\x2`
TextHeight\x2
\x6TLabel\x6Label1\x4Left\x2\x8\x3Top\x2\x8\x5Width\x2"\x6Height\x2
\x7Caption\x6\x7::LOG::  \x6TLabel\x6Label2\x4Left\x3(\x1\x3Top\x2\x8\x5Width\x2`\x6Height\x2
\x7Caption\x6\x11Test length (sec)   TPaintBox PaintBox1\x4Left\x2\x8\x3Top\x3А \x5Width\x2i\x6Height\x2i  \x5TMemo\x5Memo1\x4Left\x2\x8\x3Top\x2\x18\x5Width\x3\x19\x1\x6Height\x3Ѓ \x5Ctl3D\x8
Lines.Strings\x1\x6\x5Memo1 \xBParentCtl3D\x8\x8ReadOnly
ScrollBars\x7
ssVertical\x8TabOrder\x2    TComboBox ComboBox1\x4Left\x3(\x1\x3Top\x2\x18\x5Width\x3‘ \x6Height\x3Ѓ \x5Style\x7\x8csSimple\x5Ctl3D\x8
ItemHeight\x2
\xBParentCtl3D\x8\x8TabOrder\x2\x1\x4Text\x6\x11
Items.Strings\x1\x6\x11\x6\x12\x6\x13\x6\x14\x6\x15\x6\x16\x6\x17\x6\x18\x6\x19\x6\x210\x6\x215\x6\x220   \x7TButton\x7Button1\x4Left\x2\x8\x3Top\x3  \x5Width\x2K\x6Height\x2\x19\x7Caption\x6 ::Start::\x8TabOrder\x2\x2\x7OnClick\x7\xCButton1Click  \x7TButton\x7Button2\x4Left\x2X\x3Top\x3  \x5Width\x2K\x6Height\x2\x19\x7Caption\x6\x8::STOP::\x7Enabled\x8\x8TabOrder\x2\x3\x7OnClick\x7\xCButton2Click  \x7TButton\x7Button3\x4Left\x3ш \x3Top\x3\x10\x1\x5Width\x2K\x6Height\x2\x19\x7Caption\x6\x7Button3\x8TabOrder\x2\x4\x7OnClick\x7\xCButton3Click  \x7TButton\x7Button4\x4Left\x3ш \x3Top\x38\x1\x5Width\x2K\x6Height\x2\x19\x7Caption\x6\x7Button4\x8TabOrder\x2\x5\x7OnClick\x7\xCButton4Click        
...

это (см. выше) вообще не моё!
моя прога этого не писала!
(точнее - не должна была писать)
очень похоже на dfm'ку
но её просто не должно там быть!
вот сижу и пытаюсь понять, что именно у меня в коде не правильно

для полной ясности привожу код
TRGBA (декларация)

 TRGBA = record
   r, g, b, a: byte;
 end;


TRGBASprite (декларация)

 TRGBASprite = object
   pixels: array of TRGBA;
   height, width: integer;
   name: string[64];
   procedure LoadFromFile(filename: string);
   procedure SaveToFile(filename: string);
 end;

 TGE = object
   private

   public
     function AddMix(c1,c2: TRGBA): TRGBA;
     function BlendMix(c1,c2: TRGBA): TRGBA;
     function MultMix(col: TRGBA; coef: byte): TRGBA;
 end;


TRGBASprite.SaveToFile

procedure TRGBASprite.SaveToFile(filename: string);
var
 f: file;
 i: integer;
  t, a: integer;
begin
 AssignFile(f, filename);
 Rewrite(f);
  t:=0;
 BlockWrite(f, height, SizeOf(integer), a);
  t:=a;
 BlockWrite(f, width, SizeOf(integer), a);
  t:=t+a;
 BlockWrite(f, name, 64, a);
  t:=t+a;
  ShowMessage(IntToStr(t));
 for i:=0 to (height*width-1) do
 begin
   BlockWrite(f, pixels[i].r, 1, a);
    t:=t+a;
   BlockWrite(f, pixels[i].g, 1, a);
    t:=t+a;
   BlockWrite(f, pixels[i].b, 1, a);
    t:=t+a;
   BlockWrite(f, pixels[i].a, 1, a);
    t:=t+a;
 end;                    
  ShowMessage(IntToStr(t));
 CloseFile(f);
end;

Примечание:Курсивом выделены участки кода отвечающие за сбор информации о количестве записаных байтов.

MainUnit.pas (код для тестирования сохранения/загрузки)

procedure TMainForm.Button3Click(Sender: TObject);
var
 i: integer;
begin
 sp.height:=32;
 sp.width:=32;
 sp.name:='test';
 SetLength(sp.pixels, 1024);
 for i:=0 to 1023 do
   sp.pixels[i]:=RandomColor;
 sp.SaveToFile('c:\test.spt');
 dr;
end;

procedure TMainForm.Dr;
var
 i, j, n: integer;
begin
 for i:=0 to sp.height-1 do
   for j:=0 to sp.width-1 do
   begin
     n:=i*sp.width+j;
     paintbox1.Canvas.Pixels[i,j]:=rgb(sp.pixels[n].r, sp.pixels[n].g, sp.pixels[n].b);
   end;
end;

Примечание:sp: TRGBASPrite;
RandomColor - функция возвращающая случайный цвет в формате RGBA (TRGBA)

Как видно из кода метода TRGBASprite.SaveToFile
После последнего сообщения (4186) файл закрывается...
Хотя к чему я это, ведь вся лабуда, которая мне и не нужна вовсе вклинивается не то перед заголовком, не то между заголовком и телом.
Вобщем, надежда только на помощь из вне.

WBR, Marcuch


TButton   (2005-07-22 04:40:00) [1]


> А где код?

а уже поправил =)

> Дык... в общем-то, в [4] уже переписано.

а я сам =)
всё равно собирался переписывать


> > TButton ©   (21.07.05 08:18) [7]
> > прочитал про packed
> > понял только то
>
>
> при таком подходе

а там больше ничего и не написано
не я конечно могу добавить, что понял, что "By default, the values in a structured type are aligned on word or double-word boundaries for faster access. When you declare a structured type, you can include the reserved word packed to implement compressed data storage."

но суть то заключается как раз в изменении соотношения размер/скорость

в данном конкретном случае, размер занимаемой памяти не так критичен, как скорость обращения к элементам массива.


Digitman   (2005-07-21 13:46:00) [2]


> TButton ©   (21.07.05 08:18) [7]
> прочитал про packed
> понял только то


при таком подходе (читал и ни шута не понял) плюнь на packed или не packed - оно тебе индифферентно

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


begin...end   (2005-07-21 12:53:00) [3]

> TButton ©   (21.07.05 8:18) [7]

> прочитал про packed
> понял только то что эта директива оптимизируем
> занимаемое в памяти место, но при этом замедляет
> доступ... имхо, лучше скорость

Наше дело -- предложить, Ваше дело -- отказаться.

> а нельзя указать не Pixels[0], а просто Pixels это же
> вроде бы и есть указатель на начало массива

Нельзя. Хотя Pixels -- это действительно указатель на начало массива. Поэтому и нельзя. Pixels -- это УКАЗАТЕЛЬ на начало массива, а Pixels[0] -- это САМО начало массива.

> сохранение работает как часы
> а загрузка почему-то вызывает AV =)

А где код?

> сейчас попробую переписать на файловые потоки

Дык... в общем-то, в [4] уже переписано.


TButton   (2005-07-21 08:18:00) [4]

прочитал про packed
понял только то что эта директива оптимизируем занимаемое в памяти место, но при этом замедляет доступ... имхо, лучше скорость

> Ну и что?
ну и я тогда (как в принципе и сейчас) частенько использовал примитивные методы, вроде того что приведён в примере. пусть он и незначительно проигрывает по скорости, но зато он легко воспринимается при чтении и надёжен.


> TStream.Write записывает Count байт из памяти, начиная с
> адреса переменной Buffer
теперь понял. а нельзя указать не Pixels[0], а просто Pixels это же вроде бы и есть указатель на начало массива.

попробовал исправить код
(rewrite(f, 1); и reset(f, 1);)
сохранение работает как часы
а загрузка почему-то вызывает AV =)
сам удивляюсь
грузится.
всё нормально грузится
и AV
бред какой-то
сейчас попробую переписать на файловые потоки

ПыСы

> имя   (20.07.05 18:55) [3]

затрудняюсь даже представить, что это было =)


begin...end   (2005-07-20 20:16:00) [5]

> TButton ©   (20.07.05 19:49) [5]

>>  в файл записывается не вся строка TRGBASprite.name
> почему?

Потому что строка типа string[6 4] занимает в памяти 6 5байт. 64 -- для символов, и ещё один (в начале) -- для хранения длины строки. В приведённом коде [0] в файл записывается только 64 байта строки. Лучше не указывать размер явно (потому что, во-первых, можно ошибиться, а во-вторых, когда-нибудь может понадобиться поменять размер строки), а использовать функцию sizeof, что и сделано в [4]. Разумеется, так можно записывать только короткие строки. Тела длинных строк (AnsiString) так записать не удастся.

>> Непонятно также, зачем ТАК записывать динамический
>> массив,
> я же говорю, проект старый

Ну и что?

> с packet record не знаком абсолютно

В принципе, в данном случае packed не обязательно. Но желательно, потому что сохранение и загрузка данных могут производиться при различных директивах выравнивания. Если и при записи, и при чтении выравнивание одно и то же -- packed можно убрать. Но при этом, возможно, увеличится размер файла.

> не совсем понятно, почему Pixels[0]?

Write(const Buffer; Count: Longint): Longint

TStream.Write записывает Count байт из памяти, начиная с адреса переменной Buffer. Чтобы записать динамический массив, передаём в качестве параметров нулевой элемент массива (ведь массив нужно записать весь, с самого начала, т.е. начиная с адреса нулевого элемента) и размер массива (в байтах).


TButton   (2005-07-20 19:49:00) [6]


> Вы не указали явно размер записи файла.

всё. вспомнил.

>  в файл записывается не вся строка TRGBASprite.name

почему?

> Непонятно также, зачем ТАК записывать динамический массив,

я же говорю, проект старый

по примеру
1) с packet record не знаком абсолютно
посмотрю в хелпе
2) > Write(Pixels[0], Height * Width * sizeof(Pixels[0]))
не совсем понятно, почему Pixels[0]?

ну и конечно же спасибо, за подсказки


begin...end   (2005-07-20 19:09:00) [7]

> TButton

Вот пример (хотя и не самый лучший) реализации SaveToFile/LoadFromFile с помощью файловых потоков.
Внимание! Измените объявление типа TRGBA: recordзамените на packed record.

procedure TRGBASprite.SaveToFile(const FileName: string);
begin
 with TFileStream.Create(FileName, fmCreate) do
   try
     Write(Height, sizeof(Height));
     Write(Width, sizeof(Width));
     Write(Name, sizeof(Name));
     Write(Pixels[0], Height * Width * sizeof(Pixels[0]))
   finally
     Free
   end
end;

procedure TRGBASprite.LoadFromFile(const FileName: string);
begin
 with TFileStream.Create(FileName, fmOpenRead) do
   try
     Read(Height, sizeof(Height));
     Read(Width, sizeof(Width));
     Read(Name, sizeof(Name));
     SetLength(Pixels, Height * Width);
     Read(Pixels[0], Height * Width * sizeof(Pixels[0]))
   finally
     Free
   end
end.


  (2005-07-20 18:55:00) [8]

Удалено модератором


begin...end   (2005-07-20 18:32:00) [9]

> TButton ©   (19.07.05 15:03)

Проблема в том, что при вызове Rewrite (для нетипизированного файла) Вы не указали явно размер записифайла. По умолчанию же этот размер равен 128 байт (см. справку по Rewrite). Значение, возвращаемое процедурой BlockWrite в параметре AmtTransferred -- это количество записей, помещённых в файл. Т.к. отладка показала, что количество записей равно 4186, а размер одной записи равен 128 байтам, то размер файла будет 4186 * 128 = 535808 байт. Так что -- ничего удивительного. Чтобы исправить это, замените строку Rewrite(f)на Rewrite(f, 1).

Есть и ещё ошибка -- в файл записывается не вся строка TRGBASprite.name. Непонятно также, зачем ТАК записывать динамический массив, ведь его можно записать одной строчкой кода.


TButton   (2005-07-20 18:06:00) [10]

однако вопрос потерялся...
была мысль использовать файловые потоки. это раз.
ещё мысль использовать file of byte
а не байтовые переменные разбирать и собирать в ручную.
но это бред.
надо будет попробовать первый вариант.


Наверх

Титульная страница Поиск, карта сайта Написать письмо