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

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

Непростой вопрос по string [D5, D6, D7, Win2k, WinXP]


Страницы:   1 2

ps2006 ©   (2006-07-24 13:06:00) 

Всем привет, многоуважаемый ALL !

Есть вопросик по стрингу: есть поток, с него нужно прочитать n (ну например 7) байт в переменную типа string.
Я делаю так:


var
 s: string;
 FResponse: TMemoryStream;

begin
 ...  другой код  ...

 SetLength(s, 7);
 FResponse.Read(s[1], 7);


Неужели нет более красивого решения ?
Меня не совсем устраивает обращение к переменной так: s[1]

Спасибо.


GrayFace   (2006-07-26 04:58:00) [1]

Я про обычные string'и - AnsiString. Я не проверял, но по идее тут должно выскочить.


ps2006   (2006-07-25 16:45:00) [2]

GrayFace ©   (24.07.06 23:44)
Против - то, что если включена проверка на выход за границы массива может вылететь exception при пустой строке.

Насколько я понимаю - при обьявлении переменной типа shortstring, если не указывать размер, т.е. так:
var
 s: string;

это будет эквивалентно
 s: string[255];

т.е. exception не выскочит. Поправьте, если я неправ


GrayFace   (2006-07-24 23:44:00) [3]

ps2006 ©   (24.07.06 17:02) [17]
Я конечно могу ошибаться насчет красоты, тогда укажите свои аргументы "за" и "против"

Против - то, что если включена проверка на выход за границы массива может вылететь exception при пустой строке.
ИМХО, shortstring'и - от лукавого, о них не стоит заботиться, надо просто запретить подачу их в качестве аргументов функций в своих модулях (есть, помнится, такая директива компиллятора).


Loginov Dmitry   (2006-07-24 19:25:00) [4]

> Stakan ©   (24.07.06 18:33) [25]


Ну ладно, сдаюсь, был не прав. Как говориться, в споре рождается истина, и мы становимся более просвещенными. Не буду раскрывать причины такого заскока, т.к. самому смешно становится. Спасибо за науку!


Reindeer Moss Eater   (2006-07-24 18:51:00) [5]

Ну и в чем был смысл исходного вопроса?


ps2006   (2006-07-24 18:47:00) [6]

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

нет, не лучше - не всегда в потоке находятся одни стринги (у меня как раз такой случай).

Для себя я выяснил следующее:
если попадается ситуация, когда некая процедура возвращает данные в буфер, и эти данные нужно загнать в стринговую переменную, то лучшим решением будет следующее:

 SetLength(s, n);
 ПроцедураЧтенияВБуфер(s[1], n); // ну или m вместо n

То же касается и записи:
 ПроцедураЗаписиИзБуфера(s[1], n); // ну или Length(s) вместо n

(IMHO)


Stakan   (2006-07-24 18:38:00) [7]

Ещё бывает неплохо читать исходники:

procedure TStrings.LoadFromStream(Stream: TStream);
var
 Size: Integer;
 S: string;
begin
 BeginUpdate;
 try
   Size := Stream.Size - Stream.Position;
   SetString(S, nil, Size);
   Stream.Read(Pointer(S)^, Size);
   SetTextStr(S);
 finally
   EndUpdate;
 end;
end;


Stakan   (2006-07-24 18:33:00) [8]

Loginov Dmitry ©   (24.07.06 18:17) [21]
Повторюсь ещё раз: справку неплохо почитать и как можно внимательнее:

If you are passing a string to a read or write function, you need to be aware of the correct syntax. The Buffer parameters for the read and write routines are var and const types, respectively. These are untyped parameters, so the routine takes the address of a variable.
The most commonly used type when working with strings is a long string. However, passing a long string as the Buffer parameter does not produce the correct result. Long strings contain a size, a reference count, and a pointer to the characters in the string. Consequently, dereferencing a long string does not result in only the pointer element. What you need to do is first cast the string to a Pointer or PChar , and then dereference it. For example:

procedure caststring;

var
fs: TFileStream;
const
s: string = 'Hello';
begin
fs := TFileStream.Create('temp.txt', fmCreate or fmOpenWrite);
fs.Write(s, Length(s)); // this will give you garbage
fs.Write(PChar(s)^, Length(s)); // this is the correct way
end;


Reindeer Moss Eater   (2006-07-24 18:22:00) [9]

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


Loginov Dmitry   (2006-07-24 18:19:00) [10]

Медленно но верно все сводится к [0] ;)


ps2006   (2006-07-24 18:18:00) [11]

1) соглашусь - я никогда не пользовался Setstring;

>Кто мешает использовать смещение?
2) в принципе согласен, но этот метод не универсальный. Вы сможете работать таким образом с любым наследником TStream ?

> Никаких буферных переменных у меня не используется.
3) согласен, но это только для этого случая.

Речь не идет о том, как прочитать 7 байт из потока в переменную, речь идет о том, как это лучше сделать.Я говорю о подходе к программированию. У каждого человека он свой. Согласитесь, что легче программировать, когда везде используется один подход. Когда при изменении ТЗ если переделки приводят к "разваливанию" программы - это не подход.

(IMHO)


Loginov Dmitry   (2006-07-24 18:17:00) [12]

> Stakan ©   (24.07.06 16:59) [16]


> Бывает полезно справку читать, перед тем как говорить.


Вот именно, что бывает иногда полезно справку почитать, перед тем как говорить. А в справке ясно написано, что PChar, но никоим образом не Pointer, как указано в [2].
А еще иногда бывает полезно проверить то, что пишешь.


Reindeer Moss Eater   (2006-07-24 17:41:00) [13]

1) код не очень читабелен (нужно вникнуть, чтобы понять, что читается 7
байт с потока в переменную);

нечитабелен для того, кто не пользуется Setstring никогда.

2) читается 7 байт с начала потока, а не с текущей позиции;Это еще почему?  Кто мешает использовать смещение?

3) я привык создавать шаблоны (у себя в голове), чтобы их быстро и надежно использовать, если нужно будет использовать процедуру, которая читает(пишет) в(из) буфера, то при Вашем подходе нужно будет создать еще одну переменную для буфера. Пример:

Никаких буферных переменных у меня не используется. Есть переменная S из исходной задачи в которую надо считать данные из потока.


ps2006   (2006-07-24 17:36:00) [14]

>SetString(s,PChar(FResponse.Memory),7);
>Словно SetString вдруг перестало работать с shortstring

Это конечно тоже выход из положения, но мне не понравилось следующее:
1) код не очень читабелен (нужно вникнуть, чтобы понять, что читается 7 байт с потока в переменную);
2) читается 7 байт с начала потока, а не с текущей позиции;
3) я привык создавать шаблоны (у себя в голове), чтобы их быстро и надежно использовать, если нужно будет использовать процедуру, которая читает(пишет) в(из) буфера, то при Вашем подходе нужно будет создать еще одну переменную для буфера. Пример:

var
 s: string;
 fs: TFileStream;
 buf: array[1..1024] of bytes; // или другой буффер, это неважно
begin
 .....
 fs.Read(buf; n);
 SetString(s, buf, m);


Reindeer Moss Eater   (2006-07-24 17:16:00) [15]

Словно SetString вдруг перестало работать с shortstring


ps2006   (2006-07-24 17:02:00) [16]

Не ругайтесь, у каждого есть своя точка зрения.

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

Похоже, что все-таки наиболее красивым будет такое решение:
FResponse.Read(s[1], 7);
Обьясняю - это будет работать независимо от типа s - ShortStringили AnsiString.
Я конечно могу ошибаться насчет красоты, тогда укажите свои аргументы "за" и "против"


Stakan   (2006-07-24 16:59:00) [17]

Loginov Dmitry ©   (24.07.06 16:26) [11]

> И что это будет? Бред!

Бывает полезно справку читать, перед тем как говорить.
If you are passing a string to a read or write function, you need to be aware of the correct syntax. The Buffer parameters for the read and write routines are var and const types, respectively. These are untyped parameters, so the routine takes the address of a variable.
The most commonly used type when working with strings is a long string. However, passing a long string as the Buffer parameter does not produce the correct result. Long strings contain a size, a reference count, and a pointer to the characters in the string. Consequently, dereferencing a long string does not result in only the pointer element. What you need to do is first cast the string to a Pointer or PChar, and then dereference it. For example:

procedure caststring;

var
 fs: TFileStream;
const
 s: string = 'Hello';
begin
 fs := TFileStream.Create('temp.txt', fmCreate or fmOpenWrite);
 fs.Write(s, Length(s)); // this will give you garbage
 fs.Write(PChar(s)^, Length(s)); // this is the correct way
end;


Reindeer Moss Eater   (2006-07-24 16:46:00) [18]

Мой пример сработает и без нуля в восьмой позиции.


Loginov Dmitry   (2006-07-24 16:43:00) [19]

В догонку! Вот еще вспомнил вполне рабочий способ:

S := PChar(FResponse.Memory);

Красиво? То-то.
Только эта хрень сработает, если в потоке будет символ завершения строки.
Тогда запись в поток нужно делать так:

FResponse.Write(S[1], Length(S) + 1);

Красиво. Но не универсально. Для конкретного случая сгодится.


Reindeer Moss Eater   (2006-07-24 16:34:00) [20]

При чем здесь эта лабуда с простотой и универсальностью?
Я просто показал, что есть более красивые решения для этого конкретного случая.


Страницы:   1 2

Наверх

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