Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Делфи _ Сохранение данных Memo

Автор: Jill 30.03.2006 17:44

Не получается unsure.gif

С SaveDialog получается, но...

Задача на потоки. В одном из потоков необходимо данные Memo сохранять в текстовый файл. Как?

Автор: hiv 30.03.2006 18:02

Примерно так:

var fs:TFileStream;
...
begin
...
fs:=TFileStream.Create(SaveDialog1.FileName,fmOpenWrite);
memo1.Lines.SaveToStream(fs);
fs.Free;
end;

Автор: Jill 30.03.2006 18:06

hiv, заморочка у меня такая:

где именно вписывать имя выходного файла? как его вписывать?

и где и как этот файл обьявлять?

Автор: hardcase 30.03.2006 20:46

Зачем объявлять файл?
Файлы (file of ...) остались в Pascal - в делфи их использовать не рекомендуется, а в старших версиях Делфи они вообще запрещены.

var fs: TStream;

begin
if SaveDialog1.Execute then begin //запускаем SaveDialog
fs:=TFileStream.Create(SaveDialog1.FileName, fmCreate or fmOpenWrite);
Memo1.Lines.SaveToStream(fs);
fs.Free;
end;


ещё вариант:
var fn: string;
fs: TStream;

begin
fn:=InputBox('Output file','Enter file name:','C:\test.txt');
fs:=TFileStream.Create(fn, fmCreate or fmOpenWrite);
Memo1.Lines.SaveToStream(fs);
fs.Free;
end;

Автор: Jill 31.03.2006 13:33

hardcase, файл должен сохранятся по умолчанию

почему не проходит такой вариант?

var
f:TextFile;
fName:string[80];
i:integer;
begin
fName:='CallRecord.txt';
AssignFile(f,fName);
Rewrite(f);
for i:=0 to Form1.Memo1.Lines.Count do begin
writeln(f,Form1.Memo1.Lines[i]); end;
CloseFile(f);
end;


вроде работает в потоке...

Автор: #$# PaVeL #$# 31.03.2006 15:46

По моему лучше сделать так:

Memo1.Lines.SaveToFile(FileName);

,где FileName - это имя файла (возможно с директорией) в который сохраняется содержимое компонента Memo1

Всё гениальное - просто! blink.gif smile.gif blink.gif smile.gif

Почти тоже самое только одной строчкой кода!

Автор: Jill 31.03.2006 16:55

запускается...

тока перестает реагировать на кнопку стоп и притормаживает... blink.gif

Автор: hiv 31.03.2006 17:16

Цитата(Jill @ 31.03.2006 9:33) *

hardcase, файл должен сохранятся по умолчанию

почему не проходит такой вариант?

var
f:TextFile;
fName:string[80];
i:integer;
begin
fName:='CallRecord.txt';
AssignFile(f,fName);
Rewrite(f);
for i:=0 to Form1.Memo1.Lines.Count do begin
writeln(f,Form1.Memo1.Lines[i]); end;
CloseFile(f);
end;

вроде работает в потоке...


Потому, что надо:
 ...
for i:=0 to Form1.Memo1.Lines.Count-1 do begin
...


И где здесь потоки?

Сделай как написал тебе hardcase в своем первом примере, только не забудь кинуть на форму SaveDialog из ярлычка Dialogs в панели компонентов.
Хау!

Автор: Jill 31.03.2006 17:35

ребят, мне необходимо сохранять файл ПО УМОЛЧАНИЮ, без выбора директории
а во всех предложениях нужно выбрать папку

с первым примером hardcase вылазит предложение о выборе папки (выбрать ее невозможно) и прога не прерывается


(у меня два потока - в одном запись формируется - в другом должна сохраняться)

Автор: hiv 31.03.2006 19:02

Цитата
С SaveDialog получается, но...

Мы тут не занимаемся спиритизмом!
Давай код в студию. Может ты путаешься в понятии, что такое поток!

Автор: Jill 31.03.2006 19:16

ок smile.gif просто код длинноват:

Исходный код
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Mask, ComCtrls, Buttons;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
ScrollBox1: TScrollBox;
Memo1: TMemo;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender : TObject);
procedure Button2Click(Sender : TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TCreateRecord = class(TThread)
private
{ Private declarations }
protected
procedure DoWork;
procedure Execute; override;
end;

TSaveRecord = class(TThread)
private
{ Private declarations }
protected
procedure DoWork;
procedure Execute; override;
end;

var Form1: TForm1;
T1 : TCreateRecord;
T2 : TSaveRecord;

implementation

{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
Form1.Memo1.Clear;
end;

procedure TCreateRecord.Execute;
begin
{Пока процесс не прервали, выполняем DoWork}
while not Terminated do
Synchronize(DoWork);
end;

procedure TSaveRecord.Execute;
begin
{Пока процесс не прервали, выполняем DoWork}
while not Terminated do
Synchronize(DoWork);
end;

{Телефон абонента}
function GenerateTelAbon:string;
var
nom:integer;
begin
nom:=random(899999)+100000;
GenerateTelAbon:=' 8-375-16-'+IntToStr(nom);
end;

function GenerateTel:string;
var
k,ks,kg,nom:integer;
pr,pr1:string;
Kod:Array[1..2] of integer;
begin
Kod[1]:=8;
Kod[2]:=10;
k:=random(2)+1;
ks:=random(899)+100;
kg:=random(89)+10;
nom:=random(899999)+100000;
if Kod[k]=10 then
begin
pr:=' '; pr1:=' ';
end
else
begin
pr:=' '; pr1:=' ';
end;
GenerateTel:=' '+pr+IntToStr(Kod[k])+'-'+IntToStr(ks)+'-'+IntToStr(kg)+'-'+IntToStr(nom)+pr1;
end;

{Дата}
function GenerateDate:string;
var
d,m:integer;
day,month:string;
begin
m:=random(12);
if m=2 then d:=random(28);
if (m=1)or(m=3)or(m=5)or(m=7)or(m=8)or(m=10)or(m=12)
then d:=random(31) else d:=random(30);
day:=IntToStr(d);
if Length(day)=1 then day:='0'+day;
month:=IntToStr(m);
if Length(month)=1 then month:='0'+month;
GenerateDate:=day+'.'+month+'.'+'2006 ';
end;

{Начало и конец разговора}
function GenerateTimeStartFinish:string;
var
h,m:integer;
hour,minute:string;
begin
h:=random(24);
hour:=IntToStr(h);
if Length(hour)=1 then hour:='0'+hour;
if hour='24' then hour:='00';
m:=random(60);
minute:=IntToStr(m);
if Length(minute)=1 then minute:='0'+minute;
if hour='60' then minute:='00';
GenerateTimeStartFinish:=hour+':'+minute;
end;

{Продолжительность разговора}
function GetTime(start,finish:string):string;
var h1,h2,m1,m2,m:integer;
hour1,hour2,minute1,minute2,minute:string;
begin
hour1:=start[1]+start[2]; h1:=StrToInt(hour1);
h1:=h1*60;
minute1:=start[4]+start[5]; m1:=StrToInt(minute1);
m1:=m1+h1;

hour2:=finish[1]+finish[2]; h2:=StrToInt(hour2);
h2:=h2*60;
minute2:=finish[4]+finish[5]; m2:=StrToInt(minute2);
m2:=m2+h2;

m:=m2-m1;
if m<0 then m:=m+1440;
minute:=IntToStr(m);
if Length(minute)=1 then minute:=minute+' ';
if Length(minute)=2 then minute:=minute+' ';
if Length(minute)=3 then minute:=minute+' ';
if Length(minute)=4 then minute:=minute+' ';
GetTime:=minute;
end;

{Идентификатор линии}
function GenerateIdent:string;
var
i:integer;
id:Array[1..5] of string;
iden:string;
begin
id[1]:='C';
id[2]:='O';
id[3]:='I';
id[4]:='S';
id[5]:='R';
i:=random(5)+1;
iden:=id[i];
GenerateIdent:=iden;
end;

procedure TCreateRecord.DoWork;
var start,finish,s:string;
begin
s:=' ';
begin
start:=GenerateTimeStartFinish;
finish:=GenerateTimeStartFinish;
Form1.Memo1.SelText:=GenerateTelAbon+GenerateTel+GenerateDate+
Start+s+Finish+s+GetTime(start,finish)+s+GenerateIdent+#13#10;
end;

end;

procedure TSaveRecord.DoWork;
var
f:TextFile;
fName:string[80];
i:integer;
begin
fName:='CallRecord.txt';
AssignFile(f,fName);
Rewrite(f);
for i:=0 to Form1.Memo1.Lines.Count do begin
if i=0 then writeln(f,' '+Form1.Label1.Caption+' '
+Form1.Label2.Caption+' '+Form1.Label3.Caption+
' '+Form1.Label4.Caption+' '+Form1.Label5.Caption+
' '+Form1.Label6.Caption+' '+Form1.Label7.Caption) else
writeln(f,Form1.Memo1.Lines[i]); end;
CloseFile(f);
end;

procedure TForm1.Button1Click(Sender : TObject);
begin
Button1.Enabled:=False;
Button2.Enabled:=True;
T1:=TCreateRecord.Create(False);
T2:=TSaveRecord.Create(False);
end;

procedure TForm1.Button2Click(Sender : TObject);
begin
T1.Terminate;
T2.Terminate;
Button1.Enabled:=True;
Button2.Enabled:=False;
end;

end.


ууупс...можно же было порезать для удобочитаемости...

Автор: hardcase 31.03.2006 20:02

Хм. Код конечно странный. Сейчас посмотрел.
Когда пишиешь многопоточные приложения стоит их хоть как-то комментировать. Ты не могла бы описать, что делает сей код?
Я вижу две разные нитки (ты их называешь потоками)...
И я так вижу, что TSaveRecord на каждой своей итерации должен сохранять инфу. Зачем тебе ПОСТОЯННО это делать?

Напиши формулировку совоего задания. Наверняка всё можно сделать ГОРАЗДО проще, чем у тебя сейчас есть. Говорю тебе, как человек, который на нитках не одну собаку съел.

Автор: Jill 31.03.2006 20:09

Постановка задачи:
Написать программу, которая формирует запись о звонке и записывает ее в текстовый файл .
В программе должно быть реализовано несколько потоков.
Запись о звонке формируется в одном и передается в другой поток.
В другом потоке она записывается в выходной текстовый файл.


Суть в принципе такова - в поле Мемо формируется запись (поток1,TCreateRecord, вроде работает)
В потоке 2 (TSaveRecord) эти данные должны сохраняться

Автор: volvo 31.03.2006 20:54

Цитата
Говорю тебе, как человек, который на нитках не одну собаку съел.
Значит, мало съел! Придется повторить трапезу.

Уважаемый hardcase, возможно, снизойдет до объяснения всем остальным участникам форума, В ЧЕМ по его мнению заключается разница между нитью (thread) и потоком (опять же thread, странно, правда?) ? Только БЕЗ раскидывания понтов типа "А крутые пацаны в нашем городе привыкли треды называть нитями, не как все остальные ламеры..."

Автор: hardcase 1.04.2006 3:47

Вот мой вариант работы с нитками (так называть предпочтительнее потому как может возникнуть путаница со стримами):

Исходный код

// решение классической задачи о поставщике
// и получателе (в классическом варианте используются
// два семафора)

const
//имя файла, куда будем сохранять
RECORD_FILE = 'file.txt';


// класс нашей записи
type
TSaveRecord = class
private
fLine: string;
public
constructor Create;
property Line: string read fLine;
end;//of class


// в конструкторе втупую создаём новую строку
// ты можешь заменить на всё, что тебе нужно

var i: integer = 1;
constructor TSaveRecord.Create;
begin
fLine:='Text record #'+IntToStr(i);
inc(i);
end;

var
// текущая запись
Rec: TSaveRecord = nil;

// это специальный объект, который позволяет синхронизировать
// чтение/запись в переменную Rec
Mtx: TMultiReadExclusiveWriteSynchronizer;


// наш потребитель - получает новую запись
// и сохраняет в файл
type
TRecordSaver = class(TThread)
private
fStream: TStream;
procedure UpdateMemo;
procedure WriteRec;
public
procedure Execute; override;
end;//of class


// процедура отображает новую запись в Memo
// компонент на форме
procedure TRecordSaver.UpdateMemo;
begin
Form1.Memo1.Lines.Add(Rec.Line);
end;

// процеура чтения новой записи
procedure TRecordSaver.WriteRec;
var S: string;
begin
// бликируем Rec для изменения из поставщика
Mtx.BeginRead;
try
if Rec = nil then Exit; // переходим к блоку finally если Rec пуста
// пишем в файл
S:=Rec.Line+#13#10;
fStream.WriteBuffer(pointer(S)^,Length(S));

//отображаем в Мемо
Synchronize(UpdateMemo);

// Rec нам больше не нужна
FreeAndNil(Rec);
finally
// не забываем разблокировать
Mtx.EndRead;
end;
end;

procedure TRecordSaver.Execute;
begin
// открываем файл для записи
fStream:=TFileStream.Create(RECORD_FILE,fmCreate or fmOpenWrite);
try
while not Terminated do begin
WriteRec;
// небольшая задержка
Sleep(100);
end;
finally
fStream.Free;
end;
end;


// наш поставщик
type
TRecordGenerator = class(TThread)
private
procedure GenerateRec;
protected
procedure Execute; override;
end;//of class

procedure TRecordGenerator.GenerateRec;
begin
// блокируем Rec для чтения из другого потока
Mtx.BeginWrite;
try
// создаём новую запись
if Rec = nil then // предыдущая запись прочитана
Rec:=TSaveRecord.Create;
finally
// снимаем блокировку
Mtx.EndWrite;
end;
end;

procedure TRecordGenerator.Execute;
begin
while not Terminated do begin
GenerateRec;
// опятьже задержка
Sleep(100);
end;
end;

var
Saver: TRecordSaver;
Generator: TRecordGenerator;

procedure TForm1.FormCreate(Sender: TObject);
begin
// создали синхронизатор
Mtx:=TMultiReadExclusiveWriteSynchronizer.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
Button2.Click;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//защита от дурака
if (Saver <> nil) or (Generator <> nil) then Exit;

// создали потребителя
Saver:=TRecordSaver.Create(true);

// создали пославщика
Generator:=TRecordGenerator.Create(true);

Memo1.Clear;

// поехали!!!
Saver.Resume;
Generator.Resume;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
// уничтожаем поставщика
if Generator <> nil then begin
Generator.Terminate;
Generator.WaitFor;
FreeAndNil(Generator);
end;
// уничтожаем потребителя
if Saver <> nil then begin
Saver.Terminate;
Saver.WaitFor;
FreeAndNil(Saver);
end;
end;

На форму положить: Memo - 1 штук; Button - 2 штуки; также подсоединить событие создания формы и разрушения (в моем коде они определены)

Автор: hiv 3.04.2006 14:26

Если надо использовать метод Synchronize, то вот так переделать:
Прикрепленный файл  Unit1.pas ( 5.31 килобайт ) Кол-во скачиваний: 517

Автор: Jill 3.04.2006 15:43

спасибо всем smile.gif за помощь, примеры и варианты

отдельно спасибо hiv - это то, что надо!!! пасиба smile.gif