VS2010 上传、下载FTP服务器文件

来源:互联网 发布:vba编程从入门到精通 编辑:程序博客网 时间:2024/06/06 06:31

VS2010 上传、下载FTP服务器文件

  • 首先简单介绍一下相关类

MFC中的类CFtpConnection管理我们与Internet服务器的连接,并直接操作服务器上的目录和文件,FTP是MFC的WinInet支持的三个Internet功能之一,我们需要先创建一个CInternetSession实例和一个CFtpConnection对象就可以实现和一个FTP服务器的通信,我们不需要直接创建CFtpConnection对象,而是通过调用CInternetSession::GetFtpConnection来完成这项工作。它创建CFtpConnection对象并返回一个指向该对象的指针。

Ftp连接类的信息

—- 下面我们简要介绍连接类的信息

CInternetSession对象

CInternetSession(LPCTSTR pstrAgent,DWORD dwConText ,DWORD dwAccessType,LPCTSTR pstrProxyName,LPCTSTR pstrProxyBypass,DWORD dwFlags);

—- 在创建CInternetSession对象时调用这个成员函数,CInternetSession是应用程序第一个要调用的Internet函数,它将创始化内部数据结构,以备将来在应用程序中调用。如果dwFlags包含INTERNET_FLAG_ASYNC,那末从这个句柄派生的所有的句柄,在状态回调例程注冊之前,都会出现异步状态。如果沒有打开Internet连接,CInternetSession就会抛出一个例外,AfxThorowInternetException。

GetFtpConnection()函数

CFtpConnection* CIternetSession::GetFtpConnection(LPCTSTR pstrServer,LPCTSTR pstrUserName,LPCTSTR pstrPassword,INTERNET_PORT nPort,BOOL bPassive); 

—- 调用这个函数建立一个FTP连接,并获得一个指向CFtpConnection对象的指针,GetFtpConnection连接到一个FTP服务器,创建并返回指向CFtpConnection对象的指针,它不在服务器上进行任何操作。如果打算读写文件,必须进行分步操作。关于查找,打开和读/写文件的信息需参考CFtpConnection和CFtpFileFind类。

—- 对这个函数的调用返回一个指向CFtpConnection对象的指针。如果调用失败,检查抛出的CInternetException对象,就可以确定失败的原因。

GetFile()函数

BOOL GetFile(LPCTSTR pstrRemoteFile,LPCTSTR pstrLocalFile,BOOL bFailExists ,DWORD dwAttributes,DWORD dwFlags,DWORD dwContext); 

—- 调用这个成员函数,可以从FTP服务器取得文件,并且把文件保存在本地机器上。GetFile()函数是一个比较高级的例程,它可以处理所有有关从FTP服务器读文件,以及把文件存放在本地机器上的工作。如果dwFlags为FILE_TRANSFER_TYPE_ASCII,文件数据的传输也会把控制和格式符转化为Windows中的等阶符号。默认的传输模式是二进制模式,文件会以和服务器上相同的格式被下载。

—- pstrRemoteFile和 pstrLocalFile可以是相对于当前目录的部分文件名,也可以是全文件名,在这两个名字中间,都既可以用反斜杠()或者正斜杠(/)来作为文件名的目录分隔符,GetFile()在使用前会把目录分隔符转化为适当的字符。

—- 可以用自己选择的值来取代dwContext默认的值,设置为上下文标识符与CFtpConnection对象的定位操作有关,这个操作由CFtpConnection中的CInternetSession对象创建。返回给CInternetSession::OnStatusCallBack的值指出了所标识操作的状态。

—- 如果调用成功,函数的返回为非0,否则返回0,如果调用失败,可以调用Win32函数GetLastError(),确认出错的原因。

PutFile()函数

BOOL PutFile(LPCTSTR pstrLocalFile, LPCTSTR pstrRemoveFile ,DWORD dwFlags, DWORD dwContext); 

—- 调用这个成员函数可以把文件保存到FTP服务器。PutFile()函数是一个比较高级的例程,它可以处理有关把文件存放到服务器上的工作。只发送数据,或要严格控制文件传输的应用程序,应该调用OpenFile和 CInternet::Write。利用自己选择的值来取代dwContext默认的值,设置为上下文标识符,上下文标识符是CInternetSession对象创建的CFtpConnection对象的特定操作有关,这个值返回给CInternetSession::OnStateCallBack,从而把操作的状态通报给它所标识的上下文。

—- 如果调用成功,函数的返回为非0,否则返回0,如果调用失败,可以调用Win32函数GetLastError(),确认出错的原因。

连接到FTP站点

—- 建立连接到ftp.microsoft.com的程序,它是一个单文档程序。并且连接由视图类的构造函数完成。

  • 建立单文档程序ftp

在ftpview.h中加入包含

#include < afxinet.h > 

在ftpview.h中添加如下的成员变量

public: CInternetSession *m_pInetSession; CFtpConnection *m_pFtpConnection; 

在ftpview.cpp中的ftpview构造函数中加入下面的代码

CFtpView::CFtpView() { m_pInetSession=new CInternetSession (AfxGetAppName(),1, PRE_CONFIG_INTERNET_ACCESS); try { m_pFtpConnection=m_pInetSession-> GetFtpConnection("FTP.MICROSOFT.COM"); } catch(CInternetException *pEx) { TCHAR szError[1024]; if(pEx->GetErrorMessage(szError,1024)) AfxMessageBox(szError); else AfxMessageBox("There was an exception"); pEx->Delete(); m_pFtpConnection=NULL; } } 

在ftpview.cpp中的ftpview析构函数中加入下面的代码

CFtpView::~CFtpView() { if(m_pFtpConnection!=NULL) { m_pFtpConnection->Close(); delete m_pFtpConnection; } delete m_pInetSession; } 

编译并且执行程序,如果连接出现问题,将会在一个消息框中报告出错消息。
发送文件到FTP文件服务器

—- 创建一个发送文件到FTP文件服务器的程序

建立单文档程序ftpfw, 在ftpfwview.h中加入包含 #include < afxinet.h >

在ftpfwview.h中添加如下的成员变量

publicbool m_bConnectionAttempted; int m_nFileStatus; 在ftpview.cpp中的ftpview构造函数中加入下面的代码 CFtpfwView::CFtpfwView() { m_bConnectionAttempted=false; } 

使用ClassWizard加入新的类CFtpThread,该类派生于CWinThread 在ftpthread.h中加入如下变量

public: static UINT PutFile(LPVOID Status); 

添加新类成员函数代码

UINT CFtpThread::PutFile(LPVOID Status) {     int *pnFileStatus;     CInternetSession *pInetSession;     CFtpConnection *pFtpConnection=NULL;     pnFileStatus=(int *)Status;     *pnFileStatus=0;     pInetSession=new     CInternetSession(AfxGetAppName(),1,     PRE_CONFIG_INTERNET_ACCESS);     try     {         pFtpConnection=pInetSession->         GetFtpConnection("192.34.45.0");     }     catch(CInternetException *pEx)     {         pEx->Delete();         pFtpConnection=NULL;         *pnFileStatus=-1;         goto BallOut;     }     *pnFileStatus =1;     pFtpConnection->Remove("test.txt");     if(!pFtpConnection->PutFile     ("test.txt","test.txt"))     *pnFileStatus=-2;     else     *pnFileStatus=2;     BallOut:     if(pFtpConnection!=NULL)     {         pFtpConnection->Close();         delete pFtpConnection;     }     delete pInetSession;     AfxEndThread(0);     return false; } 

编辑ftpfwview.cpp中的OnDraw()函数

void CFtpfwView::OnDraw(CDC* pDC) {     CFtpfwDoc* pDoc = GetDocument();     ASSERT_VALID(pDoc);     if(!m_bConnectAttempted)     {         m_bConnectAttempted=TRUE;         AfxBeginThread((AFX_THREADPROC)         CFtpThread::PutFile,&m_nFileStatus);     } } 

编译并且执行程序,在连接和传输的过程中,应用程序仍然可以作自己的工作,这是因为传输的过程发生在线程中。
总结语
—- 通过以上的程序我们可以明白FTP的工作原理,我们可以编制自己的获得FTP服务器的文件以及获得FTP服务器的根目录,亲自体验一下我们的程序工作的怎末样。

Technorati Tags: CFtpConnection
// PhotoUploadDlg.cpp : implementation file
#include “stdafx.h”
#include “PhotoUpload.h”

include “afxinet.h”

include

ifdef _DEBUG

define new DEBUG_NEW

endif

// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
}; 31: 32: CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 33: { 34: } 35: 36: void CAboutDlg::DoDataExchange(CDataExchange* pDX) 37: { 38: CDialog::DoDataExchange(pDX); 39: } 40: 41: BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 42: END_MESSAGE_MAP() 43: 44: 45: // CPhotoUploadDlg dialog 46: 47: 48: 49: 50: CPhotoUploadDlg::CPhotoUploadDlg(CWnd* pParent /=NULL/) 51: : CDialog(CPhotoUploadDlg::IDD, pParent) 52: , m_strFileURL(_T(“”)) 53: { 54: m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 55: } 56: 57: void CPhotoUploadDlg::DoDataExchange(CDataExchange* pDX) 58: { 59: CDialog::DoDataExchange(pDX); 60: DDX_Text(pDX, IDC_EDIT1, m_strFileURL); 61: } 62: 63: BEGIN_MESSAGE_MAP(CPhotoUploadDlg, CDialog) 64: ON_WM_SYSCOMMAND() 65: ON_WM_PAINT() 66: ON_WM_QUERYDRAGICON() 67: //}}AFX_MSG_MAP 68: ON_BN_CLICKED(IDC_UPLOAD, &CPhotoUploadDlg::OnBnClickedUpload) 69: ON_BN_CLICKED(IDC_BUTTON1, &CPhotoUploadDlg::OnBnClickedButton1) 70: END_MESSAGE_MAP() 71: 72: 73: // CPhotoUploadDlg message handlers 74: 75: BOOL CPhotoUploadDlg::OnInitDialog() 76: { 77: CDialog::OnInitDialog(); 78: 79: // Add “About…” menu item to system menu. 80: 81: // IDM_ABOUTBOX must be in the system command range. 82: ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 83: ASSERT(IDM_ABOUTBOX < 0xF000); 84: 85: CMenu* pSysMenu = GetSystemMenu(FALSE); 86: if (pSysMenu != NULL) 87: { 88: CString strAboutMenu; 89: strAboutMenu.LoadString(IDS_ABOUTBOX); 90: if (!strAboutMenu.IsEmpty()) 91: { 92: pSysMenu->AppendMenu(MF_SEPARATOR); 93: pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 94: } 95: } 96: 97: // Set the icon for this dialog. The framework does this automatically 98: // when the application’s main window is not a dialog 99: SetIcon(m_hIcon, TRUE); // Set big icon 100: SetIcon(m_hIcon, FALSE); // Set small icon 101: 102: // TODO: Add extra initialization here 103: 104: return TRUE; // return TRUE unless you set the focus to a control 105: } 106: 107: void CPhotoUploadDlg::OnSysCommand(UINT nID, LPARAM lParam) 108: { 109: if ((nID & 0xFFF0) == IDM_ABOUTBOX) 110: { 111: CAboutDlg dlgAbout; 112: dlgAbout.DoModal(); 113: } 114: else 115: { 116: CDialog::OnSysCommand(nID, lParam); 117: } 118: } 119: 120: // If you add a minimize button to your dialog, you will need the code below 121: // to draw the icon. For MFC applications using the document/view model, 122: // this is automatically done for you by the framework. 123: 124: void CPhotoUploadDlg::OnPaint() 125: { 126: if (IsIconic()) 127: { 128: CPaintDC dc(this); // device context for painting 129: 130: SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); 131: 132: // Center icon in client rectangle 133: int cxIcon = GetSystemMetrics(SM_CXICON); 134: int cyIcon = GetSystemMetrics(SM_CYICON); 135: CRect rect; 136: GetClientRect(&rect); 137: int x = (rect.Width() - cxIcon + 1) / 2; 138: int y = (rect.Height() - cyIcon + 1) / 2; 139: 140: // Draw the icon 141: dc.DrawIcon(x, y, m_hIcon); 142: } 143: else 144: { 145: CDialog::OnPaint(); 146: } 147: } 148: 149: // The system calls this function to obtain the cursor to display while the user drags 150: // the minimized window. 151: HCURSOR CPhotoUploadDlg::OnQueryDragIcon() 152: { 153: return static_cast(m_hIcon); 154: } 155: 156: 157: void CPhotoUploadDlg::OnBnClickedUpload() 158: { 159: // TODO: Add your control notification handler code here 160: CInternetSession NetSession; 161: CFtpConnection* pFTP = NetSession.GetFtpConnection( _T(“ip address”), _T(“username”), _T(“n1u5s1p5”) , INTERNET_INVALID_PORT_NUMBER, TRUE); 162: //pFTP->GetFile() 163: if ( NULL != pFTP ) 164: { 165: pFTP->SetCurrentDirectory( _T(“BlogAttachments”) ); 166: 167: CString pathName; 168: // szFilters is a text string that includes two file name filters: 169: // “.my” for “MyType Files” and “.’ for “All Files.” 170: wchar_t szFilters[]= 171: _T(“Picture Files (.jpg)|.jpg|All Files (.)|.||”); 172: 173: // Create an Open dialog; the default file name extension is “.my”. 174: CFileDialog fileDlg (TRUE, _T(“Picture Files”), _T(“.jpg”), 175: OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, szFilters, this); 176: 177: // Display the file dialog. When user clicks OK, fileDlg.DoModal() 178: // returns IDOK. 179: if( fileDlg.DoModal () == IDOK ) 180: { 181: pathName = fileDlg.GetPathName(); 182: 183: 184: CString fileName = fileDlg.GetFileTitle (); 185: CString strNewName; 186: CTime t = CTime::GetCurrentTime(); 187: strNewName.Format( _T(“%d-%d-%d-%d-%d-%d.%s”), t.GetYear(),t.GetMonth(),t.GetDay(), 188: t.GetHour(),t.GetMinute(),t.GetSecond() , fileDlg.GetFileExt()); 189: int nResult = pFTP->PutFile( pathName, strNewName); 190: CString strURL = _T(“http://www.aboutvc.cn/BlogAttachments/“); 191: strURL += strNewName; 192: if ( nResult != 0 ) 193: { 194: m_strFileURL = strURL; 195: UpdateData( FALSE ); 196: } 197: } 198: } 199: } 200: 201: void CPhotoUploadDlg::OnBnClickedButton1() 202: { 203: HGLOBAL hglbCopy; 204: LPCTSTR lpstrCopy; 205: LPCTSTR lpszText = m_strFileURL.GetString(); 206: lpstrCopy;// = m_strFileURL.GetString(); 207: if (!OpenClipboard()) 208: return ; 209: EmptyClipboard(); 210: // Allocate a global memory object for the text. 211: hglbCopy = GlobalAlloc(GMEM_MOVEABLE, m_strFileURL.GetLength()+ 1); 212: if (hglbCopy == NULL) 213: { 214: CloseClipboard(); 215: return ; 216: } 217: lpstrCopy = (LPCTSTR)GlobalLock(hglbCopy); 218: 219: memcpy_s(lpstrCopy, lpszText, strlen(lpszText) + 1); 220: GlobalUnlock(hglbCopy); 221: // Place the handle on the clipboard. 222: SetClipboardData(CF_TEXT, hglbCopy); 223: CloseClipboard(); 224: // TODO: Add your control notification handler code here 225: }

下面是我写的下载和上传的线程,其中下载时无法改变服务器端的读文件指针,只是改变了本地文件指针,所以只有读前面已下部分时不写,这样可以提高一点速度,但还是不算断点续传.而上传就更难以实现了.

下面的程序可以运行,也可以实现ftp的基本功能.

UINT CFtpView::FileThread( LPVOID lpInf )
{
FTP_INFO lpInfo = (FTP_INFO ) lpInf;

CInternetSession *lpInetSession;
CFtpConnection *lpFtpConnection;

// Allocate a CInternetSession object.
lpInetSession = new CInternetSession(
lpInfo->szAppName, 1,
PRE_CONFIG_INTERNET_ACCESS );

// If the CInternetSession object didn’t
// allocate, bail out.
if( lpInetSession == NULL ){
delete lpInfo;
return( 0 );
}

// Attempt to make the Ftp connection.
try{

// We’ll use a NULL pointer for the
// user name since GetFtpConnection()
// will use a default value if it
// gets a NULL for it. If a user
// name was given by user, go ahead and
// point to that string.
char *lpUser = NULL;
if( lpInfo->szUser[0] != 0 )
lpUser = lpInfo->szUser;

// The same thing happens here for the
// password. Use a NULL pointer unless
// user gave a password.
char *lpPassword = NULL;
if( lpInfo->szPassword[0] != 0 )
lpPassword = lpInfo->szPassword;

lpFtpConnection =
lpInetSession->GetFtpConnection(
lpInfo->szHost, lpUser, lpPassword );
}

// If GetFtpConnection() throws an exception,
// catch it, clean up, and return.
catch( CInternetException *lpEx ){
lpEx->Delete();
delete lpInetSession;
delete lpInfo;
return( 0 );
}

try {
CInternetFile *pInternetFile;
CFile* pFile = NULL;
CFileFind finder;
BOOL bFile;
DWORD dwLocalFilelen;
DWORD dwFtpFilelen;

//seach localfile and see whether is exist
//and get it’s length
// start working for files
BOOL bWorking = finder.FindFile((CString)lpInfo->szLocalFile+”*”);
while (bWorking)
{
bWorking = finder.FindNextFile();
bFile = 1;
// skip . and .. files; otherwise, we’d
// recur infinitely!
if (finder.IsDots())
continue;
}
//if the file was exist,get the length
if( bFile ) {
pFile = new CFile(lpInfo->szLocalFile,
CFile::modeRead | CFile::shareDenyNone);
dwLocalFilelen = (DWORD)pFile->GetLength();
}
//if the file wasn’t exist,set the length zero;
else {
dwLocalFilelen = 0;
}
if (pFile != NULL) {
pFile->Close();
delete pFile;
}

//seach remote file and see whether is exist
//and get its length
CFtpFileFind *pFtpFind = new CFtpFileFind(lpFtpConnection);
BOOL res = pFtpFind->FindFile( (CString)lpInfo->szFtpFile+”*”);
if(res)
{
pFtpFind->FindNextFile();
CString strFilename = pFtpFind->GetFileName();
// if the file was exist,get the length
dwFtpFilelen = (DWORD)pFtpFind->GetLength();
}
//if the file wasn’t exist,set the length zero;
else {
dwFtpFilelen = 0;
}
if (pFtpFind != NULL) {
pFtpFind->Close();
delete pFtpFind;
}

CFile wrFile;
DWORD Percent;
DWORD dwStart;
DWORD dwEnd;
float Speed;
DWORD dwTotalReaded = 0;
DWORD dwReaded = 0;
char buffer[1024]; //存放文件数据的buffer
memset(buffer , 0 , 1024);
// Attempt to send the file from
// the local machine to the remote server.
if( lpInfo->bSendFlag ){
//check the remote file see whether it had already sent
if( dwFtpFilelen >= dwLocalFilelen) {
AfxMessageBox( “The file had already sent.” );
}
else {
//if it wasnit exist,send it
if(dwFtpFilelen == 0) {
lpFtpConnection->PutFile( lpInfo->szLocalFile,
lpInfo->szFtpFile );
dwFtpFilelen = dwLocalFilelen;
}

//if it existed but wasn't sent completly,continu sentelse {                   pInternetFile = lpFtpConnection->OpenFile( lpInfo->szFtpFile,GENERIC_WRITE ); CFile newFile(lpInfo->szLocalFile, CFile::modeRead|CFile::shareDenyNone);while(dwReaded = newFile.Read(buffer ,1024))//循环读取数据    {  dwTotalReaded += dwReaded;   pInternetFile->Write(buffer ,dwReaded);  Percent = ((float)dwTotalReaded / dwLocalFilelen)*100; }   newFile.Close( );}AfxMessageBox( "The file was sent." ); }  

}

// Attempt to retrieve the file from
// the remote server to the local machine.
else {
if( dwFtpFilelen <= dwLocalFilelen) {
AfxMessageBox( “The file had already retrieved.” );
}
else {
pInternetFile = lpFtpConnection->OpenFile( lpInfo->szFtpFile );
if( dwLocalFilelen == 0 )
wrFile.Open(lpInfo->szLocalFile, CFile::modeCreate|CFile::modeWrite | CFile::typeBinary|CFile::shareDenyNone);
else {
wrFile.Open(lpInfo->szLocalFile, CFile::modeWrite| CFile::typeBinary|CFile::shareDenyNone);
wrFile.Seek( (LONGLONG)dwLocalFilelen,CFile::begin);
}
while( dwStart = GetTickCount(),dwReaded = pInternetFile->Read(buffer ,1024))//循环读取数据
{
dwTotalReaded += dwReaded;
if( dwTotalReaded <= dwLocalFilelen )
Percent = ((float)dwLocalFilelen / dwFtpFilelen)*100;
else {
wrFile.Write(buffer ,dwReaded);
Percent = ((float)dwTotalReaded / dwFtpFilelen)*100;
}
dwEnd = GetTickCount();
Speed = (float)977/(dwStart - dwEnd);
}
AfxMessageBox( “The file was retrieved.” );
wrFile.Close( );
}
}
if(pInternetFile != NULL) {
pInternetFile->Close();
delete pInternetFile;
pInternetFile = NULL;
}
}
catch(CInternetException* e)
{
e->ReportError();
e->Delete();
return 0;
}

// Close the Ftp connection and delete
// the CFtpConnection and CInternetSession
//objects.
lpFtpConnection->Close();
delete lpFtpConnection;
delete lpInetSession;
delete lpInfo;

return( 0 );

}

0 0
原创粉丝点击