PDA

View Full Version : چند مشکل در رابطه با تابع CopyFile



A_Salimi
جمعه 16 فروردین 1387, 15:14 عصر
با سلام :

قبل از عنوان کردن این سوال ، CopyFile رو جستجو کردم ولی در موارد جستجو متاسفانه نتونستم مشکل رو برطرف کنم و به جواب برسم :

من سعی میکنم تا از این تابع برای کپی کردن یک فایل (در اینجا فایل عکس ) از یک دایرکتوری به دایرکتوری دیگر و یا به فولدری در همان دایرکتوری استفاده کنم مشکلاتی رو که برای من بوجود اومدند رو در زیر میارم :

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



LPCTSTR a="C:\\test.txt";
LPCTSTR b="C:\\New Folder";
BOOL h=CopyFile(a,b,FALSE);
if(h==0)
MessageBox(_T("function fail"));



که در درایو c هم فولدر New Folder هم موجود بود اما جالب اینجاست که بدونید بعد از اجرای خطوط فوق یک فایل به نام New Folder در درایو c بوجود می اومد !!! بعضی ها گفتند که برای مسیر دوم دوم باید دو بک اسلش دیگه هم بذارم یعنی به این صورت :



LPCTSTR b="C:\\New Folder\\”;

که البته فرقی نکرد.

2) در ادامه همان کارها را برای فایل jpg انجام دادم که نمیدونم چرا تابع fail میشد ؟
یعنی به این صورت :



LPCTSTR a="C:\\mypic.jpg";

3) من برای انتخاب عکسم از دیالوگ file browser و برای مسیر فولدرم از folder browser استفاده میکنم و آدرس های نهایی رو در یک edit box چاپ میکنم اما مشکلی که وجود داره اینه که آدرس رو با یک بک اسلش ( \ ) برمیگردونن (در حالی که در ویژوال سی باید از دو تا استفاده شه) و زمانی که اون آدرس ها رو در تابع قرار میدم تابع fail میشه . برای رفع این مشکل باید چکار کنم ؟

با تشکر

BitMap
جمعه 16 فروردین 1387, 17:08 عصر
شما باید برای مسیر مقصد هم نام کامل فایل را بنویسید.مثلا


LPCTSTR a="C:\\test.txt";
LPCTSTR b="C:\\New Folder\\text.txt";
BOOL h=CopyFile(a,b,FALSE);
if(h==0)
MessageBox(_T("function fail"));


برای همین این تابع برای rename هم به کار میره
در مورد بک اسلاش هم فکر نکنم این طور باشه.شما آدرس رو از کجا استخراج می کنید. m_OFN یکی از اعضای file browser هست.از اون می تونی استفاده کنی
این کد رو ببین:


#include <windows.h>
#include <stdio.h>

void main()
{
WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
TCHAR szDirPath[] = TEXT("c:\\TextRO\\");
TCHAR szNewPath[MAX_PATH];

BOOL fFinished = FALSE;

// Create a new directory.

if (!CreateDirectory(szDirPath, NULL))
{
printf("Could not create new directory.\n");
return;
}

// Start searching for text files in the current directory.

hSearch = FindFirstFile(TEXT("*.txt"), &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
printf("No text files found.\n");
return;
}

// Copy each .TXT file to the new directory
// and change it to read only, if not already.

while (!fFinished)
{
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (CopyFile(FileData.cFileName, szNewPath, FALSE))
{
dwAttrs = GetFileAttributes(FileData.cFileName);
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;

if (!(dwAttrs & FILE_ATTRIBUTE_READONLY))
{
SetFileAttributes(szNewPath,
dwAttrs | FILE_ATTRIBUTE_READONLY);
}
}
else
{
printf("Could not copy file.\n");
return;
}

if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
printf("Copied all text files.\n");
fFinished = TRUE;
}
else
{
printf("Could not find next file.\n");
return;
}
}
}

// Close the search handle.

FindClose(hSearch);
}

A_Salimi
جمعه 16 فروردین 1387, 17:43 عصر
ممنونم ، همونطوری که گفتید هستش

اما باید بگم اگه از یک بک اسلش استفاده کنیم تابع fail میشه . در هر حال مشکلی که گفتم در مورد file browser و folder browser همچنان وجود دارند در همون تابع اگه a توسط یک file browser و b توسط یک folder browser ایجاد بشه دو تا مشکل بوجود می آید :

1) آدرس ها دارای یک بک اسلش هستند.
2) قسمتی رو که در پست اول گفتید که باید به انتهای آدرس دوم اضافه بشه تا تابع به درستی عمل کند رو چطور به آدرس حاصل از folder browser اضافه کنم ؟

با تشکر

A_Salimi
شنبه 17 فروردین 1387, 09:44 صبح
سلام

اگه واسه کسی مقدوره به دو سوال قبلی من پاسخ بده ممنون میشم.

Nima_NF
شنبه 17 فروردین 1387, 16:12 عصر
1) آدرس ها دارای یک بک اسلش هستند.
2) قسمتی رو که در پست اول گفتید که باید به انتهای آدرس دوم اضافه بشه تا تابع به درستی عمل کند رو چطور به آدرس حاصل از folder browser اضافه کنم ؟

مسیر فولدر اگر به صورت یک slash باشد درست عمل خواهد کرد، همان مسیر را بدون تغییر به توابع دیگر ارسال کنید، چرا که در بسیاری از پروژه ها به همین شکل دیدم.
اگر هم جواب نمی دهد با نوشتن یک الگوریتم \ را با \\ جایگزین کنید

برای مورد دوم هم وقتی نام مسیر یا فولدر را دریافت کردید، به راحتی با نام و پسوند مورد نظر از طریق strcat آن را به انتهای رشته (مسیر) اضافه کنید.

A_Salimi
شنبه 17 فروردین 1387, 16:46 عصر
در مورد file browser از روش زیر استفاده میکنم :

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



char* openfile(char filter[],char defuext[],char title[])




{


char filename[500]={0};


char filetitle[100];


OPENFILENAME of;

memset(&of,0,sizeof(of));

of.lStructSize=sizeof(OPENFILENAME);
of.hwndOwner=NULL;
of.hInstance=NULL;
of.lpstrFilter=TEXT(filter);
of.lpstrCustomFilter=NULL;
of.nMaxCustFilter=0;
of.nFilterIndex=1;
of.lpstrFile=filename;
of.nMaxFile=1000;
of.nMaxFileTitle=99;
of.lpstrFileTitle=filetitle;
of.lpstrTitle=title;
of.Flags=OFN_NOREADONLYRETURN;
of.lpstrDefExt=defuext;
of.lCustData=NULL;
of.lpfnHook=NULL;
of.lpTemplateName=NULL;
GetOpenFileName(&of);
return(filename);
}













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





UpdateData();



strcpy(filename,openfile("Picture files (*.jpg;*.bmp;*.png)\0*.jpg;*.bmp;*.png","jpg;bmp;png","Choose pictures..."));



if(filename[0]!='\0'){



filen=filename;



filen.MakeUpper();



CString ext=filen.Right(3);}



UpdateData(FALSE);






که filen یک متغیر CString برای edit box است .


در مورد folder browser هم به این صورت عمل میکنم :





void CFolderBrowserDlg::OnButtonBrowse()



{



// TODO: Add your control notification



// handler code here



LPMALLOC pMalloc = NULL;



LPITEMIDLIST pidl = NULL;



BROWSEINFO bi;



ZeroMemory(&bi, sizeof(BROWSEINFO));




// set the bi's default values



bi.hwndOwner = m_hWnd;



bi.lpszTitle = _T("Current folder is:");



bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;



bi.lpfn = BrowseCallbackProc;



pidl = SHBrowseForFolder(&bi);



if(pidl != NULL)



{



SHGetPathFromIDList(pidl,



m_strFolderPath.GetBuffer(



m_strFolderPath.GetLength()));



UpdateData(FALSE);



// free memory



if(SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc);



pMalloc->Free(pidl);



pMalloc->Release();



}



}









int CALLBACK BrowseCallbackProc(



HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)



{



switch(uMsg)



{



case BFFM_INITIALIZED:



{



// add your initialization code here



}



break;



case BFFM_SELCHANGED:



{



TCHAR szText[MAX_PATH] = {0};



SHGetPathFromIDList(



reinterpret_cast<LPITEMIDLIST>(lParam), szText);



SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0,



reinterpret_cast<LPARAM>(szText));



}



break;



}



return 0;



}







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






BOOL h=CopyFile(filen,m_strFolderPath,TRUE);


if(h==0)


MessageBox(_T("function fail"));




که با MessageBox مواجه میشم.

Nima_NF
شنبه 17 فروردین 1387, 17:36 عصر
نگاه کنید درست هست که شما از \\ در هنگام تعریف مسیر استفاده می کنید ولی در هنگام ذخیره شدن فقط یک کارکتر \ در رشته ذخیره می شود چرا که در غیر این صورت کارکتر دیگری به جای \ ذخیره می شود.
پس این مورد یعنی رشته های دریافتی از توابع فوق درست هستند و باید یک \ را نشان دهند و مشکلی در این باره وجود ندارد.

اما در مورد این خط:



BOOL h=CopyFile(filen, m_strFolderPath, TRUE);

در این خط عمل debug را انجام دهید و بادقت دو رشته را با تک تک کارکتر هایش بررسی کنید که آیا مسیر در این مرحله کاملا درست هست یا نه ، و هر دو باید دارای نام فایل و پسوند آن هم باشند.
از انجایی که به پروژه دسترسی نداریم نمی توانیم بررسی دقیق کنیم. در یکی از خطوط از MakeUpper استفاده کردید که این کار بر روی تمامی کارکتر ها تاثیر می گذارد و حتی \ را به کارکتر دیگری تبدیل می کند و مسیر اشتباه خواهد شد.

پس خودتان در این مرحله نیز می توانید از GetLastError استفاده کنید تا متوجه شوید چه خطایی رخ می دهد.

A_Salimi
شنبه 17 فروردین 1387, 18:54 عصر
مسیر ها رو کاملا چک کردم (در مد دیباگ) که درست بودند (البته با یک \ ) .
در مورد MakeUpper هم ، رشته رو قبل از اینکه به این دستورات برسه در متغیر دیگری ذخیره کردم و سپس به CopyFile فرستادم . . . اما باز هم تابع fail شد.
در مورد GetLastError دقیقا چه کاری رو انجام میده ؟ و چطور باید ازش استفاده کنم ؟
در نهایت فکر کنم باید همون نظریه شما رو پیاده سازی کنم یعنی تابعی بنویسم که \ رو به \\ تبدیل کنه و در ضمن رشته ها رو به هم بچسپونه !

Nima_NF
شنبه 17 فروردین 1387, 20:43 عصر
GetLastError را بعد اجزای تابع copy قرار دهید و مقدار برگشتی آن را ذخیره کنید،

سپس شماره خطای برگشتی را در MSDN چک کنید تا ببینید چه خطایی رخ داده است.

A_Salimi
شنبه 17 فروردین 1387, 21:58 عصر
از GetLastError استفاده کردم و این تابع مقدار 5 رو برگردوند و این در msdn یعنی :


Access is denied.

به نظر شما این میتونه از همون آدرس دهی با یک \ باشه ؟

Nima_NF
یک شنبه 18 فروردین 1387, 15:53 عصر
به نظر شما این میتونه از همون آدرس دهی با یک \ باشه ؟
3 خط اول پست شماره 7 من را دوباره بخوانید، در رشته مسیر شما فقط یک \ ذخیره خواهد شد نه دو تا ، پس اشکال جای دیگری است.
یا مسیر ها به همراه نام فایل اشتباه هستند یا فایل مورد نظر در حال اجرا است و توسط تابع قابل دسترسی نیست یا ...

برای اینکه به نتیجه برسید به صورتی دستی، مانند پاراگراف اول پست شماره 2 BitMap دو مسیر را تعریف و تابع را اجرا کنید تا با مسیر دهی خوب آشنا شوید و بتوانید مشکل را حل کنید (حتما با debug در هملن خط دو مسیر را مشاهده کنید تا ببینید که فقط یک \ در مسیر دستی شما ذخیره شده است و سپس آن را با مسیر های برنامه ای که خودتان نوشتید مقایسه کنید)

A_Salimi
یک شنبه 18 فروردین 1387, 18:22 عصر
در رشته مسیر شما فقط یک \ ذخیره خواهد شد نه دو تا


خوب درسته ، منظورتون رشته های برگردانده شده توسط filebrowser و folderbrowser هست دیگه ؟



پس اشکال جای دیگری است.


چرا ؟ اتفاقا اشکال همین جاست چون همونطوری که قبلا هم گفته بودم به صورت دستی و با \\ کاملا به جواب رسیده بودم . ولی با \ و به صورت دستی تابع fail شد .(پس فکر نمیکنم مقایسه فایده ای داشته باشه )


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




void CtestDlg::myfunction(CString str1){
int len1=strlen(str1);
char k[]="\\\\\\";
int j=0;
for(int i=0;i <len1 ;i++){
str3[j]=str1[i];
if(str1[i]==k[1]){
str3[j+1]=k[1];
j++;
}
j++;
}
}


در نهایت در str3[200] مسیر با \\ ذخیره خواهد شد اما خوب خانه هایی که در آن هیچ کاراکتری ذخیره نشده اند خالی خواهند ماند که مسلما درست نیست در ضمن من خواستم از تابع Mid استفاده کنم که مشکل داشت . . . یه چیزی شبیه این :



Str3[200]. Mid(0,j);

استفاده از متغیر k به این شکل هم شاید تا حدی خنده دار باشه (هرچند درست عمل میکرد) چون خط زیر با مشکل مواجه میشد :



if(str1[i]==’\’)

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

A_Salimi
دوشنبه 19 فروردین 1387, 17:59 عصر
حرفم رو پس میگیرم حرف شما درسته من کاملا متوجه منظور شما نشده بودم در حقیقت زمانی که از \\ استفاده میکنیم ، در حالت دیباگwatch )) آدرسها به صورت \ دیده میشوند. (پس اشکال جای دیگری است)

من فایل رو به صورت کامپایل نشده در زیر قرار داده ام ، اگه لطف کنید و بگید که چطور می تونم مشکل Fail شدن تابع CopyFile رو بر طرف کنم.

با تشکر

BitMap
دوشنبه 19 فروردین 1387, 18:40 عصر
من به شما گفتم.
پارامتر دو این تابع مسیر کامل فایل مقصد همراه نام فایل است.بعنی این اشتباهه:

CopyFile("C:\\001.txt","C:\\",TRUE);
این درسته:

CopyFile("C:\\001.txt","C:\\002.txt",TRUE);

که شما در کدتون از نوع اول استفاده کرده اید.با یک debug ساده میشه فهمید

A_Salimi
دوشنبه 19 فروردین 1387, 19:19 عصر
حرف شما کاملا درسته و من هم در اون پستی که داشتید به اون نکته دقت کردم و به جواب هم رسیدم .
اما در مورد استفاده از browser ها :
دو راه هست که این دو آدرس رو به هم بچسپونیم :

1)استفاده از StrCat با header : shlwapi.h
2)استفاده از strcat

)به بزرگی و کوچکی حروف دقت کنید)
و یک چیز دیگه هم هست :
فرض کنید آدرس اول ما این باشه :



C:\a.txt

و آدرس دوم این باشه :



C:\New Folder

چیزی که در آرگومان دوم نیاز داریم باید اینجور چیزی باشه :



C:\New Folder\a.txt

پس برای رشته دوم این اتفاق افتاد :C حذف شده . . . درسته ؟

پس من قبل از چسپاندن رشته ها باید این دو کاراکتر رو در ابتدا از رشته حذف کنم که من از Mid استفاده کردم اما نمیدونم چرا رشته خروجی خالیه ؟ یه چیزی شبیه زیر :



Str2.mid(2,strlen(str2))

اما خروجیش همیشه خالیه !
ضمنا StrCat ورودی از نوع LPTSTR می خواد چطور میشه CString رو به این نوع تبدیل کرد ؟
در مورد strcat هم که یکی از ورودیهاش char* هستش که البته روش تبدیلش به CString در msdn هست .

یه روش برای درست چسپاندن رشته ها میخوام

با تشکر

Nima_NF
دوشنبه 19 فروردین 1387, 22:12 عصر
وقتی از CString استفاده می کنید امکانات زیادی برای کار با رشته ها دارید (متد های کلاس آن و کلاس های که از آن مشتق شده است را مشاهده کنید)، مثلا برای اضافه کردن رشته CString دیگر به جای strcat از Append می توانید استفاده کنید:



CString str1;

str1.Append(str2);

و یا اگر بخواهید از توابع استاندارد C استفاده کنید از GetBuffer استفاده کنید تا اشاره گری به رشته را برای char برگرداند، برای مثال:



CString str1_Folder;

strcat( str1_Folder.GetBuffer(str1_Folder.GetLength()) , _T("\\xxx.jpg"));

امیدوارم مطالب را با دقت بیشتری مطالعه کنید، مخصوصا وقتی که راهکار اولیه چندین مرتبه تکرار شده است.

BitMap
سه شنبه 20 فروردین 1387, 06:31 صبح
شما می تونید علاوه بر گرفتن مسیر فایل انتخاب شده ، فقط نام آن را هم بگیرید
از آن استفاده کنید

A_Salimi
سه شنبه 20 فروردین 1387, 11:56 صبح
سلام
نیما جان از این که وقت شما رو گرفتم معذرت میخوام همینطور شما bitmap عزیز .

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

اما کد من :




CString a=str1;
str1=str1.Mid(2);
char * b=strcat( m_strFolderPath.GetBuffer(m_strFolderPath.GetLengt h()) ,str1);
BOOL h=CopyFile(a,b,FALSE);
DWORD n=GetLastError();
if(h==0)
MessageBox(_T("function fail"));


چرا این کد همه جا درست عمل نمیکنه ؟

A_Salimi
سه شنبه 20 فروردین 1387, 13:38 عصر
مشکل اینجا بود که مسیر فایل رو به مسیر فولدر می چسپاندم که این غلطه و به همون حرف bitmap در پست 17 رسیدم . یعنی در آرگومان دوم تابع بایستی اول مسیر فولدر و سپس فقط نام فایل رو ذکر کنیم .