Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Работа с PChar / 25 сообщений из 92, страница 1 из 4
19.06.2017, 08:28:13
    #39473911
Alimkulov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
Здравствуйте эксперты по 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
19.06.2017, 08:33:00
    #39473912
Alimkulov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
Вот тест:
Код: 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
19.06.2017, 09:02:22
    #39473918
Alimkulov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
Очень нужна ваша помощь!
...
Рейтинг: 0 / 0
19.06.2017, 10:13:19
    #39473957
Maxim Rusov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
Измените Grow типа:

Код: pascal
1.
2.
3.
4.
5.
procedure TXMLWriter.Grow;
var
  NewCapacity: Integer;
begin
  NewCapacity := FCapacity + FCapacity div 4;
...
Рейтинг: 0 / 0
19.06.2017, 10:14:12
    #39473959
Softologic
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
AlimkulovОчень нужна ваша помощь!
Лучше возьми NativeXml и не изобретай велосипед. Бесплатно, доступно для Д6 и легко в освоении.
...
Рейтинг: 0 / 0
19.06.2017, 10:17:53
    #39473962
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
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
19.06.2017, 10:33:01
    #39473977
Alimkulov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
alekcvp вместо FBuffer и FLength сделать FBuffer, FCursor, FLast: PChar
Спасибо за предложения. Как решу проблему, обязательна так и делаю.
...
Рейтинг: 0 / 0
19.06.2017, 10:33:13
    #39473978
schi
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Работа с PChar
AlimkulovЗдравствуйте эксперты по Delphi!.
Мне потребовалось написать такой XML генератор, который работает очень быстро.


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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