В этой главе будет написана программа, которая может считывать файлы из 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 сессии. |
Методы ( функции ) класса CFtpConnection
Функции |
Описание |
BOOL SetCurrentDirectory( LPCTSTR pstrDirName ) |
Устанавливает текущую FTP директорию. |
BOOL GetCurrentDirectory( CString& strDirName ) const |
Записывает в strDirName текущую FTP директорию . |
BOOL RemoveDirectory( LPCTSTR pstrDirName ) |
Удаляет директорию на сервере. |
BOOL CreateDirectory( LPCTSTR pstrDirName ) |
Создаёт директорию на сервере. |
BOOL Rename( LPCTSTR pstrExisting, LPCTSTR pstrNew ) |
Переименовывает файл на сервере. |
BOOL Remove( LPCTSTR pstrFileName ) |
Удаляет файл на сервере. |
BOOL PutFile( LPCTSTR pstrLocalFile, LPCTSTR pstrRemoteFile, DWORD dwFlags = FTP_TRANSFER_TYPE_BINARY, DWORD dwContext = 1 )
|
Кладёт локальный файл на сервер. |
BOOL GetFile( LPCTSTR pstrRemoteFile, LPCTSTR pstrLocalFile, BOOL bFailIfExists = TRUE, DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL, DWORD dwFlags = FTP_TRANSFER_TYPE_BINARY, DWORD dwContext = 1 )
|
Записывает файл с сервера на локальный диск. |
CInternetFile* OpenFile( LPCTSTR pstrFileName, DWORD dwAccess = GENERIC_READ, DWORD dwFlags = FTP_TRANSFER_TYPE_BINARY, DWORD dwContext = 1 )
|
Открывает файл по FTP протоколу. |
virtual void Close( ) |
Закрывает коннект с FTP сервером. |
Методы ( функции ) класса CFtpFileFind
Функции |
Описание |
virtual BOOL FindFile( LPCTSTR pstrName = NULL, DWORD dwFlags = INTERNET_FLAG_RELOAD )
|
Включает функцию поиска файла, если pstrName = NULL, то ишет все файлы(*.*) . |
virtual BOOL FindNextFile( )
|
Ишет следующий файл. До вызова этой функции должна быть вызвана ф-я FindFile() |
CString GetFileURL( ) const |
Возвращает URL найденного файла. |
CString GetFileName( VOID ) |
Возвращает имя файла. |
unsigned long GetLength( VOID ) const |
Возвращает длину файла. |
Далее напишем код программы и разберём каждую строчку:
...
#include "afxinet.h"
#define NUM 1000 // максимальное количество файлов
char *szColumn[2]; // будет две колонки
char *Files[NUM]; // имена файлов
char *Leng[NUM]; // размеры файлов
CString m_curDirectory; // текущая директория
unsigned long m_fileLengths[NUM]; // размеры файлов
int Sel_files[NUM]; // выделенные файлы
int m_numFiles; // номер файла
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();
}
Ну вот и всё, приложение готово.
Отсюда можно взять рабочую
программу FTP Client под MFC, с использованием WinInet.
|