zoukankan      html  css  js  c++  java
  • 一则中文文件名引起的问题

          项目中有个ftp组件,在下载中文命名的文件时,总抛出错误“Access is denied, cannot be found the file specified”,英文命名的文件却能够正常下载。首先想到的是编码问题,将文件名做了一次UrlEncode,仍是同样的错误。后来查找代码,发现使用了非标准的ftp command。

      先看一下下载代码部分:

     1 public void OpenDownload(string remoteFileName, string localFileName, bool resume){
     2          ***********code etc**************
     3             SetBinaryMode(true);
     4             OpenDataSocket();
     5 
     6             bytes_total = 0;
     7 
     8             _fileSize = GetFileSize(remoteFileName);  
     9 
    10             Byte[] cmd = Encoding.UTF8.GetBytes(("RETR ").ToCharArray());
    11             byte[] bytes = Encoding.UTF8.GetBytes(remoteFileName);
    12             byte[] content = Encoding.Convert(Encoding.UTF8, Encoding.Default, bytes);
    13             int totalLength = cmd.Length + content.Length;
    14             byte[] re = new byte[totalLength + 2];
    15             for (int i = 0; i < cmd.Length; i++)
    16             {
    17                 re[i] = cmd[i];
    18             }
    19             for (int i = 0; i < content.Length; i++)
    20             {
    21                 re[cmd.Length + i] = content[i];
    22             }
    23             re[totalLength] = 13;
    24             re[totalLength + 1= 10;
    25 
    26             main_sock.Send(re, re.Length, 0);
    27 
    28             ReadResponse();
    29          ***********code etc**************
    30 }

      抛出问题的语句做了下标注。此处是获取远程服务器上文件大小。具体代码:

    获取文件大小
     1 /// <summary>
     2 /// 获取文件大小
     3 /// </summary>
     4 /// <param name="filename">文件名</param>
     5 /// <returns>文件大小</returns>
     6 public long GetFileSize(string fileName){
     7     Connect();
     8     SendCommand("SIZE " + fileName);
     9     ReadResponse();
    10 
    11     if (response != 213throw new ServerException(responseStr);
    12 
    13         return Int64.Parse(responseStr.Substring(4), CultureInfo.CurrentCulture);
    14 }

      其中,SendCommand函数为

    1 private void SendCommand(string command){
    2     Byte[] cmd = Encoding.ASCII.GetBytes((command + "\r\n").ToCharArray());
    3     main_sock.Send(cmd, cmd.Length, 0);
    4 }

      socked发出ftp的size命令后,得到的响应始终不会是213,抛出的异常就是找不到指定的文件,不论文件名是否做过unicode编码。

      在SendCommand函数中,可以看到,命令被作为ascii编码的串进行字节转换。换成Unicode?服务器会抛出超时错误:“Timed out waiting on server to respond”。UTF8?服务器则会抛出与ASCII编码一样的错误。

      后来查阅了相关的文档,发现ftp的size命令为非标准的command。在Ascii编码体系中,支持size command来获取文件大小。一些Unix的ftp服务中,已经不支持非标准的命令。size存在与ascii编码体系中,所以,如果是非ascii编码的文件名,通过size是获取文件大小,服务器就会返回550错误:"Access is denied, cannot be found the file specified"。

         问题总算找到了,中文等不在ascii码范围,发送size命令,ftp服务器(支持非标准ftp command,否则ftp server会返回500错误:不能识别的命令)会将文件名当成ascii码解析查找,中文文件名自然是查找不到,进行urlecode之后,经过一系列的字节转换,发送到ftp server之后,相当于文件名做了变更,自然找不到文件。

      接下来就是修改问题了,文件大小的计算放在了文件被下载到本地后,而没有放在下载前,同时,编码统一为UFT8。至此解决完成。

  • 相关阅读:
    把Linq查询返回的var类型的数据 转换为DataTable EF连接查询
    无法更新 EntitySet 因为它有一个 DefiningQuery
    MVC上传文件
    MySql删除表、数据
    LINQ to Entities 不支持 LINQ 表达式节点类型“ArrayIndex”。
    MVC仓储使用join
    MVC仓储执行存储过程报错“未提供该参数”
    Newtonsoft.Json自动升级版本号,导致dll冲突
    MVC中构建Linq条件、排序、Selector字段过滤
    AutoMapper
  • 原文地址:https://www.cnblogs.com/huankfy/p/1757810.html
Copyright © 2011-2022 走看看