# Native Code > برنامه نویسی در Delphi > توسعه نرم افزارهای تحت شبکه > آموزش: روش کپی کردن فایل بر روی سرور بدون اشتراک گذاشتن پوشه

## khorsandreza

سلام
قبل از هر چیز از کم و کاستی های که در تاپیک وجود خواهد داشت پوزش می خواهم این اولین تاپیکی است که سعی خواهم کرد مواردی را که از دوستان انجمن یاد گرفتم توضیح بدم  و امیدوارم با مساعدت دوستان و مدیران تالار ها تاپیک سودمندی بشود البته بخشی از مطالب در دیگر پستها بصورت پراکنده وجود دارد سعی خواهد شد تجربیات با مثال گفته شود
من در حال طراحی برنامه ای بودم با استفاده از دیتابیس بتوانم فایل های تصویری و صوتی را مدیریت بکنم  برای این منظور از امکانات خود دلفی و ابتدا پایگاه داده InterBase و سپس اسکیوال سرور استفاده کردم مشکل اصلی که داشتم این بود باید پوشه ای را در سرور به اشتراک می گذاشتم فایل ها را در این پوشه ذخیره سازی می کردم از انجائی که باید پوشه مزبور بصورت R/W بود کاربر های با سطح دسترسی R/W گاها فایل را از سرور حذف می کردند دنبال پروسه ای بودم بدون به اشتراک گذاشتن مسیر ذخیره سازی اطلاعات را در سرور ذخیره کنم که در این میان یکی از دوستان Reza_Yarahmadi  در این پست و اقای  You-See در این پست پیشنهاد کردن با استفاده از اسکیوال سرور این کار را انجام بدم چند روزی درگیر تحقیق روی این روش شدم  با استفاده از Sql-Server توانستم موردی که مد نظرم بود پیدا کنم و آن کپی فایل با استفاده از قابلیت های اسکیوال سرور در این میان به دو روش برخورد کردم یکی استفاده از امکانات فایل استریم و افزودن بعضی قابلیت به پایگاه داده که اقای وحید نصیری در سه جلسه توضیح مفصلی داده اند در این روش فایل های ارسال شده به سرور جزئی از اطلاعات پایگاه داده میشه و دقیقا فایل ها پشتیبان گیری و بازگرداندن هست مدیریت فایلهای بر عهده اسکیوال سرور است در این شیوه موقع بازیابی فایل نیازی به داشتن آدرس فیزیکی فایل بر روی سرور نیست و انتقال اطلاعات از روی سور به سرور دیگر همان روش گرفتن بکاپ و ریستور کردن است  ولی به نظر من دارای پیچیدگی های خاص خودش است که پوشه های تو در تو ساخته میشود و لاگ فایل پایگاه داده بزرگ میشود بطوری که من با افزودن 120 فایل تصویری با سایز 1MB فایل لاگ دیتابیس به 150MB رسید و به هیچ عنوان فشرده نشد .(اگه ناشیگری کردم مدیران راهنمائی کنند و تذکر بدهند)
روش دوم که از تلفیق روش بالائی درست کردم (از انجائی که هیچ ماستی نمیگه بقال ترشه :لبخند: )  بنظرم ساده و سریعتر هست خدمت دوستان عرض خواهم کرد (پست بعد)

----------


## khorsandreza

قسمت دوم :

همانطور که دوستان می دانند یکی از معایب بزرگ ذخیره کردن مسیر فیزیکی فایل در پایگاه داده تغییر مسیر است فرض ما تا امروز اطلاعات را در درایو F:\MyFile ذخیره می کردیماگر این مسیر تغییر پیدا کنه و بشود درایو E:\MyBook ما مجبور خواهیم شد در کل پایگاه داده اصلاح انجام بدیم و یا سناریو خاصی در نظر بگیریم فرضا ففط نام پوشه را ذخیره کنیم و موقع گزارش گیری نام درایو  بصورت متغییر دریافت کنیم که مشکلات خاص خودش است حال دوستان نسبت به کار چه نوع سناریوئی را تعریف می کنند بستگی به خودشان است .
ابتدا روش کپی کردن فایل به سرور را با مثال خدمت دوستان عرض کنم و سپس روشی که خودم کار می کنم و مسیرهای دسترسی و تغییر ان بدون آنکه در پایگاه داده تغییری اعمال شود
روش کار 
در اسکیول سرور جدولی به شکل زیر ایجاد کنید

EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE
CREATE TABLE [dbo].[TB_Image](
	[pk_id] [int] IDENTITY(1,1) NOT NULL,
	[ImgCode] [int] NULL,
	[ImgTopic] [nvarchar](50) NULL,
	[ImgTitle] [nvarchar](50) NULL,
	[ImgPath] [nvarchar](100) NULL,
 CONSTRAINT [PK_TB_Image] PRIMARY KEY CLUSTERED 
(
	[pk_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

این جدول جزئیات فایل تصویر و محل ذخیره سازی فایل را ثبت می کنیم
سپس یک SP بشکل زیر ایجاد کنید
قسمت اول SP فایل ارسالی از سمت کاربر را دریافت می کند و بشکل یک فایل در مسیر تعیین شده ذخیره می کند اگر فایلی با این نام  قبلا در این مسیر ذخیره شده باشد بر روی فایل قبلی مینویسد (میتونید با سناریوئی کنترل کنید فایلی هست در این مسیر و یا ... ) 

Create PROCEDURE [dbo].[AddTBImage]


(
	@ImgTopic nvarchar(50) ,
	@ImgTitle nvarchar(50) ,
	@ImgPath nvarchar(100) ,
	@FileData varbinary(max)  
--
)

AS
BEGIN
-- این قسمت کار ذخیره فایل را برروی سرور انجام می دهد
    Declare @ObjectToken INT
    EXEC sp_OACreate 'ADODB.Stream',@ObjectToken OUTPUT
    EXEC sp_OASetProperty @ObjectToken,'Type',1
    EXEC sp_OAMethod @ObjectToken,'Open'
    EXEC sp_OAMethod @ObjectToken,'Write',NULL,@FileData
    EXEC sp_OAMethod @ObjectToken,'SaveToFile',NULL,@ImgPath,2
    EXEC sp_OAMethod @ObjectToken,'Close'
    EXEC sp_OADestroy @ObjectToken
---------------------------------------این قسمت ذخیره امشخصات فایل در پایگاه داده---------------------------------
INSERT INTO TB_Image(ImgTopic,ImgTitle,ImgPath)
VALUES(@ImgTopic,@ImgTitle,@ImgPath)
END

----------


## khorsandreza

قسمت سوم:
در این قسمت کدهای سمت کاربر که با زبان دلفی است گفته می شود قبل از هر چیز  فایل پیوستی DalBase.pas را دانلود و به پروژه تان اضافه کنید این فایل را  از این پست 97 این تاپیک دریافت کردم با تغیرات جزئی در برنامه ام استفاده می کنم
فرمی بشکل زیر در دلفی ایجاد کنید و یا از پیوست کل پروژه را دانلود کنید
مطابق کد های نوشته شده در داخل پروژه 
این فرم فایل مورد نظر ما را دریافت برای کپی در سرور به سمت سرور ارسال می کند
در پست بعدی روشی که بدون نیاز به تغییر فیزیک مسیر فایل در پایگاه داده باشیم به همراه روش فراخوانی را خدمت دوستان عرض خواهم کرد 
جا دارد در اینجا از دوستان عزیز 
آقایان :
You-See
Mahan-1363
Reza_Yarahmadi
گلد (Gold)
وحید نصیری تشکر  بکنم
ضمننا مدیران نسبت به راهنمائی عنایت داشته باشند

----------


## khorsandreza

سلام
قسمت 4
ابتدا دو تا جدول در پایگاه داده ایجاد کنید(اسکریپت را از پیوست دانلود کنید)
یکی از جداول درایوهای قبل دسترسی برای کاربراس که با نام TB_Drive و جدول دوم پوشه فعالیت یا نام TB_WorkFolder میباشد
ابتدا ایتم های جداول
TB_Drive :
DriveID = ایدی است که برای هر درایو در نظر گرفته شود من در دوش خود 10 را درایو A: الی اخر مثلا درایو D  با ایدی 40 می باشد 
DriveStr = همانگونه که مشخص یک کاراکتری بوده و نام درایو را صرفا نگهداری می کند .
DriveAcc = این یک ایتم اختیاری است که دسترسی کاربران به داریوها محدود می کند
TB_WorkFolder :
PK_ID = فیلدی از نوع عددی بوده و بصورت خودکار (IDENTITY) مقدار دهی میشود
FolderPath = نام پوشه ای که ایجاد میشود مثلا MyFolder10001 
Onvan = نام یا شرح فارسی پوشه نگهداری میشود (داخل برنامه با این عناوین شناسائی میشود)
PathCode = کد یا همان DriveID از جدول TB_Drive  وارد میشود
Foldertype = نوع پوشه ای که اطلاعات ذخیره میشود من مثلا برای نگهداری پوشه تصویر عدد 1 و یا فایل صوتی عدد 2 و فایل تصویری(فیلم) عدد 3 و الی ... اخر استفاده میکنم- این فیلد اختیاری هست 
در دو فرم به شکل زیر من اطلاعات را از کاربر ریافت و در بانک ذخیره میکنم
*تذکر : کلیه جدوال من با استفاده از SP ذخیره یا اصلاح میشود*

SP زیر اطلاعات را از فرم زیرین دریافت و ضمن ذخیره اطلاعات پوشه کار را در درایو مورنظر می سازد در صورتی 
sp را بررسی در صورت سوال در خدمت خواهم بود

Create PROCEDURE [dbo].[AddWorkFolder]

(
	@PKID int,
	@DriveID int ,
	@Foldertype int,
	@Onvan nvarchar(50)
)

AS
BEGIN
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
  If(@pkid= 0)
  Begin
    declare @returnValue int
    declare @FolderStr nvarchar(6)
    set @FolderStr ='Other_'
    if (@Foldertype=1) set @FolderStr ='Movie_'
    else if (@Foldertype=2) set @FolderStr ='Sound_'
    else if (@Foldertype=3) set @FolderStr ='Image_'
    else if (@Foldertype=4) set @FolderStr ='Other_'
    Set @returnValue = 0;
    declare @GetDrive nchar(3)
    Select @GetDrive= DriveStr+':\' From TB_Drive Where DriveID=@DriveID
    Print @GetDrive
    declare @GetFolderCode int
    Select @GetFolderCode =Max(PathCode)+1 From TB_WorkFolder Where class = @DriveID
    if(@GetFolderCode is null)
     Begin
      Set @GetFolderCode = @DriveID*100000+1
     end 
    declare  @MakDir nvarchar(50)
    set @MakDir =@GetDrive+CAST(@GetFolderCode AS NvarChar(10))
    declare @xChk SMALLINT =0
	declare @Sql nvarchar(max)
	set @Sql =' EXECUTE  ChkDirExist "@MakDir" '
	EXEC sp_executeSql @query =@sql,@params = N'@xChk SMALLINT OUTPUT',@xChk=@xChk OUTPUT;
    print @xChk
    if(@xChk=0)
     begin
      set @MakDir = 'MD '+@GetDrive+@FolderStr+CAST(@GetFolderCode AS NvarChar(10))
      EXEC xp_cmdshell @MakDir
     end 
	Declare @Path nvarchar(200)
	Set @Path=@GetDrive+@FolderStr+CAST(@GetFolderCode AS NvarChar(10))+'\FolderHelp.txt' 
	declare @Command nvarchar(200)
	set @Command='echo '+@Onvan+'>' + @Path
	exec xp_cmdshell @Command, no_output
	----------------------------------------------------------------------
    if(@pkid= 0)
	Begin
      INSERT INTO TB_WorkFolder(FolderPath,Onvan,class,PathCode,Fold  ertype)
      VALUES(@GetDrive+@FolderStr+CAST(@GetFolderCode AS NvarChar(10)),@Onvan,@DriveID,@GetFolderCode,@Fold  ertype)
	  Set @returnValue = 1;
	End Else
	Begin
	Update TB_WorkFolder Set
	   Onvan =@Onvan 
	   Where PK_ID =@PKID;
	Set @returnValue = 1;
	End 
   End  Else
   Begin
	Update TB_WorkFolder Set
	   Onvan =@Onvan 
	   Where PK_ID =@PKID;
	Set @returnValue = 1;
   End 	
return @returnValue
End


ادامه در پست 13

----------


## hadisalahi2

محمد رضا جان ، لطفا اول نسخه Sql Server  رو معرفی کنید که با کدوم نسخه امکان پیاده سازی هستش
دوم اینکه در تاپیکی که معرفی کردید ، کدوم سورس کد رو دانلود کنیم
سوم اینکه ، این امکان در ویندوز XP هم قابل اجراست یا نه؟
چهارم ، نسخه دلفی که استفاده میکنید رو معرفی کنید و آیا اینکه در نسخه های قدیمی مثل 7 ، هم قابل اجرا هستش یا نه؟

----------


## یوسف زالی

رو حساب دخالت در کار دوستمون نباشه،
1- SQL ورژن 2008 به بالا این قابلیت رو داره.
2- ؟
3- این امکان ربطی به ویندوز مبدا و مقصد نداره
4- ربطی به دلفی هم نداره، مشروط به استفاده از SP

----------


## hadisalahi2

> 3- این امکان ربطی به ویندوز مبدا و مقصد نداره


پس اگه sql 2008 باشه به ویندوز هم مربوط میشه 
چون فکر نمیکنم این نسخه توی XP نصب بشه

----------


## hadisalahi2

در ضمن توی این عکس که نوشتی : ((محل ذخیره فایل در سرور ))
مگه نگفتی ، احتیاجی به مشخص نمودن آدرس سرور نیست؟
پس این کادر برای چی هستش؟

----------


## khorsandreza

> در ضمن توی این عکس که نوشتی : ((محل ذخیره فایل در سرور ))
> مگه نگفتی ، احتیاجی به مشخص نمودن آدرس سرور نیست؟
> پس این کادر برای چی هستش؟


سلام  اقای هادی
در این پست ها فقط مثال بود تا روش گفته بشه در پست 4 روش خودم را شرح میدم
با تشکر موفق باشین

----------


## khorsandreza

> پس اگه sql 2008 باشه به ویندوز هم مربوط میشه 
> چون فکر نمیکنم این نسخه توی XP نصب بشه


در هر نسخه ار ویندوز اگر اسکیوال سرور 2008 نصب بشه امکانش هست من تست نکردم روی XP نصب میشه یا نه ولی احتمال میدم با سرویس پک 3 ویندوز  XP قابل نصب باشه
خاطرتان باشه اگر اسکیو سرور روی کلاینت نصب شده باشه نمی شه فایل را بروی سرور کپی کرد حتما اسکیوال سرور در سمت سرور باید نصب بشه

----------


## khorsandreza

> محمد رضا جان ، لطفا اول نسخه Sql Server  رو معرفی کنید که با کدوم نسخه امکان پیاده سازی هستش
> دوم اینکه در تاپیکی که معرفی کردید ، کدوم سورس کد رو دانلود کنیم
> سوم اینکه ، این امکان در ویندوز XP هم قابل اجراست یا نه؟
> چهارم ، نسخه دلفی که استفاده میکنید رو معرفی کنید و آیا اینکه در نسخه های قدیمی مثل 7 ، هم قابل اجرا هستش یا نه؟


من با اسکیوال سرور 2008R2 کار می کنم و این قابلیت از این نسخه به بعد است ضمننا اسکیوال سرور با دلفی 7 مشکلی ندارد این مورد را تست کردم روی پروژه

----------


## khorsandreza

> رو حساب دخالت در کار دوستمون نباشه،
> 1- SQL ورژن 2008 به بالا این قابلیت رو داره.
> 2- ؟
> 3- این امکان ربطی به ویندوز مبدا و مقصد نداره
> 4- ربطی به دلفی هم نداره، مشروط به استفاده از SP


 آقا یوسف کلمه دخالت مناسب نیست  انتظار داریم راهنمائی بکنید و یا اگر در کلام و نوشتن ضعف داریم با توجه به تجربیاتتان اصلاح بشه علی الحال انتظار کمک داریم
موفق  باشین

----------


## khorsandreza

قسمت 5
در این روش اگر پوشه اطلاعات را از درایوی به درایو دیگر انتقال دهیم کافی است در فرم نمایش داده شده در پست 5 اصلاحی انجام دهیم و درایو را تغییر بدهیم بدون مراجعه به بانک اصلی مسیر اطلاعات تغییر پیدا خواهد کرد تصویر را ببینید

فکر می کنم دوستان با مشاهده تصویر بهتر متوجه کار شدند

*تذکر : در صورت نیاز به کامپوننت ها و یا اشکال در سورس کد ها اطلاع دهید*
کل پروژه را از اینجا دریافت کنید و یا از ضمیمه پست سورس کد را دانلود کنید

----------


## hadisalahi2

محمد رضا جان واقعا کارت ای ول داره
امیدوارم دوستان قدر این همه زحمت رو بدونند 

پیرو صحبت هایی که کردیم
من به سمت SQl Server 2012 میخوام برم
حالا توی این پکی که دارم این نسخه ها رو داره

باید کدوم نسخه رو نصب کنم؟

SQL SERVER 2012 BUSINESS INTELLIGENCE EDITION

SQL SERVER 2012 Developer

SQL SERVER 2012 ENTERPRISE EDITION

SQL SERVER 2012 ENTERPRISE Core

SQL SERVER 2012 STANDARD EDITION

SQL SERVER 2012 Web

در ضمن اگه توی نصبش نکته خاصی مد نظر هستش ، ممنون میشم یاد آوری کنی

----------


## hadisalahi2

محمد رضا جان این پروسیجر اجرا نمیشه و خطا میگیره
Create PROCEDURE [dbo].[AddWorkFolder]
 
(
    @PKID int,
    @DriveID int ,
    @Foldertype int,
    @Onvan nvarchar(50)
)
 
AS
BEGIN
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
  If(@pkid= 0)
  Begin
    declare @returnValue int
    declare @FolderStr nvarchar(6)
    set @FolderStr ='Other_'
    if (@Foldertype=1) set @FolderStr ='Movie_'
    else if (@Foldertype=2) set @FolderStr ='Sound_'
    else if (@Foldertype=3) set @FolderStr ='Image_'
    else if (@Foldertype=4) set @FolderStr ='Other_'
    Set @returnValue = 0;
    declare @GetDrive nchar(3)
    Select @GetDrive= DriveStr+':\' From TB_Drive Where DriveID=@DriveID
    Print @GetDrive
    declare @GetFolderCode int
    Select @GetFolderCode =Max(PathCode)+1 From TB_WorkFolder Where class = @DriveID
    if(@GetFolderCode is null)
     Begin
      Set @GetFolderCode = @DriveID*100000+1
     end 
    declare  @MakDir nvarchar(50)
    set @MakDir =@GetDrive+CAST(@GetFolderCode AS NvarChar(10))
    declare @xChk SMALLINT =0
    declare @Sql nvarchar(max)
    set @Sql =' EXECUTE  ChkDirExist "@MakDir" '
    EXEC sp_executeSql @query =@sql,@params = N'@xChk SMALLINT OUTPUT',@xChk=@xChk OUTPUT;
    print @xChk
    if(@xChk=0)
     begin
      set @MakDir = 'MD '+@GetDrive+@FolderStr+CAST(@GetFolderCode AS NvarChar(10))
      EXEC xp_cmdshell @MakDir
     end 
    Declare @Path nvarchar(200)
    Set @Path=@GetDrive+@FolderStr+CAST(@GetFolderCode AS NvarChar(10))+'\FolderHelp.txt' 
    declare @Command nvarchar(200)
    set @Command='echo '+@Onvan+'>' + @Path
    exec xp_cmdshell @Command, no_output
    ----------------------------------------------------------------------
    if(@pkid= 0)
    Begin
      INSERT INTO TB_WorkFolder(FolderPath,Onvan,class,PathCode,Fold    ertype)
      VALUES(@GetDrive+@FolderStr+CAST(@GetF  olderCode AS NvarChar(10)),@Onvan,@DriveID,@GetFolderCode,@Fold    ertype)
      Set @returnValue = 1;
    End Else
    Begin
    Update TB_WorkFolder Set
       Onvan =@Onvan 
       Where PK_ID =@PKID;
    Set @returnValue = 1;
    End
   End  Else
   Begin
    Update TB_WorkFolder Set
       Onvan =@Onvan 
       Where PK_ID =@PKID;
    Set @returnValue = 1;
   End 
return @returnValue
End

توی این خط
      VALUES(@GetDrive+@FolderStr+CAST(@GetF  olderCode AS NvarChar(10)),@Onvan,@DriveID,@GetFolderCode,@Fold    ertype)

البته به خاطر فاصله افتاده بین پارامتر آخره

فاصله ها رو هم که درست کردم ، بازم خطا میده 

بقیه موارد رو هم دارم چک میکنم

----------


## hadisalahi2

من بعد از اینکه پروسیجر بالا به خطا خورد ، خواستم دیتابیس رو Restore کنم

اما متاسفانه هنگام Restore کردن دیتابیس هم خطا میده

حالا دقیقا نفهمیدم کدوم بانک اطلاعات اصلی برنامه هستش

چون توی این فایل هایی که گذاشتی ، چندین فایل Bak وجود داره

در ضمن اون فایل دو قسمت ، تبدیل به یک قسمت باید بشه ، یا هر کدومش مربوط به یک بخش پروژه هستش؟

----------


## hadisalahi2

یک مشکل دیگه اینکه ، فکر کنم از کامپوننت های Raiz استفاده کرده باشی
البته یک کامپوننت png هم استفاده کرده بودی که متوجه نشدم چی بود

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

در ضمن نسخه دلفی که پروژه رو باهاش نوشتی چنده؟

----------


## hadisalahi2

در پروسیجر اول و هنگام اجرای این خط :

EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE


خطای زیر رو میده :

Msg 15123, Level 16, State 1, Procedure sp_configure, Line 51
The configuration option 'Ole Automation Procedures' does not exist, or it may be an advanced option.

----------


## hadisalahi2

توی پروسیجری که گفتم اجرا نمیشه ؛ شما یک فیلد به نام Class تعریف کردید ، اما در جدول TB_WorkFolder این فیلد تعریف نشده
بعد از کمی دست کاری ٰ بالاخره پروسیجر رو تونستم اجرا کنم
الان مشکل فقط روی اون کامپوننت هایی هستش که توی پروِژه اصلی گذاشتی ...

----------


## hadisalahi2

با کلی زور و ضرب تونستم پروِژه رو اجرا کنم

اما متاسفانه ، چند تا خطا موقع کار با برنامه بوجود اومده که خدمتتون عرض میکنم

1- : موقع ورود به فرم انتخاب عکس ، پیغام زیر رو میده



احتمالا فراموش کردی یک جدول رو در بانک اطلاعاتی ایجاد کنی.

2- هر عکسی رو که انتخاب میکنم پیغام خطای زیر رو میده :



3- موقع ذخیره کردن هم پیغام خطای زیر رو میده:

----------

