ftp upload is too big

2020-04-16 02:59发布

问题:

I've written a function in C# to upload a file when copying to a file share does not work. I'm noticing that any uploaded files are about 1.5-2x the size of the original and are invalid files. Here is the code:

public bool save_FTPUpload(FileInfo fi_attachment)
{
    bool fileSaved = false;
    string filename = fi_attachment.Name;

    while (!fileSaved)
    {
        string file_ftpURI = string.Format("{0}/{1}", ftpURI, filename);
        FtpWebRequest file_exist_request = (FtpWebRequest)FtpWebRequest.Create(file_ftpURI);
        file_exist_request.Credentials = new NetworkCredential(ftp_user, ftp_pass);
        file_exist_request.Method = WebRequestMethods.Ftp.GetFileSize;
        try
        {
            FtpWebResponse response = (FtpWebResponse)file_exist_request.GetResponse();
        }
        catch (WebException ex)
        {
            FtpWebResponse response = (FtpWebResponse)ex.Response;
            if (response.StatusCode ==
                FtpStatusCode.ActionNotTakenFileUnavailable)
            {
                FtpWebRequest upload_request = (FtpWebRequest)FtpWebRequest.Create(file_ftpURI);
                upload_request.Credentials = new NetworkCredential(ftp_user, ftp_pass);

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

                StreamReader attachment = new StreamReader(fi_attachment.FullName);
                byte[] attachmentData = Encoding.UTF8.GetBytes(attachment.ReadToEnd());
                upload_request.ContentLength = attachmentData.Length;

                //Stream upload_request_stream = upload_request.GetRequestStream();
                using (Stream upload_request_stream = upload_request.GetRequestStream())
                {
                    upload_request_stream.Write(attachmentData, 0, attachmentData.Length);
                    upload_request_stream.Close();
                }
                FtpWebResponse upload_response = (FtpWebResponse)upload_request.GetResponse();

                fileSaved = true;
            }
        }
    }
    return fileSaved;
}

Any help in figuring this out would be great.

回答1:

You need to copy the content of the file in binary mode, like this:

var response = (FtpWebResponse)ex.Response;
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable) {
    FtpWebRequest upload_request = (FtpWebRequest)FtpWebRequest.Create(file_ftpURI);
    upload_request.Credentials = new NetworkCredential(ftp_user, ftp_pass);
    upload_request.Method = WebRequestMethods.Ftp.UploadFile;
    upload_request.UsePassive = true;
    upload_request.UseBinary = true;
    upload_request.KeepAlive = false;
    var attachment = File.Open(fi_attachment.FullName, FileMode.Open);
    using (Stream upload_request_stream = upload_request.GetRequestStream()) {
        attachment.CopyTo(upload_request_stream);
        upload_request_stream.Close();
    }
    var upload_response = (FtpWebResponse)upload_request.GetResponse();
    fileSaved = true;
}

Your current program reads it as a very long string in UTF-8 encoding, which probably accounts for the change in file size.



回答2:

Why all this dance decoding a file then re-encoding it? You've got two streams right? You want the same file you have on disk to exist on the server? Stream.CopyTo would be considerably less error prone.

You could replace

                StreamReader attachment = new StreamReader(fi_attachment.FullName);
                byte[] attachmentData = Encoding.UTF8.GetBytes(attachment.ReadToEnd());
                upload_request.ContentLength = attachmentData.Length;

                //Stream upload_request_stream = upload_request.GetRequestStream();
                using (Stream upload_request_stream = upload_request.GetRequestStream())
                {
                    upload_request_stream.Write(attachmentData, 0, attachmentData.Length);
                    upload_request_stream.Close();
                }

with (off the top of my head)

using (var fs = File.OpenRead(fi_attachment.FullName))
using (Stream upload_request_stream = upload_request.GetRequestStream())
{
    fs.CopyTo(upload_request_stream);
}