4

我正在尝试使用以下代码创建一个到 ftp 服务器的文件(我也尝试使用 UseBinary 选项 true 和 false)

string username = "name";
string password = "password";
string remotefolder = "ftp://ftp.myhost.gr/public_html/test/";
string remoteFileName = "δοκιμαστικό αρχείοüß-äCopy.txt";
string localFile = @"C:\test\δοκιμαστικό αρχείο - Copy.txt";
String ftpname = "ftp://ftp.myhost.gr/public_html/test" + @"/" + Uri.EscapeUriString(Program.remoteFileName);


FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpname);
request.Proxy = null;
request.Credentials = new NetworkCredential(username, password);


request.UsePassive = true;
request.KeepAlive = true;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
//request.UseBinary = false;

 byte[] content = System.IO.File.ReadAllBytes(localFile);
 byte[] fileContents = new Byte[content.Length];

 Array.Copy(content, 0, fileContents, 0, content.Length);

 using (Stream uploadStream = request.GetRequestStream())
 {
     int contentLength = fileContents.Length;
     uploadStream.Write(fileContents, 0, contentLength);
 }

 FtpWebResponse response = (FtpWebResponse)request.GetResponse();
 Console.WriteLine(response.ExitMessage);

问题是我的 ftp 服务器上的文件没有得到我请求的包含英语、希腊语和德语字符的名称 --> "δοκιμαστικό αρχείοüß-äCopy.txt

1)我能用它做什么?

更改区域设置后会有一些改进-> 非 Unicode 程序的当前语言为希腊语,但我仍然想念德语字符。

2)为什么ac#程序依赖这个设置?为了避免依赖此设置,我应该遵循一种特殊的方法吗?

编码噩梦再次出现:(

4

2 回答 2

9

仅将字符串编码为 UTF8 并将其作为文件名发送到 FTP 服务器是不够的。过去,所有 FTP 服务器都只理解 ASCII,而现在为了保持向后兼容性——即使它们能够识别 Unicode——当它们启动时,它们也将所有文件名都视为 ASCII。

为了使这一切正常工作,您(您的程序)必须首先检查您的服务器的能力。服务器在客户端连接后发送其功能 - 在您的情况下,您必须检查FEAT UTF8。如果您的服务器发送它 - 这意味着它理解 UTF8。尽管如此 - 即使它理解它 - 你必须明确告诉它,从现在开始你将发送你的文件名 UTF8 编码,现在它是你的程序缺少的东西(因为你的服务器支持你所说的 utf8)。

您的客户端必须向 FTP 服务器发送以下OPTS UTF8 ON。发送后,您可以使用 UTF8 或对您的服务器说 UTF8-ish(可以这么说)。

阅读此处了解详细信息文件传输协议的国际化

于 2013-11-11T10:06:37.827 回答
4

在您的代码更改中:

string localFile = @"C:\test\δοκιμαστικό αρχείο - Copy.txt";
String ftpname = "ftp://ftp.myhost.gr/public_html/test" + @"/" + Uri.EscapeUriString(Program.remoteFileName);

FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpname);

至:

string remoteFileName = "δοκιμαστικό αρχείο - Copy.txt";
String ftpname = "ftp://ftp.myhost.gr/public_html/test" + @"/" + remoteFileName;

var escapedUriString = Uri.EscapeUriString(Encoding.UTF8.GetString(Encoding.ASCII.GetBytes(ftpname)));
var request = (FtpWebRequest)WebRequest.Create(escapedUriString);

之所以需要这样做,是因为EscapeUriString的输入参数根据 RFC 2396 规范进行了转义。

RFC 2396标准规定:

当一个新的 URI 方案定义了一个表示由通用字符集 [UCS] 中的字符组成的文本数据的组件时,数据应首先根据 UTF-8 字符编码 [STD63] 编码为八位字节;那么只有那些与未保留集中的字符不对应的八位字节应该进行百分比编码。

因此,上面显示的代码更改将强制此字符串以 UTF-8 格式输入。

关于:

  1. 为什么ac#程序依赖这个设置?为了避免依赖此设置,我应该遵循一种特殊的方法吗?

Uri.EscapeUriString需要遵循 RFC 2396 规范的输入,因此需要以它可以理解的格式传递数据。

于 2013-11-04T17:52:41.290 回答