Создание простого FTP-клиента Ernest Avagyan
22. Создание простого FTP-клиента
В этой главе будет написана программа, которая может считывать файлы из Internet по FTP протоколу и записывать их на диск.
Для связи с Internet в Visual C++ существует так называемый WinInet Class. В него входят несколько подклассов.
Далее представлены ксассы WinInet:
Классы | Описание |
CInternetSession | Создаёт Internet сессию. Все MFC WinInet приложения должны создавать CInternetSession объект перед использрванием других WinInet классов. |
CInternetConnection | Создаёт коннект с Internet. Это базовый класс для классов CFtpConnection, CGopherConnection, и CHttpConnection. |
CFtpConnection | Устанавливает соединение по FTP протоколу. |
CGopherConnection | Создаёт Gopher коннект. |
CHttpConnection | Устанавливает соединение по HTTP протоколу. |
CInternetFile | Разрешает удалённый доступ к файлам на Internet серверах. Это базовый класс для классов CGopherFile and CHttpFile. |
CGopherFile | Разрешает удалённый доступ к файлам на Gopher серверах. |
CHttpFile | Разрешает удалённый доступ к файлам на HTTP серверах. |
CFileFind | Разрешает поиск файлов в Internet. Это базовый класс для классов CFtpFileFind and CGopherFileFind. |
CFtpFileFind | Разрешает поиск файлов на FTP серверах. |
CGopherFileFind | Разрешает поиск файлов на Gopher серверах. |
CGopherLocator | Отыскивает Gopher устройство ввода позиций от gopher сервера. |
CInternetException | Управляет исключениями, сгенерированными WinInet классом. |
Наша программа будет использовать три класса WinInet: CInternetSession, CFtpFileFind и CFtpConnection
Далее будут описаны методы( функции ) этих классов:
Методы ( функции ) класса CInternetSession
Функции | Описание |
Close() | Закрывает Internet сессию. |
EnableStatusCallback() | Разрешает использование функции повторного вызова, которая используется для асинхронных действий. |
GetContext() | Получает значение контекста Internet сессии. |
GetFtpConnection() | Устанавливает подключение по FTP протоколу. |
GetGopherConnection() | Устанавливает подключение с Gopher серверами. |
GetHttpConnection() | Устанавливает подключение по HTTP протоклолу. |
OnStatusCallback() | Модифицирует состояние операции. |
OpenURL() | Соединяется с данным URL. |
QueryOption() | Сервис проверки ошибки провайдера. |
ServiceTypeFromHandle() | Получает тип сервиса от Internet дескриптора. |
SetOption() | Устанавливает опции Internet сессии. |
INTERNET_PORT nPort = 21; // интернет порт CString temp; char *temp2; char temp3[100];
CInternetSession internetSession; // переменная класса CInternetSession CFtpConnection* ftpConnection; // переменная класса CFtpConnection BOOLEAN gotFile; BOOL ConnFlag = FALSE;
LV_ITEM lvi; // переменная для List Control
... m_url = _T(""); m_temp = _T(""); m_user = _T("anonymous"); m_pass = _T(""); m_edit = _T(""); m_save = _T("c:\\save_to\\"); ...
// TODO: Add extra initialization here
szColumn[0] = "File names:"; // имя первой колонки szColumn[1] = "Lenght:"; // имя второй колонки
// далее создаётся List Control с двумя колонками
LV_COLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT;
for (int j = 0; j < 2; j++) { if( j == 0 ) lvc.cx = 200; else lvc.cx = 80; lvc.pszText = szColumn[j]; if ((j == 1)) lvc.fmt = LVCFMT_RIGHT; lvc.iSubItem = j; m_ListView.InsertColumn(j, &lvc); }
// --------------------------------------------------------------------------------------- m_numFiles = 0;
m_url = "ftp://mark5.dhtp.kiae.ru/"; // URL для коннекта ..
// --------------------------------------------------------------------------------------- void CFTP_ClientDlg::OnButtonConnect() { // TODO: Add your control notification handler code here // вызываем ф-ю MyConnect BOOL flag = MyConnect( MyGetURL(m_url), MyGetPath(m_url) ); if( flag == FALSE ) return; MyPrintFiles(); // печатаем список файлов в List Control
} // --------------------------------------------------------------------------------------
// функция коннектится к URL : url с текущей директорий : path
BOOL CFTP_ClientDlg::MyConnect(CString url, CString path) { if( ConnFlag == TRUE ) MyEndConnect(); try { if( (m_user == "anonymous") || (m_user == "") ) ftpConnection = internetSession.GetFtpConnection(url, NULL, NULL, nPort, FALSE ); else ftpConnection = internetSession.GetFtpConnection(url, m_user, m_pass, nPort, FALSE );
ftpConnection->SetCurrentDirectory( path ); ConnFlag = TRUE; m_ListView.SetFocus(); return TRUE; } catch (CInternetException* pException) { // если была ошибка pException->ReportError(); return FALSE; } }
..
// --------------------------------------------------------------------------------------- Функция возвращает URL сервера, например, если было введено "ftp://www.site.ru/path/" , то будет возвращено "www.site.ru"
CString CFTP_ClientDlg::MyGetURL(CString url) {
char *pre = ""; char *first=""; char *ftp = "ftp://"; char sl = '/'; int len; CString null = "";
len = url.GetLength();
if( len <= 5 ) { for( int i = 0; i < len; i++ ) { if( char(url.GetAt(i)) != sl ) pre[i] = (char)url.GetAt( i ); else { pre[i] = 0; return (CString)&pre[0]; } } }
for( int i=0; i<6; i++ ) first[i] = (char)url.GetAt( i ); first[6] = 0;
if( (strcmp(first, ftp) == 0) && (len == 6) ) { return null; }
if( strcmp(first, ftp) == 0 ) { for( i = 6; i < len; i++ ) { if( char(url.GetAt(i)) != sl ) pre[i-6] = (char)url.GetAt( i ); else { pre[i-6] = 0; i = (len - 1); } } return (CString)&pre[0];
}
if( strcmp(first, ftp) == 1 ) { for( i = 0; i < len; i++ ) { if( char(url.GetAt(i)) != sl ) pre[i] = (char)url.GetAt( i ); else { pre[i] = 0; i = (len - 1); } } return (CString)&pre[0]; }
return null; } // ---------------------------------------------------------------------------------------
Функция возвращает PATH, например, если было введено "ftp://www.site.ru/path/" , то будет возвращено "/path/"
CString CFTP_ClientDlg::MyGetPath(CString url) { char *pre = ""; char *first=""; char *ftp = "ftp://"; char sl = '/'; CString null = ""; int len, num;
len = url.GetLength();
if( len <= 5 ) { num = -1; pre = ""; for( int i = 0; i < len; i++ ) if( char(url.GetAt(i)) == sl ) { num = i; i = len-1; } if( (char(url.GetAt(num+1)) == 0) || num < 0) { return CString("/"); }
for( i = (num); i < len; i++ ) pre[i-num] = (char)url.GetAt( i ); pre[len - num] = 0;
return (CString)&pre[0]; }
for( int i=0; i<6; i++ ) first[i] = (char)url.GetAt( i ); first[6] = 0;
if( (strcmp(first, ftp) == 0) && (len == 6) ) { MessageBeep(65535); return null; }
if( strcmp(first, ftp) == 0 ) { num = -1; pre = ""; for( int i = 6; i < len; i++ ) if( char(url.GetAt(i)) == sl ) { num = i; i = len-1; } if( (char(url.GetAt(num+1)) == 0) || num < 0) { return (CString)"/"; }
for( i = (num); i < len; i++ ) { pre[i-num] = (char)url.GetAt( i );}
pre[len-num] = 0;
return (CString)&pre[0]; }
if( strcmp(first, ftp) == 1 ) { num = -1; pre = ""; for( int i = 0; i < len; i++ ) if( char(url.GetAt(i)) == sl ) { num = i; i = len-1; } if( (char(url.GetAt(num+1)) == 0) || num < 0) { return (CString)"/"; }
for( i = (num); i < len; i++ ) pre[i-num] = (char)url.GetAt( i ); pre[len-num] = 0; return (CString)&pre[0]; }
return null; }
// --------------------------------------------------------------------------------------- // вукция выводит список файлов в List Control void CFTP_ClientDlg::MyPrintFiles() { MyEraseList(); // очистка
ftpConnection->GetCurrentDirectory(m_curDirectory); // в m_curDirectory записываем текущую директорию CFtpFileFind ftpFileFind(ftpConnection); // создаём переменную класса CFtpFileFind ftpFileFind.FindFile(); // ищем все файлы
m_temp = "Current directory = " + m_curDirectory ;
int x = 1; int len = 0; CTime tim;
lvi.mask = LVIF_TEXT | LVIF_IMAGE; lvi.iSubItem = 0;
Files[0] = ".."; Leng[0] = "-"; m_ListView.SetTextColor( RGB(150,0,0 ) ); lvi.iItem = 0; lvi.pszText = Files[0]; lvi.cchTextMax = 0; lvi.iImage = 0; m_ListView.InsertItem(&lvi);
m_ListView.SetItemText(0, 1, Leng[0]);
do { temp = ""; temp2 = ""; len=0;
gotFile = ftpFileFind.FindNextFile(); // ищем следующие файлы
temp = (CString)ftpFileFind.GetFileName(); // в temp заносится имя файла
len = temp.GetLength(); в len заносится длина файла for( int a = 0; a < len; a++ ) {temp2[a] = (char)temp.GetAt(a);} temp2[len] = 0; Files[x] = temp2;
if( ftpFileFind.IsDirectory() ) // проверка на директорию { Leng[x] = "< Dir >";
} else { itoa( (int)ftpFileFind.GetLength(), temp3, 10 ); Leng[x] = temp3;
}
lvi.iItem = x; lvi.pszText = Files[x]; lvi.cchTextMax = x; lvi.iImage = x; m_ListView.InsertItem(&lvi);
m_ListView.SetItemText(x, 1, Leng[x]); ++x;
}while ((x < NUM) && (gotFile)); // цикл пока не кончатся файлы
m_numFiles = x; m_ListView.SetFocus(); m_ListView.SetHotItem( 0 );
m_ListView.UpdateData( FALSE ); m_enter.EnableWindow( TRUE ); UpdateData( FALSE ); }
// --------------------------------------------------------------------------------------- // функция очистки List Control void CFTP_ClientDlg::MyEraseList() { for( int i = 0; i < m_numFiles; i++ ) { Leng[i]=""; Files[i]="";} m_ListView.DeleteAllItems();
m_numFiles = 0; UpdateData( FALSE ); }
// --------------------------------------------------------------------------------------- // функция окончания сеанса void CFTP_ClientDlg::MyEndConnect() { delete ftpConnection; ConnFlag = FALSE; }
// функция позволяет перемещаться по каталогам сервера void CFTP_ClientDlg::OnButtonEnter() { // TODO: Add your control notification handler code here POSITION pos; CString new_url, dir;
pos = m_ListView.GetFirstSelectedItemPosition();
(int)pos--; CString name = m_ListView.GetItemText( (int)pos, 0 ); CString len = m_ListView.GetItemText( (int)pos, 1 );
if( ((int)pos == 0) && (m_curDirectory != "/" ) ) { int slashPosition = m_curDirectory.ReverseFind('/'); dir = m_curDirectory.Left(slashPosition); m_curDirectory = dir; ConnFlag = TRUE;
BOOL flag = MyConnect( MyGetURL(m_url), m_curDirectory ); MyPrintFiles(); UpdateData( FALSE ); return; }
if( len == "< Dir >" ) { if( m_curDirectory == "/" ) {dir = m_curDirectory + name;} else { dir = m_curDirectory + '/' + name;}
m_curDirectory = dir; ConnFlag = TRUE;
BOOL flag = MyConnect( MyGetURL(m_url), m_curDirectory ); MyPrintFiles(); UpdateData( FALSE ); return; }
}
// функция копирует выделенные файлы в выбранную директорию void CFTP_ClientDlg::OnCopy() { // TODO: Add your control notification handler code here POSITION cur_pos; int flag_pos; int count=0; CString file,len; CString new_url, dir;
// здесь можно дописать создание директории если она не создана //char *d = "c:\\temp\\files\\a\\b\\"; //CreateDirectoryW( &d[0], NULL );
m_edit = ""; cur_pos = m_ListView.GetFirstSelectedItemPosition(); // первый выбранный файл
if( (int)cur_pos <= 1 ) { MessageBox( "Not write file(s)", "Error" ); return; };
len = m_ListView.GetItemText( (int)cur_pos-1, 1 ); if( len != "< Dir >" ) { Sel_files[ 0 ] = (int)cur_pos-1; count++;}
itoa( (int)cur_pos-1, temp3, 10 ); m_edit += "start = "; m_edit += &temp3[0]; m_edit += "\r\n"; do { flag_pos = m_ListView.GetNextSelectedItem( cur_pos ); // следующий файл itoa( (int)cur_pos-1, temp3, 10 ); m_edit += "next = "; m_edit += &temp3[0]; m_edit += "\r\n";
len = m_ListView.GetItemText( (int)cur_pos-1, 1 ); if( len != "< Dir >" ) { Sel_files[ count++ ] = (int)cur_pos-1; }
}while( (int)cur_pos >= 1 );
count--; itoa( count, temp3, 10 ); m_edit += " Selected files = "; m_edit += &temp3[0]; m_edit += "\r\n"; m_edit += "\r\n"; if( count == 0 ) { MessageBox( "No selected file(s)", "Error" ); return; };
for( int i = 0; i <= (count-1); i++ ) { len = m_ListView.GetItemText( Sel_files[i], 1 ); file = m_ListView.GetItemText( Sel_files[i], 0 );
m_edit += "Copy file = "; m_edit += file; m_edit += " len = "; m_edit += len; m_edit += "\r\n";
int down = ftpConnection->GetFile(file, m_save+file, FALSE); // копируем файлы
if( down == 0 ) { // если нет директории MessageBeep( 65535 ); m_edit += "Error save file.Not create directory !!!"; UpdateData( FALSE ); m_ListView.SetFocus(); return; }
}
UpdateData( FALSE );
m_ListView.SetFocus(); }
Ну вот и всё, приложение готово.
К списку