C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: uriにutf8文字列をセットする方法


(過去ログ 100 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■59787 / inTopicNo.1)  uriにutf8文字列をセットする方法
  
□投稿者/ jj (1回)-(2011/06/07(Tue) 11:40:39)

分類:[VB.NET/VB2005 以降] 

vs2008とvbでftpクライアントを作っています。ftpサーバ側はlinux & vsftpdでutf-8で動いています。

ftpwebrequestを使って簡単なftp clientとなるプログラムを作っているのですが、日本語(UTF-8)ファイル名を持ったファイルをget出来なくて困っています。
ftpwebrequestオブジェクトを作る際にはString型の引数uriを指定しますが、
このuriにutf8エンコードした文字列をセットできればこの問題は解決すると思っています。
(ftpのRETRコマンドにutf8エンコードした文字列を指定すればサーバから日本語名のファイルをgetできるはずという想定は、フリーソフトffftpを使った際には日本語名ファイルを問題なくgetしている様子をパケットキャプチャして確認した事実に基づいています。)
そこで、その方法(VBで、String型の文字列にutf-8エンコーディングされたバイト列をセットする方法)を
探しているのですが、どうしても分かりませんでした。
例えば、 テスト.txt という文字列をutf-8で表すと、
e3 83 86 e3 b2 b9 e3 83 88 2e 74 78 74
になりますが、こんなバイト列をもったstring型をどうやって作り出すのかが分かりません。


すみませんがどなたか教えていただけないでしょうか。
引用返信 編集キー/
■59789 / inTopicNo.2)  Re[1]: uriにutf8文字列をセットする方法
□投稿者/ shu (763回)-(2011/06/07(Tue) 12:04:16)
No59787 (jj さん) に返信

System.Text.Enconding.UTF8.GetBytes(〜)
でUTF8エンコーディングしたbyte配列が取得出来ますが、
どうでしょう?
引用返信 編集キー/
■59793 / inTopicNo.3)  Re[1]: uriにutf8文字列をセットする方法
□投稿者/ 魔界の仮面弁士 (2198回)-(2011/06/07(Tue) 13:39:22)
No59787 (jj さん) に返信
linux → Linux
ftpwebrequest → FtpWebRequest
ではありませんか? (大文字小文字に注意)


> ftpwebrequestオブジェクトを作る際にはString型の引数uriを指定しますが、
基本的には、そのまま日本語を含めてしまって構いません。

サーバー側が、[OPTS utf8 on] コマンドに対応している場合(サーバーから
200 のステータスを返された場合など)は、そのまま UTF-8 のバイナリとして
RETR コマンドが送出されます。今回の場合は、e3 83 86 e3 b2 b9 e3 83 88 2e 74 78 74 ですね。

サーバー側が [OPTS utf8 on] に対応しておらず、501 や 502 のステータスが
返した場合、CP932 表現で送出されます。83 65 83 58 83 67 2e 74 78 74 のように。

そして FtpWebRequest では、上記以外のエンコーディングには対応できないはずです。


大文字表記の [OPTS UTF8 ON] にしか対応していないサーバーや、切り替え無しで
UTF-8 固定で喋るサーバーの場合には、FtpWebRequest では対応できない可能性があります。
その場合には、ソケットにて FTP コマンドを直接喋るようにするか、または
市販の FTP コンポーネント等に頼った方が良いでしょう。



> テスト.txt という文字列をutf-8で表すと、
> e3 83 86 e3 b2 b9 e3 83 88 2e 74 78 74
文字列をバイナリ化する際にエンコーディング作業が発生するのであって、
文字列自体にエンコーディング情報を埋め込めるわけではありませんよね。

一応、パーセントエンコーディングするというと言う手はありますが、
無理に変換したところで、結局のところ、
 u = New Uri("ftp://localhost/%e3%83%86%e3%82%b9%e3%83%88.txt")
 s = u.ToString()
は、"ftp://localhost/テスト.txt" として処理されますので、意味が無いと思います。


以下、参考までに。

Dim s As String = "テスト.txt"

'%E3%83%86%E3%82%B9%E3%83%88.txt
Dim a As String = System.Uri.EscapeUriString(s)

'%e3%83%86%e3%82%b9%e3%83%88.txt
Dim b As String = System.Web.HttpUtility.UrlEncode(s)

'E3-83-86-E3-82-B9-E3-83-88-2E-74-78-74
Dim c As String = System.BitConverter.ToString(System.Text.Encoding.UTF8.GetBytes(s))
引用返信 編集キー/
■59796 / inTopicNo.4)  Re[2]: uriにutf8文字列をセットする方法
□投稿者/ jj (2回)-(2011/06/07(Tue) 13:51:27)
shu様
返信ありがとうございます。また、言葉足らずな点があったので補足させていただきます。
ご指摘いただいた方法で、UTF8での「バイト配列」を得ることは思いつきました。
しかし、Url文字列に与える引数は絶対にString型でなければだめですよね。
つまり、この「バイトの配列」を「そのままのバイト列とした」String型(こんな言い方でいいのでしょうか)に
する方法を知る必要がある、と考えているのです。
私はバイト配列を再びstring型に変換する必要があると思っておりまして、このために見つけた方法
System.Text.Encoding.GetEncoding(エンコーディング).GetString(バイト配列)
は、結局はバイト配列をUnicodeで表記したString型に変換するものであり、役に立たないと思っています。

うまく意図をお伝えできていればいいのですが。。。
よろしくお願いします。
引用返信 編集キー/
■59813 / inTopicNo.5)  Re[3]: uriにutf8文字列をセットする方法
□投稿者/ 魔界の仮面弁士 (2202回)-(2011/06/07(Tue) 19:40:45)
No59796 (jj さん) に返信
> する方法を知る必要がある、と考えているのです。

受信側については、FtpWebResponse.GetResponseStream の読み取り時に Encoding を
指定するだけで済みますが、送信 URL については、Encoding の指定方法が提供されていません。

先の私の回答にて、FtpWebRequest が Uri をデコードする際の仕組みを記述しています。
サーバー側が [OPTS utf8 on] コマンドをサポートしているかどうかを調べてみてください。

その上で、サーバー側が OPTS utf8 on に対応できないようであれば、FtpWebRequest を
使う事は諦めて、SocketクラスやTcpClientクラスで対処した方が良いと思います。
http://members.jcom.home.ne.jp/1213687801/tookun.html


> つまり、この「バイトの配列」を「そのままのバイト列とした」String型

その方向では解決できないと思いますよ。
ANSI (CP932) で "テスト.txt" という文字列にデコード可能な文字列を格納しようにも、
ほぼ間違いなく、文字化けという名のデータ破損を引き起こすことが予想されます。

先にも書きましたが、文字列自体にエンコーディング情報を埋め込めるわけではありません。
FtpWebRequest が送出するコマンドは UTF-8 もしくは ANSI(CP932) だろうと予想していますが、
System.String の内部バイナリは UTF-16 固定であり、CP932 で格納できるようにはなっていません。

たとえば、"テスト.txt" を UTF-8 でエンコードすると、
 テ : E3 83 86
 ス : E3 82 B9
 ト : E3 83 88
 .  : 2E
 t  : 74
 x  : 78
 t  : 74
となりますよね。

上記バイナリを CP932 でデコードするとなると、結果は
 繝 : E3 83
    : 86
    :    E3
 せ : 82 B9
 繝 : E3 83
    : 88
    :    2E
 t  : 74
 x  : 78
 t  : 74
となります。

ということは、"せ繝" という文字列(5B 30 5D 7E)を渡せば、それが CP932 として
デコードされる場合、先の UTF-8 バイナリの一部に相当する 82 B9 E3 83 が送出されるわけです。

しかしこの方法では、その前後にある 86 E3 や 88 2E に相当する文字列は作れません。

86,E3 や 86 というバイナリは、CP932 では有効な文字データとして処理されないため、
これらのバイナリを無理に String 化させても、結局は破損する
(復元不可能な文字化けを引き起こす)ことになります。

ゆえに、そうしたバイナリに相当する Uri を作りこむことはできないかと。

 Dim a1 As String = Chr(&H86E3)
 Dim b1 As String = Chr(&H882E)
 Dim c1 As String = Chr(&H86)

 Dim a2 As String = System.Text.Encoding.Default.GetString(New Byte() {&H86, &HE3})
 Dim b2 As String = System.Text.Encoding.Default.GetString(New Byte() {&H88, &H2E})
 Dim c2 As String = System.Text.Encoding.Default.GetString(New Byte() {&H86})


仮に、そうした Uri を作りこめたと仮定しても、その文字列の内容が UTF-8 として
送出されるのか、それとも ANSI (CP932) で送出されるのかは、先の OPTS utf8 on への
応答結果によって変わってしまうわけですから、あまり良い方法では無いでしょう。

引用返信 編集キー/
■59816 / inTopicNo.6)  Re[1]: uriにutf8文字列をセットする方法
□投稿者/ 魔界の仮面弁士 (2203回)-(2011/06/07(Tue) 20:04:04)
No59787 (jj さん) に返信
> 例えば、 テスト.txt という文字列をutf-8で表すと、
> e3 83 86 e3 b2 b9 e3 83 88 2e 74 78 74
これは        ..
  e3 83 86 e3 82 b9 e3 83 88 2e 74 78 74
ですよね。    ^^
B2 が 82 になってしまっていますよ。


E3-82-B9 なら、ChrW(&H30B9) すなわち「ス」という文字を指しますが、
E3-B2-B9 だと、ChrW(&H3CB9) という文字になります。

# これは、の異体字ですね。(汎 から ` を消したような字)
# Win7 等では表示できますが、WinXP 等では表示できないかな?
# http://glyphwiki.org/wiki/u3cb9


細かいことですが、この B2(本来は 82)の間違いを指摘しておかないと、
>> No59813
>> 先の UTF-8 バイナリの一部に相当する 82 B9 E3 83
という発言が繋がらなくなってしまうので…一応ツッコミ。

引用返信 編集キー/
■59833 / inTopicNo.7)  Re[2]: uriにutf8文字列をセットする方法
□投稿者/ jj (3回)-(2011/06/08(Wed) 12:02:51)
魔界の仮面弁士様

一連の的確なご説明、どうもありがとうございました。非常に助かりました。
エンコーディングに関して理解不足だった事、および当初私が考えついた対応方針ではダメな事が、よく理解でしました。

いただいたアドバイスに従いサーバ側のOPTS utf8 onへの反応を調べてみたところ、非対応でした。そこでvsftpdを最新バージョンにしたところ、FtpWebRequestはご指摘の通りの挙動を示し、問題は解決できました。
どうもありがとうございました。

>細かいことですが、この B2(本来は 82)の間違いを指摘しておかないと、
>>> No59813
>>> 先の UTF-8 バイナリの一部に相当する 82 B9 E3 83
>という発言が繋がらなくなってしまうので…一応ツッコミ。
ありがとうございます。こちらもご指摘の通りでした。

最後にひとつ参考のために教えてください。
>FtpWebRequest が送出するコマンドは UTF-8 もしくは ANSI(CP932) だろうと予想していますが、
OPTS utf8 onコマンドへの応答により送出するバイト列が変化する事実は、どのようにして調べられたのですか?(私自身もかなり情報を探したつもりでしたが気がつきませんでした。。。)それとも今までのご経験からの推測でしょうか?この挙動の変化をご指摘いただいた点、非常に感心しました。

以上、ありがとうございました。
解決済み
引用返信 編集キー/
■59835 / inTopicNo.8)  Re[3]: uriにutf8文字列をセットする方法
□投稿者/ 魔界の仮面弁士 (2207回)-(2011/06/08(Wed) 12:55:12)
No59833 (jj さん) に返信
> OPTS utf8 onコマンドへの応答により送出するバイト列が変化する事実は、どのようにして調べられたのですか?

「Microsoft Network Monitor」のキャプチャ結果からです。

その中に、「OPTS utf8 on」という見知らぬコマンドを見つけたため、
試しに IIS 5.1(XP) や IIS 7.x(2008) に対して実験してみたところ、
IIS 5.1 では CP932、IIS 7.x は UTF-8 でやりとりされている事を確認できました。

そこまで解析できれば、あとはネットで調べれば、OPTS コマンドの意味を調べる事も
IIS 7.0 以降の FTP サービスが UTF8 対応になったことも容易に調査できたという次第です。


> それとも今までのご経験からの推測でしょうか?
上記の通りですので、どちらかと言えば経験則ですかね。

ただ、OPTS utf8 on 以外の切り替え方法があるのかどうかは把握していませんし、
この動作が FtpWebRequest によってもたらされているのか、それとも
OS 側の仕様に基づいているのかまでは調査していません。

なので先の回答でも、
No59813 > FtpWebRequest が送出するコマンドは UTF-8 もしくは ANSI(CP932) だろうと予想していますが
という曖昧な書き方をしています。 No59793 で断定的な書き方をしてしまったことへの訂正の意味も少し込めて。
解決済み
引用返信 編集キー/
■59844 / inTopicNo.9)  Re[4]: uriにutf8文字列をセットする方法
□投稿者/ jj (4回)-(2011/06/08(Wed) 16:41:25)
魔界の仮面弁士様

> その中に、「OPTS utf8 on」という見知らぬコマンドを見つけたため、
> 試しに IIS 5.1(XP) や IIS 7.x(2008) に対して実験してみたところ、
> IIS 5.1 では CP932、IIS 7.x は UTF-8 でやりとりされている事を確認できました。
すべて納得しました。ここまで手間をかけていただきありがとうございました。
ほんと頭が上がりません。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -