powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Работа с PChar
25 сообщений из 92, страница 1 из 4
Работа с PChar
    #39473911
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте эксперты по Delphi!.
Мне потребовалось написать такой XML генератор, который работает очень быстро.
Но не знаю где допускал ошибку.

Версия Delphi 6. (Я вынужден написать на Delphi 6. Другого выхода нет.)

Какие ошибки:
- под ОС Win 7 : AccessViolation;
- под ОС Win XP : медленно работает;

Я думаю все с PChar.

Уважаемые эксперты, посмотрите на мой код:
TXMLWriter
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
  unit XMLWriter;

interface

uses
  Classes, SysUtils;

type

  TXmlStandalone = (xsOmit, xsYes, xsNo);

  TXmlCloseTag = (xtNone, xtClose, xtSlashClose);

  TXMLWriter = class
  private
    FCapacity: LongInt;
    FLength: Integer;
    FBuffer: PChar;
    procedure Grow;
  public
    constructor Create(const Standalone: TXmlStandalone);
    destructor Destroy; override;
    procedure WriteValue(const Buffer: PChar);
    procedure OpenElement(const Name: PChar; const CloseTag: TXmlCloseTag);
    procedure WriteElement(const Name, Value: PChar);
    procedure WriteAttribute(const Name, Value: PChar; const CloseTag: TXmlCloseTag); overload;
    procedure WriteBuffer(const Buffer: PChar);
    procedure WriteChar(const Value: Char);
    procedure CloseElement(const Name: PChar);
  end; 

implementation

const

  cOpenTag       = '<';
  cCloseTag      = '>';
  cSlash         = '/';
  cOpenSlashTag  = '</';
  cSlashCloseTag = '/>';
  cSpace         = ' ';
  cEquality      = '=';
  cApostrophe    = '"';
  cEqualApos     = '="';
  cXml           = '<?xml version="1.0" encoding="UTF-8" standalone="%s" ?>';
  cStandalones   : array [TXmlStandalone] of string = ('omit', 'yes', 'no');

{ TXMLWriter }

constructor TXMLWriter.Create(const Standalone: TXmlStandalone);
begin
  FCapacity := 0;
  FLength := 0;

  Grow;
  // xml declarations
  WriteBuffer(PChar(Format(cXml, [cStandalones[Standalone]])));
end;

destructor TXMLWriter.Destroy;
begin
  if FCapacity > 0 then
    FreeMem(FBuffer);
  FBuffer := nil;
  inherited Destroy;
end;

procedure TXMLWriter.Grow;
var
  NewCapacity: Integer;
begin
  NewCapacity := FCapacity + $200;
  if FCapacity = 0 then
  begin
    GetMem(FBuffer, NewCapacity * SizeOf(Char))
  end
  else
  begin
    ReallocMem(FBuffer, NewCapacity * SizeOf(Char));
  end;
  FCapacity := NewCapacity;
end;

procedure TXMLWriter.OpenElement(const Name: PChar; const CloseTag: TXmlCloseTag);
begin
  // <
  WriteChar(cOpenTag);
  // name
  WriteBuffer(Name);
  // >
  case CloseTag of
    xtClose: WriteChar(cCloseTag);
    xtSlashClose: WriteBuffer(cSlashCloseTag);
  end;
end;

procedure TXMLWriter.CloseElement(const Name: PChar);
begin
  // </
  WriteBuffer(cOpenSlashTag);
  // name
  WriteBuffer(Name);
  // >
  WriteChar(cCloseTag);
end;


procedure TXMLWriter.WriteElement(const Name, Value: PChar);
begin
  OpenElement(Name, xtClose);
  if Value <> nil then
  begin
    // value
    WriteValue(Value);
    // </name>
    CloseElement(Name);
  end
  else
    // />
    WriteBuffer(cSlashCloseTag);
end;


procedure TXMLWriter.WriteAttribute(const Name, Value: PChar; const CloseTag: TXmlCloseTag);
begin
  // space
  WriteChar(cSpace);
  // name
  WriteBuffer(Name);
  // ="
  WriteBuffer(cEqualApos);
  // value
  WriteValue(Value);
  // "
  WriteChar(cApostrophe);
  // >
  case CloseTag of
    xtClose: WriteChar(cCloseTag);
    xtSlashClose: WriteBuffer(cSlashCloseTag);
  end;
end;


procedure TXMLWriter.WriteBuffer(const Buffer: PChar);
var
  P: PChar;
begin
  P := Buffer;  
  while P^ <> #0 do begin
    (FBuffer + FLength)^ := P^;
    Inc(FLength);
    if FLength >= FCapacity then
      Grow;
    Inc(P);
  end;
end;

procedure TXMLWriter.WriteChar(const Value: Char);
begin
  (FBuffer + FLength)^ := Value;
  Inc(FLength);
  if FLength >= FCapacity then
    Grow;
end;


procedure TXMLWriter.WriteValue(const Buffer: PChar);
const
   clt  = '%lt;';
   cgt  = '%gt;';
   cmp  = '&amp;';
   cqt  = '&quot;';
var
  P: PChar;
  n : Integer;
begin
  P := Buffer;
  while P^ <> #0 do
  begin
    case P^ of
      '<':
        begin
          WriteBuffer(clt);
          Inc(P);
        end;
      '>':
        begin
          WriteBuffer(cgt);
          Inc(P);
        end;
      '&':
        begin
          WriteBuffer(cmp);
          Inc(P);
        end;
      '"':
        begin
          WriteBuffer(cqt);
          Inc(P);
        end
    else
      begin
         (FBuffer + FLength)^ := P^;
         Inc(FLength);
         if FLength = FCapacity then
           Grow;
         Inc(P);
      end;
    end
  end;
end;

end.




Заранее спасибо!
...
Рейтинг: 0 / 0
Работа с PChar
    #39473912
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот тест:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
    procedure TForm1.btn1Click(Sender: TObject);
const
   c1:PChar = 'root';
   c2:PChar = 'chs';
   c3:PChar = 'i';
   c4:PChar = 'chd';
   c5:PChar = 'n';

var
  xWriter : TXMLWriter;
  i, j : Integer;
  p : PChar;
begin
  xWriter := TXMLWriter.Create(xsYes);
  try
    xWriter.OpenElement(c1, xtClose);
    for i := 0 to 10000 do
    begin
      xWriter.OpenElement(c2, xtNone);
      p := PChar(IntToStr(i));
      xWriter.WriteAttribute(c3, p, xtClose);

      for j := 0 to 50 do
      begin
        xWriter.OpenElement(c4, xtNone);
        p := PChar(IntToStr(j));
        xWriter.WriteAttribute(c5, p, xtClose);
        xWriter.CloseElement(c4);
      end;
      xWriter.CloseElement(c2);
    end;
    xWriter.CloseElement(c1);

    ShowMessage('ok');
  finally
    xWriter.Free;
  end;
end;
  
...
Рейтинг: 0 / 0
Работа с PChar
    #39473918
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Очень нужна ваша помощь!
...
Рейтинг: 0 / 0
Работа с PChar
    #39473957
Фотография Maxim Rusov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Измените Grow типа:

Код: pascal
1.
2.
3.
4.
5.
procedure TXMLWriter.Grow;
var
  NewCapacity: Integer;
begin
  NewCapacity := FCapacity + FCapacity div 4;
...
Рейтинг: 0 / 0
Работа с PChar
    #39473959
Softologic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
AlimkulovОчень нужна ваша помощь!
Лучше возьми NativeXml и не изобретай велосипед. Бесплатно, доступно для Д6 и легко в освоении.
...
Рейтинг: 0 / 0
Работа с PChar
    #39473962
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1. А в дебаггере на какой именно строке вылетает Access Violation? Потому что у меня на XE2 и Windows 7 не воспроизводится (скопировал код из btn1Click в консольное приложение).
2. Не по теме, но если вам важна скорость, то ИМХО вместо FBuffer и FLength сделать FBuffer, FCursor, FLast: PChar, примерно так:
Код: pascal
1.
2.
3.
4.
5.
6.
while P^ <> #0 do begin
  FCursor^ := P^;
  Inc(FCursor);
  if FCursor >= FLast then 
    Grow;
  Inc(P^);


3. Есть ли объективная причина везде использовать PChar?.. Если не планируется выносить код в DLL, то может всё-таки string?
А в коде, соответственно:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
procedure TXMLWriter.WriteValue(const Buffer: string);
...
var
  P: PChar;
...
begin
  if Buffer <> '' then begin
    P := Pointer(Buffer);
    while P^ <> #0 do
...
Рейтинг: 0 / 0
Работа с PChar
    #39473977
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp вместо FBuffer и FLength сделать FBuffer, FCursor, FLast: PChar
Спасибо за предложения. Как решу проблему, обязательна так и делаю.
...
Рейтинг: 0 / 0
Работа с PChar
    #39473978
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlimkulovЗдравствуйте эксперты по Delphi!.
Мне потребовалось написать такой XML генератор, который работает очень быстро.


быстрее writeln вряд ли что-то создает xml
...
Рейтинг: 0 / 0
Работа с PChar
    #39473981
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Softologic,
Спасибо за совет! NativeXml соответствует ли требованиям (сверхлимитный скорость)?
...
Рейтинг: 0 / 0
Работа с PChar
    #39473988
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp1. А в дебаггере на какой именно строке вылетает Access Violation?


Не могу ловить строку AccessViolation. То OpenElement, в другой раз на WriteAttribute и.т.д.
Логировал в Grow и как NewCapacity получает значение свыше 2000000, везде AccessViolation.
...
Рейтинг: 0 / 0
Работа с PChar
    #39473991
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp3. Есть ли объективная причина везде использовать PChar?.. Если не планируется выносить код в DLL, то может всё-таки string?
[/src]

Да конечно. Можно и так. Переделаю как вы указали.
...
Рейтинг: 0 / 0
Работа с PChar
    #39474026
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
AlimkulovSoftologic,
Спасибо за совет! NativeXml соответствует ли требованиям (сверхлимитный скорость)?
а лимит какой?
...
Рейтинг: 0 / 0
Работа с PChar
    #39474028
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alimkulovalekcvp1. А в дебаггере на какой именно строке вылетает Access Violation?

Не могу ловить строку AccessViolation. То OpenElement, в другой раз на WriteAttribute и.т.д.
Логировал в Grow и как NewCapacity получает значение свыше 2000000, везде AccessViolation.
А если сразу выделить, скажем, 4194304 (4 Mb), и увеличивать не по $200, а по $400000 - будут AV?
Еще вариант, подключить к тестовому проекту FastMM4 - с ним тоже AV?
...
Рейтинг: 0 / 0
Работа с PChar
    #39474032
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
мне кажется, что не стоит бесконечно наращивать буфер, у тебя сильно дефрагментируется память
...
Рейтинг: 0 / 0
Работа с PChar
    #39474033
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecator,
Я думал NativeXml формирует DOM, а на это уходить много времени.
А у меня задача: генерировать XML который объем свыше 50 mb.
...
Рейтинг: 0 / 0
Работа с PChar
    #39474035
Alimkulov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecatorмне кажется, что не стоит бесконечно наращивать буфер, у тебя сильно дефрагментируется память
Какой вариант предлагаете?
...
Рейтинг: 0 / 0
Работа с PChar
    #39474039
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Alimkulovdefecator,
Я думал NativeXml формирует DOM, а на это уходить много времени.
А у меня задача: генерировать XML который объем свыше 50 mb.
возьми его и не парься
...
Рейтинг: 0 / 0
Работа с PChar
    #39474045
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alimkulovdefecatorмне кажется, что не стоит бесконечно наращивать буфер, у тебя сильно дефрагментируется память
Какой вариант предлагаете?

Зависит от того, что потом планируется делать с данными в буфере.

Можно писать буфер на диск и использовать старый буфер повторно для новой порции данных,
можно выделять новый буфер и писать новую порцию в него.
...
Рейтинг: 0 / 0
Работа с PChar
    #39474056
Фотография Maxim Rusov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Grow измени, бладж!
...
Рейтинг: 0 / 0
Работа с PChar
    #39474078
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alimkulov,

Я не знаю, почему у тебя AV, но я знаю, что ты достаточно долго мучаешься с памятью: реаллоки, проверки. Тебе нужно умно писать на диск, т.е. через буфер.

Тебе поможет библиотека CachedBuffers, там есть отдельный класс для файлов и есть высокоуровневой метод Write. Ты сможешь записывать как отдельно символы, так и строки.

Если в перспективе ты захочешь писать не только в UTF-8, но и в других кодировках, тогда тебе понадобится CachedTexts - там фишка в том, данные пишешь в одной кодировке, а на диск они кладутся в нужной тебе.
...
Рейтинг: 0 / 0
Работа с PChar
    #39474081
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SOFT FOR YOUAlimkulov,

Я не знаю, почему у тебя AV, но я знаю, что ты достаточно долго мучаешься с памятью: реаллоки, проверки. Тебе нужно умно писать на диск, т.е. через буфер.

Тебе поможет библиотека CachedBuffers, там есть отдельный класс для файлов и есть высокоуровневой метод Write. Ты сможешь записывать как отдельно символы, так и строки.

Если в перспективе ты захочешь писать не только в UTF-8, но и в других кодировках, тогда тебе понадобится CachedTexts - там фишка в том, данные пишешь в одной кодировке, а на диск они кладутся в нужной тебе.

ему не надо тащить очередного монстра в проект, достаточно NativeXML
...
Рейтинг: 0 / 0
Работа с PChar
    #39474083
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecator,

CachedBuffers меньше NatuveXml-я. Значительно. И дополнительных библиотек типа Classes не юзает. Совместим с KOL
...
Рейтинг: 0 / 0
Работа с PChar
    #39474094
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SOFT FOR YOUdefecator,

CachedBuffers меньше NatuveXml-я. Значительно. И дополнительных библиотек типа Classes не юзает. Совместим с KOLзато NativeXML выполняет то, что нужно ТС.
...
Рейтинг: 0 / 0
Работа с PChar
    #39474100
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecator,

Нет, он пишет в память. И выполняет тонну проверок и преобразований, которые в случае ТС скорее всего не нужны
...
Рейтинг: 0 / 0
Работа с PChar
    #39474106
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Автору нужна запись 50Мб быстро. CachedBuffers писал 100Мб на тестах за 100мск. О чем мы говорим?
...
Рейтинг: 0 / 0
25 сообщений из 92, страница 1 из 4
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Работа с PChar
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]