Конференция "Начинающим" » Запись в файл и чтение из файла записи: есть запись:
 
  • EgorovAlex © (16.06.08 14:54) [0]
    record
     s1,
     s2: PWideChar;
    end;

    Как мне её записать в файл и потом прочитать из файла?

    пробовал так: MS: TMemoryStream;

    MS.Write(Rec^, SizeOf(Rec));
    MS.Position := 0;
    MS.WriteToFile...

    но потом при чтении из файла (тоже через мемористрим) не читаются s1 и s2.

    Что я не так делаю?
  • Поросенок Винни-Пух © (16.06.08 15:25) [1]
    все так. что записал то и считал.
  • Поросенок Винни-Пух © (16.06.08 15:28) [2]
    Поразмышляй вот над этим:
    showmrssage(inttostr(SizeOf(rec)))
  • EgorovAlex © (16.06.08 15:52) [3]
    Я над этим уже поразмышлял :) только как применить пока не понимаю, я понял, что я пишу 2 байта указателей, а не содержимое полей записи, а вот как записать всё?
  • clickmaker © (16.06.08 15:54) [4]
    > как записать всё?

    также. Write() каждое поле отдельно
  • Поросенок Винни-Пух © (16.06.08 16:01) [5]
    плюс еще записать туда же обе длины чтобы знать сколько читать в последствии
  • EgorovAlex © (16.06.08 16:39) [6]
    т.е. писать так?

    Size: Cardinal;

    MS.Write(Rec^, SizeOf(Rec));
    Size := Length(Rec.s1)*SizeOf(WideChar);
    MS.Write(Size, SizeOf(Size));
    MS.Write(Rec.s1, Size);
    Size := Length(Rec.s2)*SizeOf(WideChar);
    MS.Write(Size, SizeOf(Size));
    MS.Write(Rec.s2, Size);
    MS.Position := 0;
    MS.WriteToFile...
  • Поросенок Винни-Пух © (16.06.08 16:50) [7]
    записать длину первого поля.
    записать само первое поле.
    записать длину второго поля
    записать само второе поле.
  • EgorovAlex © (16.06.08 16:54) [8]
    Вроде всё так и написано в приведённом коде, но считать почему-то не получается, читаю так:

    MS.ReadBuffer(Size, SizeOf(Size));
    if (Size > 0) then
    begin
     GetMem(Rec.s1, Size);
     MS.ReadBuffer(Rec.s1, Size);
    end;
    MS.ReadBuffer(Size, SizeOf(Size));
    if (Size > 0) then
    begin
     GetMem(Rec.s2, Size);
     MS.ReadBuffer(Rec.s2, Size);
    end;
  • Поросенок Винни-Пух © (16.06.08 17:01) [9]
    try
    ms := T....Stream.create(...);
    except
    on E:Exception do ShowMessage('Ой, мама!'#13#10 + E.Message)
    end
  • TForumHelp © (16.06.08 17:02) [10]
    ну еще бы читалось.
  • EgorovAlex © (16.06.08 17:05) [11]
    так нет никаких исключений, но и не читается :(

    to TForumHelp

    а как читать-то :)
  • Поросенок Винни-Пух © (16.06.08 17:09) [12]
    Эт я не в ту ветку запостил
  • Поросенок Винни-Пух © (16.06.08 17:10) [13]
    ридбуфер требует параметром адрес, а не указатель
  • EgorovAlex © (17.06.08 09:50) [14]
    С этим разобрался, спасибо, теперь для уточнения моих познаний :)
    (т.к. старался всегда использовать только записи с фиксированными полями, а не указателями)

    Если у меня есть запись Rec1 и мне нужно сделать её дубликат, то достаточно ли этих двух строк:

    type
     PMyRec = ^TMyRec;
     TMyRec = record
       S: PWideChar;
     end;

    var
     Rec1, Rec2: PMyRec;

    GetMem(Rec2, SizeOf(Rec2));
    Rec2^ := Rec1^;

    или нужны ещё и эти строки:

    GetMem(Rec2.S, Length(Rec1.S)*SizeOf(WideChar));
    CopyMemory(Rec2.S, Rec1.S, Length(Rec1.S)*SizeOf(WideChar));
  • Поросенок Винни-Пух © (17.06.08 10:41) [15]
    1. New(Rec2) красивше чем гетмем в этом случае.
    2. Память под строки распределять надо и надо копировать сами строки если хочешь именно дубликат записи, а не две записи с указателями на один и тот же буфер.
    3. Со строками тоже лучше работать через строковые функции а не через гетмем и копимемори
  • EgorovAlex © (17.06.08 10:57) [16]
    Что за функции работы со строками? Какие преимущества они дадут?
  • Поросенок Винни-Пух © (17.06.08 11:05) [17]
    тебе перепечатать сюда штатную справку?
  • Василий Жогарев © (17.06.08 11:30) [18]

    >  Запись в файл и чтение из файла записи: есть запись:
    >
    > EgorovAlex ©   (16.06.08 14:54)  


    type
     TRow = packed record
       Value1: String[32];
       Value2: String[32];
       Value3: LongInt;
     end;

    var
     Rows: array[1..16] of TRow;



    var
     F: file of TRow;
     i: Integer;
    begin
     // Вносим значения.
     {Rows[1].Value1 := 'Значение 1';
     Rows[1].Value2 := 'Значение 2';
     Rows[1].Value3 := 3;}


     AssignFile(F, './rows.my');
     Rewrite(F);

     try
       for i:= 1 to 16 do
       Write(F, Rows[i]);
     finally
       CloseFile(F);
     end;



    var
     Row: TRow;
     F: file of TRow;
    begin
     AssignFile(F, './rows.my');
     Reset(F);
     try
       while not Eof(F) do
         begin
           Read (F, Row);
           // Получаем значения.
           {Row.Value1...}
         end;
     finally
       CloseFile(F);
     end;
    end;



    Идея рассматривалась на http://forum.sources.ru
  • Palladin © (17.06.08 11:53) [19]

    > Идея рассматривалась на http://forum.sources.ru

    однако растут :) какие великие идеи рассматривать начали
  • EgorovAlex © (17.06.08 12:47) [20]
    Для такой записи всё просто, она же фиксированной длины, да к тому же и не юникодная
  • Sapersky (17.06.08 13:15) [21]
    Для записи с WideString могу предложить хакерский метод, позволяющий писать/читать запись одной командой. Но вам, как начинающему, возможно, лучше о нём не знать :)
  • EgorovAlex © (17.06.08 13:38) [22]
    Все мы когда-то в чём-то начинающие, не томи, показывай :)
  • Sapersky (17.06.08 13:55) [23]
    На всякий случай повторю: запись должна быть с WideString, не WideChar. Собственно, с чем оно будет работать, с чем нет - расписано в комментарии в начале модуля TypInfoEx.
    http://sapersky.narod.ru/files/TypInfoEx.rar
  • EgorovAlex © (19.06.08 12:46) [24]
    Опять вопрос:
    Сейчас записываю в стрим так:

    type
     PMyRec = ^TMyRec;
     TMyRec = record
       S: PWideChar;
     end;
    var
     Size: Cardinal;
     MS: TMemoryStream;
     Rec: PMyRec;

    MS.WriteBuffer(Rec^, SizeOf(TMyRec));
    if Assigned(Rec.S) then
     Size := WStrLen(Rec.S)
    else
     Size := 0;
    MS.WriteBuffer(Size, SizeOf(Size));
    MS.WriteBuffer(Rec.S^, Size*SizeOf(WideChar));



    а читаю так:

    var
     Buf: WideString;

    MS.ReadBuffer(Rec^, SizeOf(TMyRec));
    MS.ReadBuffer(Size, SizeOf(Size));
    if (Size > 0) then
    begin
     SetLength(Buf, Size);
     MS.ReadBuffer(PWideChar(Buf)^, Size*SizeOf(WideChar));
     Rec.S := WStrNew(PWideChar(Buf));
    end;



    и всё работает нормально, но если я пытаюсь избавиться от промежуточного буфера и читать так:

    MS.ReadBuffer(Rec^, SizeOf(TMyRec));
    MS.ReadBuffer(Size, SizeOf(Size));
    if (Size > 0) then
    begin
     Rec.S := WStrAlloc(Size);
     MS.ReadBuffer(Rec.S^, Size*SizeOf(WideChar));
    end;



    то в конце строки Rec.S появляется какой-то мусор. Почему?
  • Sapersky (19.06.08 15:51) [25]
    Насколько я понял, WStrLen (из TntWideStrUtils), даёт длину без завершающего #0, а в WStrAlloc её нужно указывать с учётом нуля, во всяком случае, WStrNew берёт Size := WStrLen(Str) + 1.

    И вот это зачем:
    MS.WriteBuffer(Rec^, SizeOf(TMyRec));
    MS.ReadBuffer(Rec^, SizeOf(TMyRec));
  • EgorovAlex © (19.06.08 16:14) [26]
    Это здесь не нужно, просто по инерции на упрощённыи пример перекинул, а в D2007 WStrLen уже в WideStrUtils есть.
    Да, с прибавлением единицы перед записью проблема решилась
 
Конференция "Начинающим" » Запись в файл и чтение из файла записи: есть запись:
Есть новые Нет новых   [134434   +27][b:0][p:0.002]