I am trying to use a GZipStream to compress a document prior to uploading to an FTP server. If I save the compressed file stream to disk just prior to uploading, the copy on the local file system is correct. However, when I try to unzip the file on the FTP server I get a 'File is broken' error from 7zip. The resultant unzipped file is correct until the last few characters when a sequence of characters is repeated. I have tried many different configurations to no avail.
public static void FTPPut_Compressed(string fileContents, string ftpPutPath)
{
using (var inStream = new System.IO.MemoryStream(System.Text.Encoding.Default.GetBytes(fileContents)))
{
inStream.Seek(0, SeekOrigin.Begin);
using (var outStream = new System.IO.MemoryStream())
{
using (var zipStream = new GZipStream(outStream, CompressionMode.Compress))
{
inStream.CopyTo(zipStream);
outStream.Seek(0, SeekOrigin.Begin);
FTPPut(ftpPutPath, outStream.ToArray());
}
}
}
}
private static void FTPPut(string ftpPutPath, byte[] fileContents)
{
FtpWebRequest request;
request = WebRequest.Create(new Uri(string.Format(@"ftp://{0}/{1}", Constants.FTPServerAddress, ftpPutPath))) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
request.Credentials = new NetworkCredential(Constants.FTPUserName, Constants.FTPPassword);
request.ContentLength = fileContents.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
requestStream.Flush();
}
}
Ex of corrupted output:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfCreateRMACriteria xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CreateRMACriteria>
<RepairOrderId xsi:nil="true" />
<RMANumber>11-11111</RMANumber>
<CustomerId>1111</CustomerId>
</CreateRMACriteria>
</ArrayOfCreateRMACriteriafriafriafriafriafriafriafriafriafriafriafriafriafriafriafriafriafria
<!-- missing '></xml>' -->
You're not closing (and therefore flushing) the zip stream until after you've uploaded it. I suspect that may well be the problem. Move this line to after the using
statement that creates/uses/closes the GZipStream
:
FTPPut(ftpPutPath, outStream.ToArray());
... and get rid of the Seek
call entirely. ToArray
doesn't require it, and there's no suitable point in your code to call it. (If you call it before you flush and close the GZipStream
, it will corrept the data; if you call it afterwards it'll fail as the MemoryStream
is closed.) As an aside, when you do need to rewind a stream, I'd recommend using stream.Position = 0;
as a simpler alternative.
See more on this question at Stackoverflow