【问题标题】:Why when downloading a file from my ftp server on the hard disk i see it 100???.jpg?为什么从我的硬盘上的 ftp 服务器下载文件时,我看到 100???.jpg?
【发布时间】:2015-02-23 09:42:54
【问题描述】:

首先这是我硬盘上的原始文件名:שקל100.jpg שקל 是希伯来语中的一个词 当我将文件上传到我的 ftp 时,上传没有问题,但 ftp 服务器上的文件名如下所示:

ftp 服务器上的文件看起来像 gibrish 而不是希伯来语。 问题是当我尝试下载文件时。文件名是100???.jpg 而且 FtpWebrequest 不知道什么是 100???.jpg

reqFTP = (FtpWebRequest)FtpWebRequest.Create(fileurl);

在 fileurl 我看到:ftp://ftp.newsxpressmedia.com/D/100???.jpg

问题是在这种情况下我能做什么?也许强制将文件名重命名为一些默认的临时文件名?

我猜问题是 ftp 服务器 ipage.com 主机不知道阅读希伯来语所以上传后它看起来像乱码。

或者我可能需要以某种方式上传它并使用希伯来语对文件名进行编码? 这是我用来上传文件的方法:

private void StringArrayUploadFiles(object sender, DoWorkEventArgs e)
        {
            try
            {
                UploadedFiles = files;
                foreach (string fn in files)
                {                  
                    BackgroundWorker bw = sender as BackgroundWorker;
                    f = e.Argument as FtpSettings;
                    MakeDir(f.TargetFolder);
                    string UploadPath = String.Format("{0}/{1}{2}", f.Host, f.TargetFolder == "" ? "" : f.TargetFolder + "/", Path.GetFileName(fn));
                    if (!UploadPath.ToLower().StartsWith("ftp://"))
                        UploadPath = "ftp://" + UploadPath;
                    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(UploadPath);
                    request.UseBinary = true;
                    request.UsePassive = f.Passive;
                    request.Method = WebRequestMethods.Ftp.UploadFile;
                    request.Timeout = 300000;
                    request.Credentials = new NetworkCredential(f.Username, f.Password);
                    long FileSize = new FileInfo(fn).Length;//f.SourceFile).Length;
                    string FileSizeDescription = GetFileSize(FileSize);
                    int ChunkSize = 4096, NumRetries = 0, MaxRetries = 50;
                    long SentBytes = 0;
                    byte[] Buffer = new byte[ChunkSize];
                    using (Stream requestStream = request.GetRequestStream())
                    {
                        using (FileStream fs = File.Open(fn, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                        {
                            int BytesRead = fs.Read(Buffer, 0, ChunkSize);
                            while (BytesRead > 0)
                            {
                                try
                                {
                                    if (bw.CancellationPending)
                                        return;

                                    requestStream.Write(Buffer, 0, BytesRead);

                                    SentBytes += BytesRead;

                                    string SummaryText = String.Format("Transferred {0} / {1}", GetFileSize(SentBytes), FileSizeDescription);
                                    bw.ReportProgress((int)(((decimal)SentBytes / (decimal)FileSize) * 100), SummaryText);
                                }
                                catch (Exception ex)
                                {
                                    Debug.WriteLine("Exception: " + ex.ToString());
                                    if (NumRetries++ < MaxRetries)
                                    {
                                        fs.Position -= BytesRead;
                                    }
                                    else
                                    {
                                        throw new Exception(String.Format("Error occurred during upload, too many retries. \n{0}", ex.ToString()));
                                    }
                                }
                                BytesRead = fs.Read(Buffer, 0, ChunkSize);
                            }
                        }
                    }
                    using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
                        System.Diagnostics.Debug.WriteLine(String.Format("Upload File Complete, status {0}", response.StatusDescription));
                }
                //}
            }
            catch (WebException ex)
            {
                switch (ex.Status)
                {
                    case WebExceptionStatus.NameResolutionFailure:
                        ConnectionError = "Error: Please check the ftp address";
                        break;
                    case WebExceptionStatus.Timeout:
                        ConnectionError = "Error: Timout Request";
                        break;
                }
            }
        }

我现在做了一个测试,试图上传一个文件名中带有希伯来语的文件。 在变量文件中,我看到带有希伯来字母的文件很好。 并且上传的文件没有任何异常或问题。

这是文件在再次使用 gibrish 上传后在 ftp 服务器上的样子:

遇到这种情况我该怎么办?在上传方法中进行上传之前的编码应该解决吗?如果是这样,我该如何进行编码?

【问题讨论】:

  • 您的 FTP 服务器和操作系统是否支持 unicode 名称?
  • Dark my os 是的,我不确定我的 ftp 服务器。

标签: c# .net winforms file-upload ftp


【解决方案1】:

这可能就像更改 FTP 服务器、configuring to support Unicode characters 或切换到 SFTP 一样简单。

如果符合 RFC 2640 的客户端发送 OPTS UTF-8 ON,无论 OPTS UTF-8 ON 是否成功,它都必须使用 UTF-8。符合 RFC 2640 的服务器不得使 UTF-8 依赖于 OPTS UTF-8 ON。

Ftp create a filename with utf-8 chars such as greek, german etc

如果这不是一个选项,恐怕在这种情况下您将不得不自己执行文件名编码和解码。

const string fileName = "100%ץצקרתﬤﬢ.jpg";
var bytes = Encoding.Unicode.GetBytes(fileName);
var doubleBytes = bytes.ToObservable().Buffer(2);

var asciiFileName = new StringBuilder();
doubleBytes.Subscribe(
    s =>
        asciiFileName.Append(s[1] == 0
            ? (s[0] == 37 ? "%25" : Convert.ToString((char) s[0]))
            : String.Format("%{0:X2}%{1:X2}", s[0], s[1]).PadLeft(2, '0')));

我在这里完全懒惰依赖响应式扩展来为我缓冲数据。

asciiFileName 的值为

100%25%E5%05%E6%05%E7%05%E8%05%EA%05%24%FB%22%FB.jpg

不是最漂亮的,但它保留了原始字符。左右对齐的字符串可能会遇到额外的挑战,所以轻轻地穿线...... :)

如果您不想使用 Rx,那么这个扩展就可以解决问题:

public static class Extensions
{
    public static IEnumerable<byte[]> ToBytePairs(this byte[] array)
    {
        var enumerator = array.GetEnumerator();
        while (enumerator.MoveNext())
        {
            var bytePair = new byte[2];
            bytePair[0] = (byte)enumerator.Current;
            enumerator.MoveNext();
            bytePair[1] = (byte)enumerator.Current;
            yield return bytePair;
        }
    }
}

我希望这能给你一个开始,但你必须自己编写相反的过程。 :)

更新

我获取了一个 Microsoft 样本并确认它可以与 FileZilla 服务器(前面提到过)一起使用

#region

using System;
using System.IO;
using System.Net;
using System.Threading;

#endregion

namespace FtpUnicodeClient
{
    public class FtpState
    {
        private readonly ManualResetEvent _wait;

        public FtpState()
        {
            OperationException = null;
            _wait = new ManualResetEvent(false);
        }

        public ManualResetEvent OperationComplete
        {
            get { return _wait; }
        }

        public FtpWebRequest Request { get; set; }

        public string FileName { get; set; }

        public Exception OperationException { get; set; }

        public string StatusDescription { get; set; }
    }

    public class AsynchronousFtpUpLoader
    {
        // Command line arguments are two strings: 
        // 1. The url that is the name of the file being uploaded to the server. 
        // 2. The name of the file on the local machine. 
        // 
        public static void Main(string[] args)
        {
            // Create a Uri instance with the specified URI string. 
            // If the URI is not correctly formed, the Uri constructor 
            // will throw an exception.

            var target = new Uri(args[0]);
            string fileName = args[1];
            var state = new FtpState();
            var request = (FtpWebRequest) WebRequest.Create(target + fileName);
            request.Method = WebRequestMethods.Ftp.UploadFile;

            // This example uses anonymous logon. 
            // The request is anonymous by default; the credential does not have to be specified.  
            // The example specifies the credential only to 
            // control how actions are logged on the server.

            request.Credentials = new NetworkCredential("demo", "demo");

            // Store the request in the object that we pass into the 
            // asynchronous operations.
            state.Request = request;
            state.FileName = fileName;

            // Get the event to wait on.
            ManualResetEvent waitObject = state.OperationComplete;

            // Asynchronously get the stream for the file contents.
            request.BeginGetRequestStream(EndGetStreamCallback, state);

            // Block the current thread until all operations are complete.
            waitObject.WaitOne();

            // The operations either completed or threw an exception. 
            if (state.OperationException != null)
            {
                throw state.OperationException;
            }
            Console.WriteLine("The operation completed - {0}", state.StatusDescription);
        }

        private static void EndGetStreamCallback(IAsyncResult ar)
        {
            var state = (FtpState) ar.AsyncState;

            // End the asynchronous call to get the request stream. 
            try
            {
                Stream requestStream = state.Request.EndGetRequestStream(ar);
                // Copy the file contents to the request stream. 
                const int bufferLength = 2048;
                var buffer = new byte[bufferLength];
                int count = 0;
                int readBytes;
                FileStream stream = File.OpenRead(state.FileName);
                do
                {
                    readBytes = stream.Read(buffer, 0, bufferLength);
                    requestStream.Write(buffer, 0, readBytes);
                    count += readBytes;
                } while (readBytes != 0);
                Console.WriteLine("Writing {0} bytes to the stream.", count);
                // IMPORTANT: Close the request stream before sending the request.
                requestStream.Close();
                // Asynchronously get the response to the upload request.
                state.Request.BeginGetResponse(EndGetResponseCallback, state);
            }
                // Return exceptions to the main application thread. 
            catch (Exception e)
            {
                Console.WriteLine("Could not get the request stream.");
                state.OperationException = e;
                state.OperationComplete.Set();
            }
        }

        // The EndGetResponseCallback method   
        // completes a call to BeginGetResponse. 
        private static void EndGetResponseCallback(IAsyncResult ar)
        {
            var state = (FtpState) ar.AsyncState;
            try
            {
                var response = (FtpWebResponse) state.Request.EndGetResponse(ar);
                response.Close();
                state.StatusDescription = response.StatusDescription;
                // Signal the main application thread that  
                // the operation is complete.
                state.OperationComplete.Set();
            }
                // Return exceptions to the main application thread. 
            catch (Exception e)
            {
                Console.WriteLine("Error getting response.");
                state.OperationException = e;
                state.OperationComplete.Set();
            }
        }
    }
}

检查您的 FTP 日志文件。 FtpWebRequest 客户端似乎已经发送了所需的命令:

(000005)12/26/2014 15:17:15 PM - (not logged in) (::1)> Connected on port 21, sending welcome message...
(000005)12/26/2014 15:17:15 PM - (not logged in) (::1)> USER demo
(000005)12/26/2014 15:17:15 PM - (not logged in) (::1)> 331 Password required for demo
(000005)12/26/2014 15:17:15 PM - (not logged in) (::1)> PASS ****
(000005)12/26/2014 15:17:15 PM - demo (::1)> 230 Logged on
(000005)12/26/2014 15:17:15 PM - demo (::1)> OPTS utf8 on
(000005)12/26/2014 15:17:15 PM - demo (::1)> 202 UTF8 mode is always enabled. No need to send this command.
(000005)12/26/2014 15:17:15 PM - demo (::1)> PWD
(000005)12/26/2014 15:17:15 PM - demo (::1)> 257 "/" is current directory.
(000005)12/26/2014 15:17:15 PM - demo (::1)> TYPE I
(000005)12/26/2014 15:17:15 PM - demo (::1)> 200 Type set to I
(000005)12/26/2014 15:17:15 PM - demo (::1)> EPSV
(000005)12/26/2014 15:17:15 PM - demo (::1)> 229 Entering Extended Passive Mode (|||7800|)
(000005)12/26/2014 15:17:15 PM - demo (::1)> STOR 100ץצקרתﬤﬢ.txt
(000005)12/26/2014 15:17:15 PM - demo (::1)> 150 Opening data channel for file upload to server of "/100ץצקרתﬤﬢ.txt"
(000005)12/26/2014 15:17:15 PM - demo (::1)> 226 Successfully transferred "/100ץצקרתﬤﬢ.txt"
(000005)12/26/2014 15:17:15 PM - demo (::1)> disconnected.

【讨论】:

    猜你喜欢
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多