トップ回答者
ftp接続でファイルを連続でアップロードすると2回目以降エラー

質問
-
お世話になります。
下記のようにしてループでファイルをアップロードしようとすると2回目以降エラーになります。
1回目は、正しくアップロードされています。フォルダーもなければ作成されています。
2回目以降、失敗しているようですが問題点などわかりましたらご指摘ください。
また、環境情報が足らなければご指摘ください。長文で申し訳ありません。List<string> folders = new List<string>(); 28478・01_20190904.pdfのようなファイル名がある
string ftpFolder;freach(var txt in folders){
string[] dir = txt2[0].Split('_');
ftpFolder = dir[0]; // + '/' + dir[1]; 前半部分をフォルダーとして作成するif (ftp.FtpExistDirectory(ftpFolder) == false) <= 2回目のここでエラー
ftp.FtpMakeDirectory(ftpFolder);ftp.FtpUploadDupli(ftpFolder + '/' + txt, txt);
}2回目にftp.FtpExistDirectory(ftpFolder)を実行すると「リモート サーバーがエラーを返しました: 226 Transfer complete.」
※ using(FtpWebResponse ftpRes =GetResponse()・・・は、ググってる時にusingを使った方がいい!?というのを見かけたのでこうしてます。
ftp.cs
public bool FtpExistDirectory(string dir)
{
if (!FtpOpen(dir))
return false;ftpReq.Method = System.Net.WebRequestMethods.Ftp.ListDirectory;
try
{
2回目以降、ここでスローされる
using (System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse()) { }
}
catch (WebException e)
{
if (e.Status == WebExceptionStatus.ProtocolError)
{
FtpWebResponse r = (FtpWebResponse)e.Response;
if (r.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
{
return false;
}
}ftpRes.Close();
throw; // ファイル関連以外の例外は再スロー
}
finally
{
}
return true;
}
internal void FtpMakeDirectory(string txt)
{
if (!FtpOpen(txt))
return;ftpReq.KeepAlive = false;
//PASSIVEモードを無効にする
ftpReq.UsePassive = false;//MethodにWebRequestMethods.Ftp.DeleteFile(DELE)を設定
ftpReq.Method = System.Net.WebRequestMethods.Ftp.MakeDirectory;//FtpWebResponseを取得
System.Net.FtpWebResponse ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse();
ftpRes.Close();
}
public void FtpUploadDupli(string mei, string fulPath = "")
{
if (!FtpOpen(mei))
return;try
{
// MethodにWebRequestMethods.Ftp.UploadFile("STOR")を設定
ftpReq.Method = System.Net.WebRequestMethods.Ftp.UploadFile; // UploadFileWithUniqueName;
// 要求の完了後に接続を閉じる
ftpReq.KeepAlive = false;
// ASCIIモードで転送する
ftpReq.UseBinary = false;
// PASVモードにする
ftpReq.UsePassive = true;ftpReq.Proxy = null;
using (ftpRes = (System.Net.FtpWebResponse)ftpReq.GetResponse())
{
//ファイルをアップロードするためのStreamを取得
System.IO.Stream reqStrm = ftpReq.GetRequestStream();長くなるので割愛
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
ftpReq.Abort();
}
}
private bool FtpOpen(string mei = "")
{
if (adr.Length == 0)
{
MessageBox.Show("Uri名が指定されていません", "確認", MessageBoxButtons.OK, MessageBoxIcon.Question);
return false;
}
if (usr.Length == 0 || pwl.Length == 0)
{
MessageBox.Show("ユーザー名かパスワードがセットされていません", "確認", MessageBoxButtons.OK, MessageBoxIcon.Question);
return false;
}char xhk = adr[adr.Length - 1];
if (xhk != '/')
adr += "/"; // '/';Uri u = new Uri(adr + mei);
//FtpWebRequestの作成
ftpReq = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(u);//ログインユーザー名とパスワードを設定
ftpReq.Credentials = new System.Net.NetworkCredential(usr, pwl);return true;
}System.Net.FtpWebRequest ftpReq = null;
System.Net.FtpWebResponse ftpRes = null;
Uri uri = null;public string adr = "ftp://www.xxxxxx.com/abc/pdf"; こんな感じ
public string usr = "ユーザー名";
public string pwl = "パスワード";開発環境 Windows10 VS2015 C# WinForm
アップロード先 レンタルサーバー(Windows Server 2016 Datacenter) OSビルド 1607
回答
-
補足すると、
FTPサーバーとのTCPコネクションは、FtpWebRequestオブジェクトが保持・管理しているわけではありません。FtpWebRequest.ServicePointに設定されているServicePointオブジェクトであり、ServicePointManagerクラスが管理しています。
# なので、FtpWebRequestはIDisposableとなっていません。ですので、FtpWebRequestは毎回作成し、インスタンスは使い捨ててください。
- 回答としてマーク ferret001 2019年10月16日 4:44
すべての返信
-
補足すると、
FTPサーバーとのTCPコネクションは、FtpWebRequestオブジェクトが保持・管理しているわけではありません。FtpWebRequest.ServicePointに設定されているServicePointオブジェクトであり、ServicePointManagerクラスが管理しています。
# なので、FtpWebRequestはIDisposableとなっていません。ですので、FtpWebRequestは毎回作成し、インスタンスは使い捨ててください。
- 回答としてマーク ferret001 2019年10月16日 4:44
-
お世話になります。
> ですので、FtpWebRequestは毎回作成し、インスタンスは使い捨ててください
毎回作成するとのことですので、ループ内でインスタンスを作成するようにしましたが、依然同じところで同じエラーになります。
下記では毎回作成していることにならないのでしょうか?
foreach (var txt in zipF)
{
if (txt.Length > 0)
{
Ftp ftp = new Ftp();
ftp.adr = Form1._form1Instance.FtpServer;
ftp.usr = Form1._form1Instance.FtpUser;
ftp.pwl = Form1._form1Instance.FtpPassword; -
結論から言って連続でアップロードできるようになりました。
接続できない理由はうまく説明できませんが、
ftpReq.KeepAlive = false; を true に変更することで連続のアップロードが可能になりました。
もう一つエラーが吐かれたときに意味が分からず、
catch (WebException ex)
{
FtpWebResponse res = (FtpWebResponse)ex.Response;
string txt = res.StatusDescription; // 550 The system cannot find the path specified.
MessageBox.Show(ex.Message);
}とした方が、メッセージがより分かりやすいことも
ありがとうございました。
-
相対パスと絶対パスの違いは理解されていますでしょうか? FTPに接続し、PWDコマンドで返される初期パス(仮に /xxx とします。)、URIが "ftp://www.example.com/abc/pdf" とした場合、絶対パスは /xxx/abc/pdf となります。これをURIで表すには "ftp://www.example.com/%2Fxxx/abc/pdf" と記述する必要があります。
逆に相対パスのままですと、2回目の接続時に /xxx/abc/pdf/abc/pdf にアクセスしてしまう場合があり、「550 The system cannot find the path specified.」が発生してもおかしくありません。
- 編集済み 佐祐理 2019年10月16日 8:08 コマンド誤りを修正