DOBON.NET DOBON.NETプログラミング掲示板過去ログ

FTPサーバーからのファイルのダウンロードについて

環境/言語:[XP VB.2008]
分類:[.NET]

いつもこちらのページのお世話になっておりますVB.NET初心者です。

プログラム作成にて問題があり投稿致しました。

目的
あるFTPサーバーに保存されたデータから、決まったファイル名(例***ABC.CSV)
の最新版をダウンロードしたいと思っています。

こちらのサンプルコードを参考にサーバーへの接続及びFtpWebRequestの
Listコマンドを使用しての一覧の取得までは出来たのですが、そこで
躓いてしまいました。

初心者のため状況説明に足りない点もあるかもしれませんが、
どうかご教授お願いします。
■No26108に返信(マメオさんの記事)
> こちらのサンプルコードを参考にサーバーへの接続及びFtpWebRequestの
> Listコマンドを使用しての一覧の取得までは出来たのですが、そこで
> 躓いてしまいました。

取得した後、何に躓いているのでしょうか?

・エラーが出てしまうなら、どのようなコードを書いたときに
 どの部分でどのようなエラーが出るのかを書いてみてください。
・どのようなコードを書けば良いのかわからないのであれば、
 現在、具体的にどういったコードを書いていて、そこに対して
 どういった機能を実装しようとしているのかを教えてください。
・エラーが出るわけではないが、期待した動作と違うようであれば、
 問題のコードと、そこに期待する結果、そして実際の動作結果を
 それぞれ記述してみてください。
お世話になります。
返信ありがとうございました。

現在の状況ですが、こちらのサンプルコード 「http://dobon.net/vb/dotnet/internet/ftpwebrequest.html#listdirectory」
 を参考に

'----------------------------------------------

'ファイル一覧を取得するディレクトリのURI
Dim u As New Uri("指定したアドレス")

'FtpWebRequestの作成
Dim ftpReq As System.Net.FtpWebRequest = _
CType(System.Net.WebRequest.Create(u), System.Net.FtpWebRequest)
'ログインユーザー名とパスワードを設定
ftpReq.Credentials = New System.Net.NetworkCredential("***", "***")
'MethodにWebRequestMethods.Ftp.ListDirectoryDetails("LIST")を設定
ftpReq.Method = System.Net.WebRequestMethods.Ftp.ListDirectoryDetails
'要求の完了後に接続を閉じる
ftpReq.KeepAlive = False
'PASSIVEモードを無効にする
ftpReq.UsePassive = False

'FtpWebResponseを取得
Dim ftpRes As System.Net.FtpWebResponse = _
CType(ftpReq.GetResponse(), System.Net.FtpWebResponse)
'FTPサーバーから送信されたデータを取得
Dim sr As New System.IO.StreamReader(ftpRes.GetResponseStream())
Dim res As String = sr.ReadToEnd()
'ファイル一覧を表示
Console.WriteLine(res)
sr.Close()

'FTPサーバーから送信されたステータスを表示
Console.WriteLine("{0}: {1}", ftpRes.StatusCode, ftpRes.StatusDescription)
'閉じる
ftpRes.Close()

'-----------------------------------------------

で、内容の確認まではできました。
この一覧から最新の「***.ABC.CSV」だけを選択してダウンロードしたいのですが
そのファイル抽出のコードが分からず悩んでいます。

今の所、エラーは発生していません。

どうか宜しくお願いします。
■No26110に返信(マメオさんの記事)
> で、内容の確認まではできました。
> この一覧から最新の「***.ABC.CSV」だけを選択してダウンロードしたいのですが
> そのファイル抽出のコードが分からず悩んでいます。

Dim res As String = sr.ReadToEnd()
とすると、改行文字も含めてres変数に格納されます。
表示するだけなら問題ないですが、ファイルの中身を検索するなら
改行文字で分割して、tests配列に格納させるとかね。
Dim tests() As String = Split(res, vbCrLf)

あとは、配列から目的のファイル名を探索して、ダウンロードさせれば…
ファイルのダウンロードの方法は、先頭にありますよね。
「http://dobon.net/vb/dotnet/internet/ftpwebrequest.html」
■No26110に返信(マメオさんの記事)
> この一覧から最新の「***.ABC.CSV」だけを選択してダウンロードしたいのですが

最新のファイルの取得方法が解らない?
コードを試してないからどの様な結果が返ってくるか不明ですけど、
ファイル作成日時で比較すればOKだと思いますけど。
■No26112に返信(ヴァンさんの記事)

やじゅさん、ヴァンさん回答ありがとうございます。
参考にしてがんばってみます。

詳細はもう一度連絡します。
■No26112に返信(ヴァンさんの記事)

お世話になります。
すいません、やはり皆様の知恵を貸してください。

出力結果です↓↓

----------------------------------------------------------------------
-rwxrwxrwx 1 0 0 36768 Sep 15 10:35 081217_***.csv
-rwxrwxrwx 1 0 0 625651 Oct 07 2008 ***.aaa.CSV
-rwxrwxrwx 1 0 0 182030 Oct 07 2008 ***.ABC.CSV
-rwxrwxrwx 1 0 0 2708 Oct 07 2008 ***.aaa.CSV
-rwxrwxrwx 1 0 0 588627 Oct 07 2008 ***.aaa.CSV
-rwxrwxrwx 1 0 0 175894 Oct 07 2008 ***.ABC.CSV
-rwxrwxrwx 1 0 0 2711 Oct 07 2008 ***.aaa.CSV
----------------------------------------------------------------------

ファイル一覧のほんの一部ですが、この中から最新の「***.ABC.CSV」だけを
抽出しダウンロードできればと考えています。

宜しくお願い致します。
■No26114に返信(マメオさんの記事)
FTP サーバーから返される一覧の内容は、サーバーに依存しています。
そのため、汎用的なコードを記述する事は非常に大変です。

たとえば、当日分であれば年表示を省略するサーバー、
当日分以外は、時刻部を出力しないサーバー、
当日分だと日付部を出力しないサーバー、
時刻を24時間表記で出力するサーバー、
時刻を12時間表記し、午後帯には末尾にPの文字を付けるサーバー、
10時より前の時刻の場合、時刻部を1桁で表示するサーバー、
10時より前の時刻の場合、時刻部を先頭ゼロ埋め2桁で表示するサーバー、
10時より前の時刻の場合、時刻部を先頭空白埋め2桁で表示するサーバー、
日付にタイムゾーンを用いて表示するサーバーなどなどなど。


> 出力結果です↓↓
解析対象をこのサーバーに限定して良いのであれば、
たとえばこんな感じでしょうか。

細かい表記仕様が分からないので、解析処理の部分は適宜補ってみてください。


'テストデータ。実際にはFTPサーバーから取得される文字列。
Dim ftpResult As String = <![CDATA[-rwxrwxrwx    1 0        0           36768 Sep 15 10:35 081217_***.csv
-rwxrwxrwx    1 0        0          625651 Oct 07  2008 ***.aaa.CSV
-rwxrwxrwx    1 0        0          182030 Oct 07  2008 ***.ABC.CSV
-rwxrwxrwx    1 0        0            2708 Oct 07  2008 ***.aaa.CSV
-rwxrwxrwx    1 0        0          588627 Oct 07  2008 ***.aaa.CSV
-rwxrwxrwx    1 0        0          175894 Oct 07  2008 ***.ABC.CSV
-rwxrwxrwx    1 0        0            2711 Oct 07  2008 ***.aaa.CSV]]>.Value

'サーバー側の改行コードが分からないので、一度 vbNewLine 揃えておく。
ftpResult = Replace(ftpResult, vbCrLf, vbLf).Replace(vbCr, vbLf).Replace(vbLf, vbNewLine)

'行単位に置換
Dim lines() As String = Split(ftpResult, vbNewLine)

'予期される日付形式
Dim datePattern() As String = {"MMM dd  yyyy", "MMM dd hh:mm", "MMM dd h:mm", "MMM dd  h:mm"}
Dim ci = System.Globalization.CultureInfo.InvariantCulture
Dim dts = System.Globalization.DateTimeStyles.None

'ファイル名と日付部だけ取りだす
Dim q = From line In Array.ConvertAll(lines, Function(s) Mid(s, 44)) _
        Select line, pos = InStrRev(line, " ") _
        Select Name = Mid(line, pos + 1), [Date] = _
        Date.ParseExact(Left(line, pos - 1), datePattern, ci, dts)

'取りだした一覧から、最大日付のファイル名を選ぶ
Dim lastUpdatedFile As String = If(q.Count = 0, Nothing, q.OrderBy(Function(x) x.Date).First().Name)

Console.WriteLine(lastUpdatedFile)
■No26114に返信(マメオさんの記事)
> ■No26112に返信(ヴァンさんの記事)
>
> お世話になります。
> すいません、やはり皆様の知恵を貸してください。
>
> 出力結果です↓↓
>
> ----------------------------------------------------------------------
> -rwxrwxrwx 1 0 0 36768 Sep 15 10:35 081217_***.csv
> -rwxrwxrwx 1 0 0 625651 Oct 07 2008 ***.aaa.CSV
> -rwxrwxrwx 1 0 0 182030 Oct 07 2008 ***.ABC.CSV
> -rwxrwxrwx 1 0 0 2708 Oct 07 2008 ***.aaa.CSV
> -rwxrwxrwx 1 0 0 588627 Oct 07 2008 ***.aaa.CSV
> -rwxrwxrwx 1 0 0 175894 Oct 07 2008 ***.ABC.CSV
> -rwxrwxrwx 1 0 0 2711 Oct 07 2008 ***.aaa.CSV
> ----------------------------------------------------------------------
>
> ファイル一覧のほんの一部ですが、この中から最新の「***.ABC.CSV」だけを
> 抽出しダウンロードできればと考えています。
>
> 宜しくお願い致します。

この出力結果から日時とファイル名を切り出せば良いと思いますが。
切り出し方法は色々あると思います。
…もしかしたら、質問の意図を読み違えていたかも。

■No26114に返信(マメオさんの記事)
> ----------------------------------------------------------------------
> -rwxrwxrwx    1 0        0           36768 Sep 15 10:35 081217_***.csv
> -rwxrwxrwx    1 0        0          625651 Oct 07  2008 ***.aaa.CSV
> -rwxrwxrwx    1 0        0          182030 Oct 07  2008 ***.ABC.CSV
> -rwxrwxrwx    1 0        0            2708 Oct 07  2008 ***.aaa.CSV
> -rwxrwxrwx    1 0        0          588627 Oct 07  2008 ***.aaa.CSV
> -rwxrwxrwx    1 0        0          175894 Oct 07  2008 ***.ABC.CSV
> -rwxrwxrwx    1 0        0            2711 Oct 07  2008 ***.aaa.CSV
> ----------------------------------------------------------------------
> ファイル一覧のほんの一部ですが、この中から最新の「***.ABC.CSV」だけを
> 抽出しダウンロードできればと考えています。

見たところ、「***.ABC.CSV」が複数ありますね。

で、『最新』を抽出したいとの事ですが、提示された結果を見る限り、
081217_***.csv のみが "????/09/15 10:35:??" となっていて、その他の
***.ABC.CSV (等)は全て"2008/10/07 ??:??:??" となっていますよね。

時刻部が不足しているこの結果から、[***.aaa.CSV] と [***.ABC.CSV] のうち、
どちらがより新しいかを見分ける事は不可能と言えるかと思います。

ただし、その一覧が "LIST" (ListDirectoryDetails) コマンドで得た物なら、
さらにそのファイル名を用いて、"MDTM" (GetDateTimestamp) コマンドを
再発行することで、個々のファイルの更新日時を得られる可能性があります。
(サーバー側の対応も必要なので保証はできかねますが)


もし、MDTM でも取得できない場合には、そもそもその FTP サーバーが、
日時をより正確に取得するコマンドを実装していないかどうかを
管理者に問い合わせてみてください。
(そもそもサーバーが実装していないのであれば、今回の件は実現は不可能です)

なお、日付を正しく取得するコマンドが WebRequestMethods.Ftp に定義されて
いない場合には、FtpWebRequest 以外の方法に切り替える必要が生じます。
■No26117に返信(魔界の仮面弁士さんの記事)

返信有難うございます。

支援を糧に明日以降になりますが挑戦します。

結果はまた連絡します。
2009/12/26(Sat) 00:13:39 編集(投稿者)

■No26115に返信(魔界の仮面弁士さんの記事)

参考にさせて頂きましたが「Left」の部分でエラーが発生しました。

               ↓↓ 変更点(サンプルではなく)
>
> Dim ftpResult As String = sr.ReadToEnd()

> 'サーバー側の改行コードが分からないので、一度 vbNewLine 揃えておく。
> ftpResult = Replace(ftpResult, vbCrLf, vbLf).Replace(vbCr, vbLf).Replace(vbLf, vbNewLine)
>
> '行単位に置換
> Dim lines() As String = Split(ftpResult, vbNewLine)
>
> '予期される日付形式
> Dim datePattern() As String = {"MMM dd yyyy", "MMM dd hh:mm", "MMM dd h:mm", "MMM dd h:mm"}
> Dim ci = System.Globalization.CultureInfo.InvariantCulture
> Dim dts = System.Globalization.DateTimeStyles.None
>
> 'ファイル名と日付部だけ取りだす
> Dim q = From line In Array.ConvertAll(lines, Function(s) Mid(s, 44)) _
> Select line, pos = InStrRev(line, " ") _
> Select Name = Mid(line, pos + 1), [Date] = _
> Date.ParseExact(Left(line, pos - 1), datePattern, ci, dts)
>
             ↑↑ Leftについて
             'Public Property Left() As Integer' には
             引数がないため、戻り値の型をインデックス化
             できません。


> '取りだした一覧から、最大日付のファイル名を選ぶ
> Dim lastUpdatedFile As String = If(q.Count = 0, Nothing, q.OrderBy(Function(x) x.Date).First().Name)
>
> Console.WriteLine(lastUpdatedFile)

とても初歩的な質問かもしれませんが対応方法はありますでしょか?
宜しくお願いします。
>> Date.ParseExact(Left(line, pos - 1), datePattern, ci, dts)
> >
>              ↑↑ Leftについて
>              'Public Property Left() As Integer' には
>              引数がないため、戻り値の型をインデックス化
>              できません。

例えばこのコードがフォームに書かれていたとすれば、「Left」はそのフォームのLeftプロパティということになってしまいますので、「Left」を「Microsoft.VisualBasic.Left」と記述してください。詳しくはMSDNで「Left関数」を調べてみてください。

もしくはString.Substringを使って、「line.Substring(0, pos - 1)」としてください。
挑戦してみましたが、下記例外が発生しました。

【'System.FormatException' の初回例外が mscorlib.dll で発生しました。】

これまでの状況からこちらのサーバー時間標記の問題の様な気がします。
今回は長くなりましたので、この辺で一度解決としたいと思います。

また改めて相談させて頂こうとは考えておりますが
もし、良い方法をご存じであればご教授ください。

宜しくお願いします。
■No26213に返信(マメオさんの記事)

すいませんチェックを忘れていました。
解決済み!
解決していないのであれば、解決済みにしないでください。これは、「書き込みのルールについて」に書いてありますので、ご確認ください。

また、半角カナは使用しないでください。これは投稿フォームの上の説明に書いてあります。

> 【'System.FormatException' の初回例外が mscorlib.dll で発生しました。】

どのような文字列を変換しようとしたときに例外がスローされるでしょうか?
ありがとうございます。
改めて宜しくお願いします。

現在の状況です↓

'予期される日付形式
Dim datePattern() As String = {"mmm dd yyyy", "mmm dd hh:mm", "mmm dd hh:mm", "mmm dd yyyy"}
Dim ci = System.Globalization.CultureInfo.InvariantCulture
Dim dts = System.Globalization.DateTimeStyles.None

'ファイル名と日付部だけ取りだす
Dim q = From line In Array.ConvertAll(lines, Function(s) Mid(s, 44)) _
Select line, pos = InStrRev(line, " ") _
Select Name = Mid(line, pos + 1), [Date] = _
Date.ParseExact(Microsoft.VisualBasic.Left(line, pos - 1), datePattern, ci, dts)

'取りだした一覧から、最大日付のファイル名を選ぶ
Dim lastUpdatedFile As String = If(q.Count = 0, Nothing, q.OrderBy(Function(x) x.Date).First().Name)

↑↑上記の部分で「文字列は有効な DateTime ではありませんでした。」と、なります。

日付の取り出し方に問題があるのでしょうか?

宜しくお願いします。
ParseExactメソッドでエラーが発生していると思うのですが、具体的にどのような文字列をParseExactメソッドでDateTimeに変換しようとしたときにエラーが発生するのでしょうか?
お世話になります。

出力結果を整理してみました。↓↓

--------------------------------------------------------------------
-rwxrwxrwx 1 0 0 36768 Sep 15 10:35 ***.aaa.CSV
-rwxrwxrwx 1 0 0 2708 Oct 07 2008 ***.aaa.CSV
-rw-r--r-- 1 502 503 51873 Sep 15 10:35 ***.aaa.CSV
-rwxrwxrwx 1 0 0 2797 Feb 06 2009 ***.aaa.CSV
-rw-r--r-- 1 502 503 471593 Feb 19 2009 ***.aaa.CSV

-rw-r--r-- 1 502 503 143957 May 18 2009 ***.ABC.CSV
-rw-r--r-- 1 502 503 49027 Sep 03 21:22 ***.aaa.CSV

-rw-r--r-- 1 502 503 183830 Sep 03 21:22 ***.ABC.CSV
-rw-r--r-- 1 505 506 70188 Dec 03 07:36 ***.aaa.CSV

-rw-r--r-- 1 505 506 207747 Dec 03 07:36 ***.ABC.CSV
-rw-r--r-- 1 505 506 3355 Jan 08 21:20 ***.aaa.CSV
-rwxrwxrwx 1 0 0 109315 Oct 22 2008 ***.aaa.CSV
-rwxrwxrwx 1 0 0 2807 Feb 01 2009 ***.aaa.CSV
-rw-r--r-- 1 502 503 53601 Feb 13 2009 ***.aaa.CSV
-rw-r--r-- 1 505 506 3351 Nov 18 17:34 ***.aaa.CSV
drwxrwxrwx 2 0 0 69632 Jan 08 21:20 edp

ClosingData: 226 Directory send OK.
--------------------------------------------------------------------

この中から最新の「***.ABC.CSV」の抽出したいところです。
調べたところ古いファイルは西暦があり、新しいものには時間が入っていました。

宜しくお願いします。
■No26219に返信(マメオさんの記事)
> 出力結果を整理してみました。↓↓

ファイル情報は、先頭が "-" で始まる行ですよね。
それ以外の行(ディレクトリ情報、空行、最終行)を除去する必要がありそうです。

そして、日付書式の見直しも必要です。
今回の場合、24時間表記なので、予期される日付形式は
"MMM dd  yyyy" と "MMM dd HH:mm" だけで良いでしょう。

以上 2 点を直せば、動作すると思います。


'%WINDIR%\Microsoft.NET\Framework\v3.5\VBC.EXE /out:sample.exe sample.vb
Imports System
Imports System.Globalization
Imports Microsoft.VisualBasic
Module Test
Sub Main()

'FTPサーバーから取得される文字列
Dim ftpResult As String = <![CDATA[-rwxrwxrwx    1 0        0           36768 Sep 15 10:35 ***.aaa.CSV
-rwxrwxrwx    1 0        0            2708 Oct 07  2008 ***.aaa.CSV
-rw-r--r--    1 502      503         51873 Sep 15 10:35 ***.aaa.CSV
-rwxrwxrwx    1 0        0            2797 Feb 06  2009 ***.aaa.CSV
-rw-r--r--    1 502      503        471593 Feb 19  2009 ***.aaa.CSV

-rw-r--r--    1 502      503        143957 May 18  2009 ***.ABC.CSV
-rw-r--r--    1 502      503         49027 Sep 03 21:22 ***.aaa.CSV

-rw-r--r--    1 502      503        183830 Sep 03 21:22 ***.ABC.CSV
-rw-r--r--    1 505      506         70188 Dec 03 07:36 ***.aaa.CSV

-rw-r--r--    1 505      506        207747 Dec 03 07:36 ***.ABC.CSV
-rw-r--r--    1 505      506          3355 Jan 08 21:20 ***.aaa.CSV
-rwxrwxrwx    1 0        0          109315 Oct 22  2008 ***.aaa.CSV
-rwxrwxrwx    1 0        0            2807 Feb 01  2009 ***.aaa.CSV
-rw-r--r--    1 502      503         53601 Feb 13  2009 ***.aaa.CSV
-rw-r--r--    1 505      506          3351 Nov 18 17:34 ***.aaa.CSV
drwxrwxrwx    2 0        0           69632 Jan 08 21:20 edp]]>.Value

'改行コードを vbCrLf に揃える
ftpResult = Replace(ftpResult, vbCrLf, vbLf).Replace(vbCr, vbLf).Replace(vbLf, vbCrLf)

'空行を削除
ftpResult = ftpResult.Replace(vbLf & vbCr, "")

'行単位に置換
Dim lines() As String = Split(ftpResult, vbNewLine)

'予期される日付形式
Dim datePattern() As String = {"MMM dd  yyyy", "MMM dd HH:mm"}
Dim ci = CultureInfo.InvariantCulture
Dim dts = DateTimeStyles.None


'ファイル名と日付部だけ取りだす
Dim q = From line In Array.ConvertAll(lines, Function(s) Mid(s, 44)) _
        Select line, pos = InStrRev(line, " ") _
        Select Name = Mid(line, pos + 1), [Date] = _
        Date.ParseExact(line.Substring(0, pos - 1), datePattern, ci, dts)


'取りだした一覧から、最大日付のファイル名を選ぶ
Dim lastUpdatedFile As String = If(q.Count = 0, Nothing, q.OrderBy(Function(x) x.Date).First().Name)

Console.WriteLine(lastUpdatedFile)

End Sub
End Module
ありがとうございます。
試してみたところ下記のエラーが発生しました。

■No26220に返信(魔界の仮面弁士さんの記事)
> '取りだした一覧から、最大日付のファイル名を選ぶ
> Dim lastUpdatedFile As String = If(q.Count = 0, Nothing, q.OrderBy(Function(x) x.Date).First().Name)
>
↑↑この部分で
「ArgumentOutOfRangeExceptionはハンドルされませんでした。」
「長さを 0 未満にすることはできません。 パラメータ名: length」

サーバーからの取得情報に例で示したもの以外があったのでしょうか?
代表的なものを抜粋して記載したので・・・。

こちらの問題であれば確認します。

宜しくお願いします。
■No26221に返信(マメオさんの記事)

> サーバーからの取得情報に例で示したもの以外があったのでしょうか?

ファイル一覧の文字列の中に ClosingData: 226 Directory send OK. の文字
列が含まれてしまっているのではないでしょうか。
ただの予想です。
本題はこちらです。LINQ を利用しているところで例外が発生しています。そ
してエラーメッセージは引数がおかしいですよーといった意味ですが、どこの
引数なのかまでは特定できません。問題解決のためには LINQ で行う処理のど
こで例外が発生するのか、さらに絞り込む必要があります。
LINQ で行われる処理を分解して、例外が発生する処理の特定と、そのときの
行文字列がどのようなものか確認してみてはいかがでしょうか。
原因が明確になれば、新たに日付形式を追加したりといった具体的な対策を考
えることが出来ます。

Sub Main()
    
    ...省略...
    
    '予期される日付形式
    Dim datePattern() As String = {"MMM dd  yyyy", "MMM dd HH:mm"}
    Dim ci = CultureInfo.InvariantCulture
    Dim dts = DateTimeStyles.None
        
    ' 各行の44文字以降を切り出す処理
    Dim convertedLines = Array.ConvertAll(lines, Function(x) Mid(x, 44))
    
    For Each convertedLine In convertedLines
        ' 文字列から空白の位置を探す処理
        Dim position = InStrRev(convertedLine, " ")
    
        ' 文字列からファイル名を切り出す処理
        Dim fileName = convertedLine.Substring(position + 1)
    
        ' 文字列からファイルの日付を切り出す処理
        Dim fileDateString = convertedLine.Substring(0, position - 1)
    
        ' 日付を DateTime 型に変換する処理
        Dim fileDate = DateTime.ParseExact(fileDateString, datePattern, ci, dts)
    Next
    
End Sub
WININETのFTPじゃダメ?
ありがとうございます。
■No26227に返信(もりおさんの記事)
> ' 文字列からファイル名を切り出す処理
> Dim fileName = convertedLine.Substring(position + 1)
      ↑↑にてエラーが発生しました。
「ArgumentOutOfRangeExpectionはハンドルされませんでした。」
「startIndex に文字列の長さより大きい値を指定することはできません。 パラメータ名: startIndex」

宜しくお願いします。
■No26229に返信(ヴァンさんの記事)
> WININETのFTPじゃダメ?
>
ありがとうございます。
しかし上記の意味が分かりません。
もう少し詳しくご教授頂けると喜びます。

宜しくお願いします。
おはようございます。

>にてエラーが発生しました。
読んだ通りのエラーですので…
データに関することは人に聞いても確実な答えは出ませんから、
場所も分かったことですしご自身でデバッグ実行してその際のposition変数やconvertedLine変数の値を
確認されてはいかがでしょう。
(tryで囲んでいる場合、一時的にtryをコメント化すれば、
ステップ実行せずにF5で一気に実行しても例外発生箇所に黄色い行がとどまってくれるので
変数にマウスカーソルをあてればすぐ確認できると思います。)

また、一覧のフォーマットが気になったのですが、
マメオさんの示されるデータは二回とも各部のスペースがすべてひとつになっていましたが、
魔界の仮面弁士さんの示されるような桁合わせされたフォーマットにはなっていないのでしょうか。
■No26235に返信(こど。さんの記事)
> また、一覧のフォーマットが気になったのですが、
> マメオさんの示されるデータは二回とも各部のスペースがすべてひとつになっていましたが、
> 魔界の仮面弁士さんの示されるような桁合わせされたフォーマットにはなっていないのでしょうか。

それは多分、掲示板への投稿時に「図表モード」を選択しなかったために、
HTML での表示上、複数の空白がひとつにまとめられてしまっているためかと。


■No26227に返信(マメオさんの記事)
> Dim fileName = convertedLine.Substring(position + 1)
> 「ArgumentOutOfRangeExpectionはハンドルされませんでした。」
> 「startIndex に文字列の長さより大きい値を指定することはできません。 パラメータ名: startIndex」

こど。さんも指摘されていますように、エラーが発生したときに、
convertedLine の中身が何になっているか、また、startIndex の値が
何になっているのかを追跡してみてください。


どのような文字列が返されるか分かるのは、その環境を有するマメオさんだけですので、
他の人に聞いても答えは出てきません。御自身でデバッグしていってください。

回答者は、結果から推測する事ができるだけです。とりあえず…可能性としては、
convertedLine が空文字列だとすれば、position は 0 になるでしょうね。

その場合、私の記述にある Mid(line, pos + 1) であれば "" を返しますが、
convertedLine.Substring(position + 1) で取得した場合、今回の
> 「ArgumentOutOfRangeExpectionはハンドルされませんでした。」
> 「startIndex に文字列の長さより大きい値を指定することはできません。 パラメータ名: startIndex」
というエラーとなるはずです。この点を見直してみてください。(ここでいう見直しとは、
Mid 関数に書き換えましょうという意味では無く、元データを調査しましょうという意味です)


一応補足しておくと:

今回のように、Substring では桁数が不足した時にエラーになるので、それを避ける意味で、
先の私の回答( No26115 / No26220 ) では、あえて VB の Left / Mid 関数を使うコードを
提示しています。( No26220 の方は、Left を Substring に置き換えていますが、これは
今回の場合、Substring を Left にしても、エラーを軽減できるわけでは無いためです)

また、今回の処理にそのような空文字列が渡される事が無いように、
あらかじめデータを整備しておいてくださいという意味を込めて、 No26220 にて
> ファイル情報は、先頭が "-" で始まる行ですよね。
> それ以外の行(ディレクトリ情報、空行、最終行)を除去する必要がありそう
と指摘していたのですが、その点は大丈夫でしょうか?

今までのサンプル中には、このデータ整備作業は組み込まれておらず、
単に不要データを除去した後のデータを渡しているだけなので、ご注意ください。
この不要な行を除去する処理は、頑張って御自身で記述してくださいね。
(どんなデータが来るのかを把握/調査できるのは、マメオさんだけなのですから)


下記に、個人的に気になっている点を幾つか挙げておきます。

・ディレクトリとファイルを区別する必要があるのか、無いのか。
・最大の更新日を持つファイルが複数見つかった場合、それらすべてを
 列挙する必要があるのか。それとも任意の一つだけを取得すれば良いのか。
・空白を含むファイル名があった場合、どのように表示されるのか。
・西暦部の表示が省略される事があるようだが、万一、FTPサーバーと
 クライアントのシステム日付が1年以上ずれていた場合、更新日を
 正しく取得できるのか否か。
・昨年以前のファイルには時刻情報が含まれないようだが、その場合、
 日付だけでなく、時刻情報を追加取得する必要があるのではないか。
・いままで提示されてきたサンプル群の内容を、自分なりに理解できているか否か。
・エラーが発生した際に、そのエラーメッセージの意味を理解できているか否か。
■No26239に返信(魔界の仮面弁士さんの記事)
> ■No26235に返信(こど。さんの記事)

こど。さん、魔界の仮面弁士さんありがとうございます。
確認してみます。

先に質問についてですが

> 下記に、個人的に気になっている点を幾つか挙げておきます。
>
> ・ディレクトリとファイルを区別する必要があるのか、無いのか。
区別が必要です。

> ・最大の更新日を持つファイルが複数見つかった場合、それらすべてを
>  列挙する必要があるのか。それとも任意の一つだけを取得すれば良いのか。
時間で抽出すれば、最新の「ABC」ファイルは一つです。
ファイル名違いを含めれば、最新は一つではない場合もあります。

> ・空白を含むファイル名があった場合、どのように表示されるのか。
空白を含むファイル名はありませんが、あった場合のことは未確認です。

> ・西暦部の表示が省略される事があるようだが、万一、FTPサーバーと
>  クライアントのシステム日付が1年以上ずれていた場合、更新日を
>  正しく取得できるのか否か。
サーバーに直接アクセスすると通常の時間表示なので問題ないと思っています。

> ・昨年以前のファイルには時刻情報が含まれないようだが、その場合、
>  日付だけでなく、時刻情報を追加取得する必要があるのではないか。
調べ直したところ、指摘の通りでした。
また古いファイルは西暦表示だけなので、無視して良いかと思ってましたが
年が変わり2010年になって、西暦情報も必要になっているのに気付きました。

> ・いままで提示されてきたサンプル群の内容を、自分なりに理解できているか否か。
全て理解が出来ているとは言えません。

> ・エラーが発生した際に、そのエラーメッセージの意味を理解できているか否か。
それについても上記のとおりです。

すいません、皆さんに頼りすぎですね。
頑張ってみます。
■No26243に返信(マメオさんの記事)
>>・ディレクトリとファイルを区別する必要があるのか、無いのか。
> 区別が必要です。
その場合、行頭文字で判別できると思います。

-rw-r--r--    1 505      506          3351 Nov 18 17:34 ***.aaa.CSV
drwxrwxrwx    2 0        0           69632 Jan 08 21:20 edp

おそらく、行頭が "-" ならファイル情報、"d" ならディレクトリです。
そのいずれでも無い行は、解析対象外として扱うようにすれば良いかと。



> 時間で抽出すれば、最新の「ABC」ファイルは一つです。
ここでいう 「ABC ファイル」というのは、
「ファイル名が "ABC" に完全一致するファイル」ではなく、
「ファイル名の一部に "ABC" を含むファイル」の事と
理解しましたが、この認識で間違いないでしょうか?


> ファイル名違いを含めれば、最新は一つではない場合もあります。
同一ファイル名が同時に複数現れる事は無いと思いますので、これは
「"ABC" を含むファイル名」が複数登場した場合の事だと読み取りました。

その上で、その ABC ファイル群の中に、更新時刻が秒単位まで完全一致する
ファイルがありえる…という意味に受け取りましたが、この認識で合っていますか?


>>・空白を含むファイル名があった場合、どのように表示されるのか。
> 空白を含むファイル名はありませんが、あった場合のことは未確認です。
たとえば Windows XP だと、エクスプローラーでコピーしたファイルは、
"test.txt" → "コピー 〜 test.txt" という名前が付けられたりしますよね。

今回の解析法では、最後の空白以降にある文字列をファイル名として
扱っていますので、万一、上記のように空白を含むファイル名があった場合、
正しく解析できない事になります。


>>・西暦部の表示が省略される事があるようだが、万一、FTPサーバーと
>> クライアントのシステム日付が1年以上ずれていた場合、更新日を
>> 正しく取得できるのか否か。
> サーバーに直接アクセスすると通常の時間表示なので問題ないと思っています。
西暦部が省略されるのは、おそらく「今年更新されたファイル」に対してですよね。
ではその「今年」とは、サーバー日付でしょうか? クライアント日付でしょうか?
恐らくはサーバー日付だと思います。

例えば、"2009/12/31 12:34:45" に更新されたファイルがあったとします。
FTP サーバーの日付が 2009/12/31 23:34:45 の時、取得結果は恐らく、
「Dec 23 12:34」という文字列で返されるものと予想されます。

そしてクライアント時刻が、2010/01/01 00:23:45 にずれていたとします。
その場合、先のロジックで解析すると、「Jan 23 12:34」を日付化した結果、
"2009/12/31 12:34:00" ではなく、"2010/12/31 12:34:00" として
解釈されてしまう恐れがあるのではないでしょうか。


>>・昨年以前のファイルには時刻情報が含まれないようだが、その場合、
>> 日付だけでなく、時刻情報を追加取得する必要があるのではないか。
> 調べ直したところ、指摘の通りでした。
> また古いファイルは西暦表示だけなので、無視して良いかと思ってましたが
> 年が変わり2010年になって、西暦情報も必要になっているのに気付きました。
となると、今のファイル一覧からの解析は不可能ですので、
No26117 にて指摘していた対処が必要になるかと思われます。


>>・いままで提示されてきたサンプル群の内容を、自分なりに理解できているか否か。
> 全て理解が出来ているとは言えません。
「全て」とは、理解度0%という意味ではなく、部分的には理解できたという意味ですよね。
分からなかった部分があるなら、その点を具体的に質問していただければ、
何かしらの追加説明をできるかと思います。


>>・エラーが発生した際に、そのエラーメッセージの意味を理解できているか否か。
> それについても上記のとおりです。
では、No26233 のエラーの意味は理解できましたか?

> Dim fileName = convertedLine.Substring(position + 1)
> 「ArgumentOutOfRangeExpectionはハンドルされませんでした。」
> 「startIndex に文字列の長さより大きい値を指定することはできません。 パラメータ名: startIndex」

このエラーは、ArgumentOutOfRangeExpection という例外です。
文字通り、引数に渡した値が範囲外である事を示しています。

そして、この例外に続くメッセージには、詳細情報として
  Substring メソッドの引数(startIndex) に指定した「文字位置」が、
  元の文字列(convertedLine)の長さに収まっていなかった
という事が示されています。

そこまで分かれば、エラー発生時にどのようなデータを指定したのかを
調べることで、「データの問題」なのか「解析処理の実装ミス」なのかを
判断できるかと思います。
ありがとうございます。
現在分かる範囲で回答致します。

■No26244に返信(魔界の仮面弁士さんの記事)
> ■No26243に返信(マメオさんの記事)
>>時間で抽出すれば、最新の「ABC」ファイルは一つです。
> ここでいう 「ABC ファイル」というのは、
> 「ファイル名が "ABC" に完全一致するファイル」ではなく、
> 「ファイル名の一部に "ABC" を含むファイル」の事と
> 理解しましたが、この認識で間違いないでしょうか?
間違いありません。
>
>
>>ファイル名違いを含めれば、最新は一つではない場合もあります。
> 同一ファイル名が同時に複数現れる事は無いと思いますので、これは
> 「"ABC" を含むファイル名」が複数登場した場合の事だと読み取りました。
>
> その上で、その ABC ファイル群の中に、更新時刻が秒単位まで完全一致する
> ファイルがありえる…という意味に受け取りましたが、この認識で合っていますか?
「ABC」を含むファイル名に更新時間の同じものはありません。
>
>
> >>・空白を含むファイル名があった場合、どのように表示されるのか。
>>空白を含むファイル名はありませんが、あった場合のことは未確認です。
> たとえば Windows XP だと、エクスプローラーでコピーしたファイルは、
> "test.txt" → "コピー 〜 test.txt" という名前が付けられたりしますよね。
>
> 今回の解析法では、最後の空白以降にある文字列をファイル名として
> 扱っていますので、万一、上記のように空白を含むファイル名があった場合、
> 正しく解析できない事になります。
通常空白を含むファイル名はありませんが考慮します。
>
>
> >>・西暦部の表示が省略される事があるようだが、万一、FTPサーバーと
> >> クライアントのシステム日付が1年以上ずれていた場合、更新日を
> >> 正しく取得できるのか否か。
>>サーバーに直接アクセスすると通常の時間表示なので問題ないと思っています。
> 西暦部が省略されるのは、おそらく「今年更新されたファイル」に対してですよね。
> ではその「今年」とは、サーバー日付でしょうか? クライアント日付でしょうか?
> 恐らくはサーバー日付だと思います。
>
> 例えば、"2009/12/31 12:34:45" に更新されたファイルがあったとします。
> FTP サーバーの日付が 2009/12/31 23:34:45 の時、取得結果は恐らく、
> 「Dec 23 12:34」という文字列で返されるものと予想されます。
>
> そしてクライアント時刻が、2010/01/01 00:23:45 にずれていたとします。
> その場合、先のロジックで解析すると、「Jan 23 12:34」を日付化した結果、
> "2009/12/31 12:34:00" ではなく、"2010/12/31 12:34:00" として
> 解釈されてしまう恐れがあるのではないでしょうか。
>
>
> >>・昨年以前のファイルには時刻情報が含まれないようだが、その場合、
> >> 日付だけでなく、時刻情報を追加取得する必要があるのではないか。
>>調べ直したところ、指摘の通りでした。
>>また古いファイルは西暦表示だけなので、無視して良いかと思ってましたが
>>年が変わり2010年になって、西暦情報も必要になっているのに気付きました。
> となると、今のファイル一覧からの解析は不可能ですので、
> No26117 にて指摘していた対処が必要になるかと思われます。
確認してみます。
宜しくお願いします。

DOBON.NET | プログラミング道 | プログラミング掲示板