teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

修正

2018/05/30 07:25

投稿

8524ba23
8524ba23

スコア38352

answer CHANGED
@@ -1,21 +1,46 @@
1
1
  そもそも`FTP`において日本語を含むファイル名を使うのは避けるべきなのですが…
2
2
 
3
3
  [ftplib](https://github.com/python/cpython/blob/master/Lib/ftplib.py)ソースの[このあたり](https://github.com/python/cpython/blob/master/Lib/ftplib.py#L106)や[このあたり](https://github.com/python/cpython/blob/master/Lib/ftplib.py#L469)を見るからに、`.nlst`の結果を`Latin-1`(` ISO-8859-1`)として読み込んでいるのが問題のようです。
4
- サーバの返すテキストのエンコーディングと、読込用に開いているテキストのエンコーディングが正しくマッチしていないため、読込後の文字列(`str`型)の内容が正しくりません。
4
+ サーバの返すテキストのエンコーディングと、読込用に開いているテキストのエンコーディングが正しくマッチしていない場合、読込後の文字列(`str`型)の内容が正しくりません。
5
5
 
6
6
  そこでFTPサーバの返す文字列のエンコーディングを事前に確認しておき、ソース上で明示的に指定することで正しく動作する可能性があります。
7
7
 
8
8
  参考:[Python: Reading Ftp file list with UTF-8?](https://stackoverflow.com/questions/29523067/python-reading-ftp-file-list-with-utf-8)
9
9
 
10
+ ## 修正
11
+ サーバ側が対応しているかによりますが、`OPTS UTF8 ON`コマンドによって、サーバ応答を`UTF-8`エンコーディング指定できるかもしれません。指定できた場合は`ftp.encoding = 'utf-8'`により`utf-8`で受け取れます。
12
+
13
+ 以下、検証コードです。
10
- ちなみに`IIS(10.0)`だと`shift_jis`正常読み込めるようになりました
14
+ 当方環境の`IIS(10.0)`や、著名FTPサイトはこのコマンド対応しているようです
11
15
  ```Python
12
- from ftplib import FTP
16
+ from ftplib import FTP, all_errors
17
+
18
+ host_names = [
19
+ #'localhost', # 独自検証できるサーバがあれば…
20
+ 'ftp.riken.go.jp','ftp.jaist.ac.jp','ftp.u-aizu.ac.jp','ftp.iij.ad.jp','ftp.mirrorservice.org' # 著名サイト
21
+ ]
22
+
23
+ with open( 'nlst.txt', 'w', encoding='utf-8') as f:
24
+
25
+ for host_name in host_names:
13
- with FTP('localhost') as ftp:
26
+ with FTP(host_name) as ftp:
27
+ print(host_name)
28
+ f.write(host_name + '\n')
29
+
30
+ # まずはサーバ側にUTF-8で応答してもらうように頼む
31
+ try:
32
+ print(ftp.sendcmd('OPTS UTF8 ON')) # 確認用
33
+
34
+ ftp.voidcmd( 'OPTS UTF8 ON')
35
+ ftp.encoding = 'utf-8'
36
+ except all_errors as e:
37
+ print( e)
38
+ # 'Latin-1'以外のサーバが利用している(と思われる)エンコーディングが分かっていれば指定する
14
- ftp.encoding = 'shift_jis' # この行を追加
39
+ ftp.encoding = 'shift_jis'
40
+
15
- ftp.login()
41
+ ftp.login()
16
- items = ftp.nlst('test/')
42
+ items = ftp.nlst('pub/')
17
- with open('ret.txt', 'w', encoding='utf-8') as f:
18
- for row in items:
43
+ for row in items:
19
- f.write(row + '\n') # 標準出力に惑わされないようファイルにも出力
44
+ f.write(row + '\n') # 標準出力に惑わされないようファイルにも出力
20
- print(row) # test/あいう_sjis.txt
45
+ print(row)
21
46
  ```