为什么从硬盘上的ftp服务器下载文件时,我看到它是100 ???。jpg?

时间:2014-12-25 21:54:08

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

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

File on ftp server

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

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

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

问题是在这种情况下我该怎么办?也许强制将文件名重新命名为某个默认的临时文件名?

我想问题是ftp服务器ipage.com主机不知道读取希伯来文,所以上传后看起来像gibrish。

或许我需要以某种方式上传它使用希伯来语编码文件名? 这是我用来上传文件的方法:

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;
                }
            }
        }

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

这就是ftp服务器上的文件在用gibrish上传之后的样子:

Uploaded test file

我该怎么办?在上传方法中进行上传之前的编码应该解决吗?如果是这样我怎么做编码?

1 个答案:

答案 0 :(得分:0)

可能就像更改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')));

我完全懒惰,依靠Reactive Extensions为我缓冲数据。

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.