tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルFTP Socket,LISTで全角文字が正常に表示されない
記事No11350
投稿日: 2014/12/11(Thu) 10:43
投稿者まつ
VB2010 / Windows7 32bit / Framework4

お世話になります。

以前質問させて頂きFtpWebRequestではファイル名に「#」がある場合に
Uriクラスの影響で正常にファイル名が表示されないとご指南頂きました。

そこでMicrosoftのページからFTP Socketクラスのコードを借用しツールを
作り直しています。

Visual Basic .NET または Visual Basic 2005を使用して FTP サイトにアクセスする方法
http://support.microsoft.com/kb/832679/ja

取り敢えずそのままのコードでSolarisサーバーからLISTコマンドで
ファイル名を取得したところ全角文字が「???」になります。
(Function GetFileListのコードを使用)

「あいうえお_1211.xlsx」→「???????????????_1211.xlsx」

他のサイトのコードも試しましたが同じ結果でした。
FTPでファイルの一覧を取得する(パッシブモード)
http://anetm.com/dev/tools/vbdotnet/112303.htm

たまたま試したファイル名が全角だっただけで,今のところ全角文字は
使用しないので困りませんが気になります。

受信時に1バイトづつ読んで文字コード変換とかしているように見えますが
そのために全角は対応出来ないのでしょうか?
じっくりコードを見れば分かるとは思いますがちょっと敷居が高くて。

何か参考になるコードは無いでしょうか?

[ツリー表示へ]
タイトルRe: FTP Socket,LISTで全角文字が正常に表示されない
記事No11354
投稿日: 2014/12/11(Thu) 14:05
投稿者Hongliang
まず前提として、FTPでは文字集合/文字符号化方式について、ほとんどのサーバ/クライアントが従っている
デファクトスタンダードというものが存在していません。
ですので、クライアントはサーバ毎に有効な文字エンコーディングを選択する必要があります。

さて、元のソースを見ると、バイト配列から文字列に変換する際に、Encoding.ASCIIを使用していますね。
ASCIIは0x00〜0x7Fまでの英数字と一部記号程度しか扱わないエンコーディングですので、当然全角文字は
変な変換になってしまいます。
任意のエンコーディングを使ってバイト配列から文字列に変換するには、
Encoding.GetEncoding静的メソッドによってEncodingオブジェクトを取得し、
それを使って変換処理を行うことになります。
たとえばShift_JISを使っているサーバなら、Encoding.GetEncoding("Shift_JIS")みたいな。

> 受信時に1バイトづつ読んで文字コード変換とかしているように見えますが
いえ、Receiveで取得したバイト配列毎に文字列に変換していますよ。
ただマルチバイト文字列の場合、このままだと1文字を表す2バイトの真ん中までで一旦Receiveが完了した場合に、
その部分の文字が化けることになります。
たとえば「いいえ」の3文字はShift_JISだと82 A2 82 A2 82 A6という6バイトになりますが、
82 A2 82とA2 82 A6
という2回に分割されてそれぞれReceiveする可能性があります。
これらにそれぞれEncoding::GetStringすると、"い・"、"「え"という文字列になってしまいます。
これを防ぐためには、EncodingオブジェクトのGetDecoderメソッドで取得できるDecoderオブジェクトを使って
変換処理を行うのがベターです。

Dim text As New StringBuilder()
Dim buffer(m_aBuffer.Length - 1) As Char
Dim dec As Decoder = m_encoding.GetDecoder() ' m_encodingは元ソースではASCIIという名前のメンバ変数
Do While (True)
    bytes = cSocket.Receive(m_aBuffer, m_aBuffer.Length, 0)
    Dim converted As Integer = dec.GetChars(m_aBuffer, 0, bytes, buffer, 0)
    text.Append(buffer, 0 converted)
    
    If (bytes < m_aBuffer.Length) Then
        Exit Do
    End If
Loop

mess = text.ToString().Split(seperator)

[ツリー表示へ]
タイトルRe^2: FTP Socket,LISTで全角文字が正常に表示されない
記事No11355
投稿日: 2014/12/11(Thu) 15:29
投稿者まつ
Hongliang様

的確なご返答ありがとうございました。
内容を理解致しました(コードはまだちょっと分かっていませんが…)。

頂いたコードに置き換えたところ全角文字のファイル名を取得出来ました。

頂いたコードの追記事項
1)UTF-8で変数を宣言
  Private m_encoding As Encoding = Encoding.UTF8
2)記述ミスを修正
  text.Append(buffer, 0 converted) → text.Append(buffer, 0, converted)

[ツリー表示へ]