PDA

View Full Version : خواندن / نوشتن اطلاعات از / در فایل ...



Mahmood_M
چهارشنبه 18 مهر 1386, 15:19 عصر
با سلام ...

من یک کلاس به صورت زیر دارم :

type
TProject = class
private
function CheckFile(FName : String) : Boolean;
public
Info : TProjectInfo;
procedure SaveToFile(FName : String; ACode : TStrings; CCode : TStrings; Password : String);
function LoadFromFile(FName : String; ACode : TStrings; CCode : TStrings) : Boolean;
end;

متغیر Info در کلاس بالا از نوع TProjectInfo هست که اون به صورت یک رکورد تعریف شده :

type
TProjectInfo = record
Algorithm : TStringList;
Acount : Integer;
Code : TStringList;
CCount : Integer;
Password : String[20];
end;

من میخوام اطلاعاتی رو در رکورد بالا ( TProjectInfo‌ ) وارد کنم و بعد اون رو به عنوان یک فایل ذخیره کنم ...

برای ذخیره اطلاعات از روش زیر استفاده کردم :

procedure TProject.SaveToFile(FName : String; ACode : TStrings; CCode : TStrings; Password : String);
var
PrFile : file of TProjectInfo;
I : Integer;
begin
Info.Algorithm := TStringList.Create;
Info.Code := TStringList.Create;
for I := 0 to ACode.Count - 1 do
begin
Info.Algorithm.Add(ACode.Strings[I]);
end;
for I := 0 to CCode.Count - 1 do
begin
Info.Code.Add(CCode.Strings[I]);
end;
Info.Acount := Info.Algorithm.Count;
Info.CCount := Info.Code.Count;
Info.Password := Password;
AssignFile(PrFile, FName);
Rewrite(PrFile);
try
Write(PrFile, Info);
finally
CloseFile(PrFile);
end;
Info.Algorithm.Free;
Info.Code.Free;
end;

کد بالا به خوبی عمل میکنه و فایل ذخیره میشه ...

و اما برای خواندن فایل از روش زیر استفاده کردم :

function TProject.LoadFromFile(FName : String; ACode : TStrings; CCode : TStrings) : Boolean;
var
PrFile : file of TProjectInfo;
I, PI : Integer;
Pass : String[20];
begin
Result := False;
Info.Algorithm := TStringList.Create;
Info.Code := TStringList.Create;
AssignFile(PrFile, FName);
Reset(PrFile);
try
Read(PrFile, Info);
finally
CloseFile(PrFile);
end;
Pass := Info.Password;
if Pass <> '' then
begin
for PI := 0 to 3 do
begin
if InputBox('Password Protected ...', 'Enter Password of File Here :', '') = Pass then
begin
for I := 0 to Info.Acount - 1 do
ACode.Add(Info.Algorithm.Strings[0]);
for I := 0 to Info.CCount - 1 do
CCode.Add(Info.Code.Strings[I]);
Result := True;
Break;
end;
end;
end
else
begin
Result := True;
Exit;
end;
Result := True;
end;

برای استفاده از این کدها هم این کار رو میکنم :

procedure TMainFrm.OpenMenuClick(Sender: TObject);
var
Project : TProject;
begin
if OpenDialog.Execute then
begin
Project := TProject.Create;
try
Project.LoadFromFile(OpenDialog.FileName, ACodeMemo.Lines, CCodeMemo.Lines);
finally
Project.Free;
end;
end;
end;

مشکل اینجاست که در هنگام وارد کردن اطلاعات به Acode و CCode در تابع LoadFromFile یک AV نمایش میده ، هرکاری کردم نتونستم دلیل رو متوجه بشم ... !!
من Class و رکورد رو در یک یونیت جدا تعریف کردم و متد آخر که برای استفاده هست رو در یک Unit دیگه مینویسم ...

کدهای بالا رو خیلی تغییر دادم و یک بار هم نتیجه گرفتم ولی کد ماقص بود ، الآن که کامل شده هرچی سعی می کنم نمیتونم به نتیجه برسم ...

اگر یکی از دوستان راهنمایی کوچیکی بکنه ممنون میشم ...
اگر توضیحات کامل نیست بگید تا بیشتر توضیح بدم ...

با تشکر از همگی ...

ghabil
چهارشنبه 18 مهر 1386, 19:33 عصر
ببین تو نمیتونی همینطوری یک آبجکت رو که Write کنی ! این Info تو یک آبجکت هست نه یک رکورد ، اگر میشد یک آبجکت رو به همین راحتی ذخیره کرد دیگه اینهمه مکامنیزم Streaming که توی DFM هست بیخود بود که !
این کد ذخیره کردنی که نوشتی یعنی Write(F,Info) توی Info فقط آدرس آبجکت F توی حافظه هست برای همین هم فقط اون آدرس ذخیره میشه ، اگر هم دقت کنی میبینی هرچقدر هم که توی آبجکتت vALUE ریخته باشی تغییری در حجم فایل ساخته شده ایجاد نمیشه و همیشه احتمالا 4 بایت میمونه ، دلیلش اینه که فقط آدرس آبجکت توی حافظه داره نوشته میشه ، خب طبعیه که اگر بعدا این آدرس رو بخونی داره به یک آدرس Garbage تو حافظه اشاره میکنه و آبجکت اصلی هم از بین رفته .
راه حلت اینه که مکانیزمی بنویسی که آبجکتت رو به یک رکورد تبدیل کنه و رکورد رو ذخیره کنی زمانی هم که میخونی رکورد رو بخونی و به آبجکت تبدیل کنی .

یا میتونی کلاست رو از TPersistant درایو کنی و بعد از مکانیزمهایی استریمینگش استفاده کنی برای نوشتن آبجکتت ، اما دیگه امکاناتی که توی فایلینگ داری رو نخواهی داشت.

Mahmood_M
چهارشنبه 18 مهر 1386, 21:31 عصر
سلام
ممنون بابت جواب ...

این Info تو یک آبجکت هست نه یک رکورد
اما اون یک رکورد هست ... !! ، اون برابر با TProjectInfo هست که به عنوان یک رکورد تعریف شده ...
من این موضوع رو توی سایت About هم جستجو کردم و یک مقاله در همین مورد پیدا کردم که اونجا هم از همین روش استفاده شده ... ( لینک مقاله (http://delphi.about.com/od/fileio/a/fileof_delphi.htm) )

مشکل اصلی و تفاوت کد من اینه که من در رکورد خودم TStringList دارم ، و فکر می کنم همین باعث خطا شده ،‌چطور باید اطلاعات یک TStrings رو در فایل بریزم ؟
مشکل اصلی همینه ...

در رکوردی که تعریف کردم یک String هم هست برای Password ، اطلاعات اون نوشته و خونده میشه ، اما TStrings ها نه ... !!

توی مقدار دهی به TStrings ها مشکل دارم ...
یک جورایی انگار در Create و استفاده از این TStrings ها خوب عمل نکردم ...
من یک بار جواب گرفتم ، یعنی تونستم اطلاعات رو ذخیره و بازیابی کنم ولی الآن هرکاری میکنم نمیشه ... !!

به هر حال اگه بیشتر راهنمایی کنید ممنون میشم ...

موفق باشید ...

hossein taghi zadeh
چهارشنبه 18 مهر 1386, 23:13 عصر
با سلام


‌چطور باید اطلاعات یک TStrings رو در فایل بریزم


type
TProjectInfo = record
Algorithm : Array[1..100] Of String[255];
Acount : Integer;
Code : Array[1..100]Of String[255];
CCount : Integer;
Password : String[20];
end;
و یا راه حل بهتر:


Type
TProjectInfo = Class(TComponent)
FCode: TStrings;
FAlgorithm: TStrings;
Public
Procedure LoadFromFile(FileName: TFileName);
Procedure SaveToFile(FileName: TFileName);
Published
Property Code: TStrings Read FCode;
Property Algorithm: TStrings Read FAlgorithm;
End;

Procedure TProjectInfo.SaveToFile(FileName: TFileName);
Begin
WriteComponentResFile(FileName, Self);
End;

Procedure TProjectInfo.LoadFromFile(FileName: TFileName);
Begin
ReadComponentResFile(FileName, Self);
End;

ghabil
چهارشنبه 18 مهر 1386, 23:22 عصر
سلام
ممنون بابت جواب ...

اما اون یک رکورد هست ... !! ، اون برابر با TProjectInfo هست که به عنوان یک رکورد تعریف شده ...
من این موضوع رو توی سایت About هم جستجو کردم و یک مقاله در همین مورد پیدا کردم که اونجا هم از همین روش استفاده شده ... ( لینک مقاله (http://delphi.about.com/od/fileio/a/fileof_delphi.htm) )

مشکل اصلی و تفاوت کد من اینه که من در رکورد خودم TStringList دارم ، و فکر می کنم همین باعث خطا شده ،‌چطور باید اطلاعات یک TStrings رو در فایل بریزم ؟
مشکل اصلی همینه ...

موفق باشید ...

فرقی نداره به هر حال اونایی که توشون StringList هار رو نگه میداری به آبجکت اشاره میکنند و این اتفاق برای اونها میفته ، یعنی فقط آدرسشون ذخیره میشه ، کاری نداره که برای اینکه مطمئن بشی یکی از استرینگ لیستهات رو خیلی بزرگ کن ، مثلا توش 100000 بار بنویس Alireza ببین حجم فایلی که ساخته میشه فرق میکنه یا نه !
به هر حال تو نمیتونی یک آبجکت رو اینطوری ذخیره کنی ، اگر هم یک بار کردی شده شاید دلیلش این بوده که هنوز اون جافظه سالم بوده و تغییر نکرده بوده ، یعنی بالافاصله بعد از Save تست کردی و لود کردی که البته اینم بعیده!

Mahmood_M
پنج شنبه 19 مهر 1386, 00:09 صبح
@جناب تقی زاده :
راه حل اول نمی شه چون من میخوام یک لیست از رشته ها رو ثبت کنم ( تعدادشون هم مشخص نیست )

راه حل دوم هم باید امتحان کنم ،‌ امیدوارم جواب بده ...

به هر حال ممنون ...


فرقی نداره به هر حال اونایی که توشون StringList هار رو نگه میداری به آبجکت اشاره میکنند و این اتفاق برای اونها میفته ، یعنی فقط آدرسشون ذخیره میشه ، کاری نداره که برای اینکه مطمئن بشی یکی از استرینگ لیستهات رو خیلی بزرگ کن ، مثلا توش 100000 بار بنویس Alireza ببین حجم فایلی که ساخته میشه فرق میکنه یا نه !
به هر حال تو نمیتونی یک آبجکت رو اینطوری ذخیره کنی ، اگر هم یک بار کردی شده شاید دلیلش این بوده که هنوز اون جافظه سالم بوده و تغییر نکرده بوده ، یعنی بالافاصله بعد از Save تست کردی و لود کردی که البته اینم بعیده!
درسته ، حق با شماست ، منم گفتم که مشکل از همون TStrings ها هست ...
میشه یه راهی پیشنهاد کنید ؟ چطور باید این کار رو انجام بدم ؟!

با تشکر از همگی ...

vcldeveloper
پنج شنبه 19 مهر 1386, 02:04 صبح
درسته ، حق با شماست ، منم گفتم که مشکل از همون TStrings ها هست ...
میشه یه راهی پیشنهاد کنید ؟ چطور باید این کار رو انجام بدم ؟!
باید روی طراحی کلاس ها بیشتر وقت بزارید و همونطور که گفته شد، کلاس های خود را از TPersistant یا یکی از مشتقاتش مشتق بگیرید تا بتونید از امکانات ذخیره در فایل آن استفاده کنید. همان کاری که دوستمان در پست 4 مثال دوم انجام دادند.

Mahmood_M
پنج شنبه 19 مهر 1386, 10:49 صبح
سلام
از همه دوستان ممنونم ( تا حدودی مشکل حل شد )
اما مشکل جدیدی که دارم :

مشکل در مقداردهی به TStrings ها هست !! :کف:

من کلاس رو به صورت زیر تعریف کردم:

type
TProjectInfo = Class(TComponent)

private
FCode : TStrings;
FAlgorithm : TStrings;
FPassword : String;
FACount : Integer;
FCCount : Integer;
function CheckFile(FName : String) : Boolean;
function CheckPassword(Pass : String) : Boolean;
public
procedure Save(FName : String);
function Load(FName : String) : Boolean;
published
property Algorithm : TStrings read FAlgorithm write FAlgorithm;
property Code : TStrings read FCode write FCode;
property Password : String read FPassword write FPassword;
property ACount : Integer read FACount write FACount;
property CCount : Integer read FCCount write FCCount;
end;

برای مقدار دهی ابتدا یک Procedure ایجاد کردم ، ( همون رویه Save در کلاس بالا اما با ورودیهای بیشتر ، دو تا ورودی که TStrings های مبدا رو میگیرن و یک ورودی هم برای پسورد و یک وردی هم به عنوان نام فایل ) ، بعد مقادیر دو TStrings ورودی رو در FAlgorithm و FCode ریختم و فایل ذخیره شد ، موقع Load کردن در دستور " ReadComponentRes(FName, Self) " یک AV نمایش میده !
انگار فایل مناسب نیست ...
گفتم شاید عناصر به درستی ‍Create نمی شن ! ، به خاطر همین کلاس بالا رو به صورت زیر تغییر دادم :

type
TProjectInfo = Class(TComponent)
FCode : TStrings;
FAlgorithm : TStrings;
private
FPassword : String;
FACount : Integer;
FCCount : Integer;
function CheckFile(FName : String) : Boolean;
function CheckPassword(Pass : String) : Boolean;
public
procedure Save(FName : String);
function Load(FName : String) : Boolean;
published
property Algorithm : TStrings read FAlgorithm write FAlgorithm;
property Code : TStrings read FCode write FCode;
property Password : String read FPassword write FPassword;
property ACount : Integer read FACount write FACount;
property CCount : Integer read FCCount write FCCount;
protected
constructor Create;
destructor Destroy;
end;

و Create و Destroy رو به صورت زیر تعریف کردم :

constructor TProjectInfo.Create;
begin
inherited Create(Owner);
Algorithm := TStrings.Create;
Code := TStrings.Create;
FAlgorithm := TStrings.Create;
FCode := TStrings.Create;
end;

destructor TProjectInfo.Destroy;
begin
FCode.Free;
FAlgorithm.Free;
Algorithm.Free;
Code.Free;
end;

اما باز هم همون مشکل هست ! ...
من در خارج از خود Component مقدار دهی رو انجام دادم ولی باز هم AV نشون میده ! ، یعنی در رویه Save ( به شکل بالا و بدون ورودیهای دیگر و فقط با ورودی نام فایل ) فقط WriteComponentRes رو نوشتم و مقدار دهی رو مثلا در OnClick یک منو انجام دادم ، ولی موقعی که میخوام خطوط یک TStrings رو در Algorithm یا Code یا FAlgorithm یا FCode بریزم باز هم AV نشون میده !! ( انگار TStrings های کامپوننت ساخته نشدن ! )

راستش دیگه نمیدونم چیکار باید بکنم ...

اگر میشه راهنمایی بیشتری بکنید ... ،‌ باورکنید الآن حدود 3 روز هست که دارم روش کار میکنم :کف: (‌ اینها حاصل بی تجربگی من در ساخت کامپوننتها هست ! :گیج: )

با تشکر از همگی ... ( بی صبرانه منتظرم )
موفق باشید ...

vcldeveloper
پنج شنبه 19 مهر 1386, 14:36 عصر
( انگار TStrings های کامپوننت ساخته نشدن ! )
TStrings یک کلاس Abstract هست. کلاس های دیگه از این کلاس مشتق میشند و متدهای آن را پیاده سازی می کنند. شما نمی تونید مستقیما از TStrings استفاده کنید، غیر از اینکه بخواید یک کلاس جدید بر پایه آن بسازید و متدهای آن را به روش خود پیاده سازی کنید. برای کاری که شما می خواید انجام بدید، باید از TStringList بجای TStrings استفاده بشه.

معمولا TStrings را در پارامترهای ورودی/خروجی توابع زیاد می بینید که معنی آن این است که این تابع هر یک از اشیاء ساخته شده از یکی از مشتقات TStrings را قبول می کند. یعنی هر چیزی که TStrings را پیاده سازی کرده باشد، از نظر تابع مربوطه قابل قبول است.

hossein taghi zadeh
پنج شنبه 19 مهر 1386, 14:52 عصر
با سلام


TStrings یک کلاس Abstract هست. کلاس های دیگه از این کلاس مشتق میشند و متدهای آن را پیاده سازی می کنند. شما نمی تونید مستقیما از TStrings استفاده کنید، غیر از اینکه بخواید یک کلاس جدید بر پایه آن بسازید و متدهای آن را به روش خود پیاده سازی کنید. برای کاری که شما می خواید انجام بدید، باید از TStringList بجای TStrings استفاده بشه.


type
TProjectInfo = Class(TComponent)
private
FCode : TStrings;
FAlgorithm : TStrings;
FPassword : String;
FACount : Integer;
FCCount : Integer;
function CheckFile(FName : String) : Boolean;
function CheckPassword(Pass : String) : Boolean;
Protected
Procedure SetCode(Value: TStrings);
Procedure SetAlgorithm(Value: TStrings);
public
procedure Save(FName : String);
function Load(FName : String) : Boolean;
published
property Algorithm : TStrings read FAlgorithm write SetAlgorithm;
property Code : TStrings read FCode write SetCode;
property Password : String read FPassword write FPassword;
property ACount : Integer read FACount write FACount;
property CCount : Integer read FCCount write FCCount;
end;

constructor TProjectInfo.Create;
begin
inherited Create(Owner);
FAlgorithm := TStringList.Create;
FCode := TStringList.Create;
end;

destructor TProjectInfo.Destroy;
begin
FCode.Free;
FAlgorithm.Free;
Inherited Destroy;
end;

Procedure TProjectInfo.SetCode(Value: TStrings);
begin
if value <> FCode then FCode.Assign(Value);
end;

Procedure TProjectInfo.SetAlgorithm(Value: TStrings);
begin
if value <> FAlgorithm then FAlgorithm.Assign(Value);
end;

Mahmood_M
پنج شنبه 19 مهر 1386, 17:30 عصر
جناب تقی زاده میشه در مور کدتون کمی توضیح بدید ، من مقدارم رو باید در کدوم Property وارد کنم ، موقع ورود اطلاعات در پروپرتی Algorithm یا Code باز هم AV نشون میده ... !!!!!

اگر میشه یک مثال بزنید ( لطفا توضیح بدید )

با تشکر از همگی ...

hossein taghi zadeh
پنج شنبه 19 مهر 1386, 20:23 عصر
با سلام

مثالی در این مورد ضمیمه شده است.

Hamid_PaK
جمعه 20 مهر 1386, 04:45 صبح
محمود جان تا جایی که من در این مورد تجربه دارم اکثر ذخیره و فراخوانی اطلاعات از فایل ها اینگونه است :
شما باید یک کلاس برای سرلوحه فایل باینری ایجاد کنید که شامل طول فایل و بدنه باشد.
بعد در ادامه مقادیر مورد نظر رو با چند بایت ابتدایی برای طول حافظه قسمت و اطلاعات باینری ذخیره و فراخوانی کنید.

به زبان ساده تر اینطوری می شه :


Heaher
{
signature: array[0..9] of Char; // must be 'Test File'
size: DWORD; // 15 bytes
}
Body
{
aaa
{
size: DWORD; // 10 bytes
stream: PByte; // 1234567890
}
aab
{
size: DWORD; // 5 bytes
stream: PByte; // abcde
}
...
...
...
}


یا حق ...

Mahmood_M
جمعه 20 مهر 1386, 11:53 صبح
با تشکر از همه دوستان ...

مشکل حل شد ...