ウェブサイトを構築するには、 通常は管理ツールを使用したり、FTP ソフトを利用したりしますが、 データファイルなどの管理のため、自分でサーバーにアクセスしたいことがあるかもしれません。
Windows で C++ プログラムから FTP サーバーへのアクセスが非常に簡単でしたので、 何に使うかわかりませんが、ここにコードを残しています。
自分で FTP ソフトを作成したりするよりは、 無料でも優れた FTP ソフトがすぐに見つかりますので、 どんな用途で利用できるか、思いついたら追記します。
ここにあるコードの開発環境は Windows 10 Pro、Visual C++ 2015、
なお、本サイトのご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
投稿 February 26, 2022
Visual Studio を起動して、Visual C++ にある MFC アプリケーションを作成します。 ここでは単純にテスト目的ですのでダイアログベース・アプリにしていますが、おそらく何でも問題ありません。
忘れてはいけないのは、「高度な機能」のページで、 「Windows ソケット」にチェックを入れることです。
新しいバージョンの Visual Studio では画面が異なるかもしれませんが、設定項目は同じだと思います。
ダイアログベースであれば、とりあえず IDOK ボタンのラベルを「接続」や「テスト」に書き換えて、 このボタン処理で FTP 接続機能を試します。
ちゃんとアプリにする場合は、UI や表示の工夫が必要ですが、ここでは扱いません。 例えばダイアログにドロップされたファイルをアップロードするような場合は、 「タイムスタンプを自由に変更する」の 「ダイアログでドロップファイルを受け入れる」セクション などを参考にしていただけます。
投稿 February 26, 2022
ここでは Visual C++ で
#include "afxinet.h"
IDOK ボタンのハンドラ OnBnClickedOk() に実装した順に記載します。
まず行うべきことは、WININET ライブラリを初期化するためにセッションオブジェクトを作成することです。 レジストリに記載のアクセスメソッドがデフォルトパラメータとして使用されるとされていますので、 つまり、コントロールパネルの "インターネット" アイコンからの設定値が使用されるようです。 詳しくは、 「CInternetSession クラス」 に記載されています。
CInternetSession sess(_T("My FTP Session"));
オブジェクト名は sess としていますが、もちろん何でも構いません。 引数としている「セッション名」も、何でも構いません。
続けて、FTP 接続を取得します。
CFtpConnection *pConnect = NULL; try { pConnect = sess.GetFtpConnection(_T("ftp.YourDomain.com"), _T("username"), _T("password"), 21, TRUE);
まず、途中でエラー(例外)が出たときのため、しばらくの処理を try でくくっています。
ftp ドメイン名やログインするためのユーザー名、パスワードなどは、 プロバイダやレンタルサーバーから提供されたもの、あるいは自前のものならその設定に従います。 21 はポート番号ですが、指定があればその値を使います。 事前に FTP ソフトで接続が確認できているのであれば、そこに記載した値を使えば間違いありません。
怖いので試しませんが、もしかすると(パスワード打ち間違いなどで)何度も接続に失敗すると、 アカウントがロックされたり、一定の時間、あるいは解除するまで接続できなくなったりするかもしれませんので、ご注意ください。
次のコードは確認用ですので、実際には不要です。
#if 1 CString str; pConnect->GetCurrentDirectoryAsURL(str); #endif
この場合、
ftp://ftp.YourDomain.com/
のような値が返されていました。
次のような呼び出しも試みました。
#if 1
pConnect->GetCurrentDirectory(str);
#endif
この場合、返されたのは / のみでした。
pConnect->SetCurrentDirectory(_T("WWW")); #if 1 pConnect->GetCurrentDirectory(str); #endif
私がテストしたサーバーの場合、WWW サブフォルダにデータがありますので、 カレントディレクトリを WWW にするため、SetCurrentDirectory 関数を呼び出しました。 すると、GetCurrentDirectory 関数では、 /WWW が返るようになりました。
カレントディレクトリにあるファイルを列挙してみます。
CFtpFileFind finder(pConnect); // ループを開始します。 BOOL bWorking = finder.FindFile(_T("*")); while (bWorking) { bWorking = finder.FindNextFile(); // finder.GetFileURL() では、"ftp://ftp.YourDomain.com/WWW" で終わってしまい、ファイル名が取れない // finder.GetFilePath() では、上記の場合、"/WWW" だけが返される // finder.GetFileName() で、ファイル名を取得できた if (finder.IsDirectory()) { str.Format(_T("[DIR] %s"), finder.GetFileName()); } else { str.Format(_T("[FILE] %s"), finder.GetFileName()); } // str を使って表示等を行います。 } }
try ブロックはここで終わります。
どこかでエラーとなった場合は、catch で取得します。
catch (CInternetException *pEx) { TCHAR sz[1024]; pEx->GetErrorMessage(sz, 1024); // sz を使って表示等を行います。 pEx->Delete(); }
ひとまず、ファイルの列挙ができましたので、終了します。
if (pConnect != NULL){ pConnect->Close(); delete pConnect; }
投稿 February 26, 2022
あるとわかっているファイルをダウンロードしたい場合、 上記と同じ手順で CFtpConnection へのポインタ pConnect を取得した後、 下記のように実行します。
if (pConnect->GetFile(_T("data.dat"), _T("C:\\data\\data.dat"))) { // data.dat を取得できました。 } else { // data.dat を取得できませんでした。 }
GetFile 関数の第 1 引数がネットワーク上のファイル名です。 サブフォルダにある場合は、事前に pConnect->SetCurrentDirectory 関数で移動しておきます。
第 2 引数はローカルのパスとファイル名です。 ファイル名を指定しているということは、ファイル名は変更可能である、ということになります。
呼び出し後は Close 関数を呼び忘れないようにします。
投稿 February 26, 2022
ローカルにあるファイルをアップロードしたい場合も、 まずは上記と同じ手順で CFtpConnection へのポインタ pConnect を取得します。 そのあと下記のように実行します。
if (pConnect->PutFile(_T("D:\\data\\data.png"), _T("data.png"), FTP_TRANSFER_TYPE_BINARY)) { // data.png をアップロードできました。 } else { // data.png をアップロードできませんでした。 }
PutFile 関数の引数は GetFile 関数とは逆に、 第 1 引数がローカルのパスとファイル名です。
第 2 引数はネットワーク上のファイル名です。 サブフォルダにコピーしたい場合は、事前に pConnect->SetCurrentDirectory 関数で移動しておきます。
呼び出し後は Close 関数を呼び忘れないようにします。
Windows 開発トップ
Windows 開発関連の情報を、書いています。
おすすめ記事はありません。