【大話QT之三】FileZilla命令行實現文件上傳以及CreateProcess實現靜默調用

應用需求:

        用戶在選擇渲染作業時面臨兩種情況:一是選擇用戶遠程存儲上的文件;二是選擇本地文件系統中的文件進行渲染。由於渲染任務是在遠程主機上進行的,實際進行渲染時源文件也是在ftp目錄中獲取的,因此當用戶選擇本地文件系統中的文件時,文件必須上傳到ftp上的指定目錄中,遠程主機才能正確獲取到文件的路徑,下載後進行文件渲染,然後將渲染結果保存在ftp的指定路徑下。因此,需求就是當用戶選擇本地文件系統中的文件時,文件要自動上傳到ftp的目錄中,供渲染程序調用執行。

解決方案分析:

        原有Qftp的操作中存在文件上傳的操作,但是利用qftp中的方式,上傳文件不穩定,而且如果文件較大,很容易發生錯誤,因此纔想着使用外部的Ftp工具實現文件的上傳。

        到這裏我們已經明確,要實現上述目標需要解決以下兩個問題:1)FileZilla上傳文件的命令行形式。2)如何實現FileZilla靜默上傳,即不彈出窗口。

        1)FileZilla上傳文件的命令行形式。在解決這個問題的時候,費了一點時間。Google之後的確有使用命令行上傳文件的相關信息,但是我在cmd下調用FileZilla.exe查看相關幫助,一直說命令不存在。經過一番周折看到一篇帖子,說命令的支持與FileZilla的版本有關,較高版本的FileZilla不支持文件上傳的命令行形式。因此,又下載了較低版本的FileZilla,這裏我使用的是2.2.17版本。使用方式如下:

        OK,第一個問題解決,但它還不太完美,因爲到調用的時候總是彈出窗口,雖然在上述命令的最後加上"-close",在文件上傳結束後,窗口會自動關閉,但這會嚴重影響用戶的使用體驗,那麼就集中解決這個問題吧。

        2)如何實現FileZilla靜默上傳,即不彈出窗口

        剛開始解決這個問題時,一直在找它的命令行中是否相關參數能夠實現靜默上傳,但是很遺憾,沒有找到。甚至還想到了修改FileZilla的源碼,反正它也是開源的。但是後來一想,調用它要採用CreateProcess創建一個新的進程的方式,以前有些印象通過CreateProcess設置某些參數可以不顯示子進程的窗口。通過查閱相關資料,bingo,方案可行。相關代碼如下:

void LHGoldenfarmClientPrivate::StartProcessDownloadFiles(const QStringList downloadFiles)
{
	int file_count = downloadFiles.size();
	HANDLE *file_handles = (HANDLE *)malloc(file_count*sizeof(HANDLE)) ;
	for(int i = 0 ; i < downloadFiles.size() ; i++)
	{
		QFileInfo files(downloadFiles.at(i));

		if(files.exists()){

			STARTUPINFO si = {sizeof(si)};
			PROCESS_INFORMATION pi ;

			si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
			si.wShowWindow = SW_HIDE;

			QString ftpHost ;
			QString ftpUser ;
			QString ftpPass ;
			LHGoldenfarmClientPrivate::Mgr->GetFtpCredentials(ftpHost , ftpUser , ftpPass);
			QString filepath = files.absoluteFilePath().replace("/","\\");
			QString filename = files.fileName();
			QString filesuffix = files.suffix();
			QString destdir = QString("scene_Files") ;

			QString s_cmdline = QString("FileZilla//filezilla.exe -r -u %1 ftp://%2:%3@%4/%5 -t %6 -close").arg(filepath.toLatin1().data()
          ).arg(ftpUser.toLatin1().data()).arg(ftpPass.toLatin1().data()).arg(ftpHost.toLatin1().data()).arg(
                                            destdir.toLatin1().data()).arg(filename.toLatin1().data());
			
			qDebug() << s_cmdline.toLatin1().data();

			//! 完成多字節到寬字節的轉換
			WCHAR *w_cmdline = ConvertFromCharToWchar(s_cmdline.toLatin1().data());

			BOOL bRet = ::CreateProcess(
						  NULL ,
						  w_cmdline ,
						  NULL,
						  NULL,
						  FALSE,
						  CREATE_NO_WINDOW,
						  NULL,
						  NULL,
						  &si,
						  &pi
                        );

			if(bRet){
				file_handles[i] = pi.hThread;
			}

		}
	}

	WaitForMultipleObjects(file_count , file_handles , TRUE , 3 * 60 *1000);


}
         這裏主要要同時設置:si.wShowWindow = SW_HIDE以及CreateProcess中的CRATE_NO_WINDOW參數纔可以。好了,運行一下,嗯,不過,文件正確上傳;再運行一下,怎麼會彈出窗口?原來是文件已經存在了,在這種情況下,會彈出窗口詢問你如何操作,這裏採用-r的命令行可以設置默認直接覆蓋,話說這個參數還是自己猜出來的,我是有多麼偉大。

總結:

         這篇文章大部分爲技術性的,而非思路上的拓展。但是這裏要提的一點是,在解決第二個問題的時候,花的時間不太久,但是已近超過了我的預期。而且想起這個方法來,也是不經意間就想起來了。因爲以前用過這種方式,不知道爲嘛第一時間沒有想起這個方法來,看來還是知識掌握的不夠牢固,缺乏靈活運用。不過倒也符合我現在看書對自己的要求,不要試圖記一些東西,只要能在腦子裏留一點點印象就足夠了,將來碰到問題的時候,能有印象知道應該向哪個方向查找,或許這就是我說的思路。

        珍惜時間。時間這麼緊張,真心不想大把大把的把時間浪費在無用的事情上,因爲------我是有野心的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章