Our Products:   CompleteFTP  edtFTPnet/Free  edtFTPnet/PRO  edtFTPj/Free  edtFTPj/PRO
0 votes
3.3k views
in .NET FTP by (320 points)
I am using edtFTPnet Free version (and have been using it successfully for quite while). I have encountered an exception.
I am copying files from one FTP server to a second (different) FTP server. I am using the DownloadStream and UploadStream methods of the ftp connection object. It works well for small files. I have successfully queued up a number of small files to transfer in succession from one server to the other.

But when I tried to transfer a large (400 MB) file I am getting a System.OutOfMemoryException. I have successfully copied this file from the FTP server to my hard drive with no errors using the DownloadFile method.

Here is the entire exception message -
Execption of type 'System.OutOfMemoryException' was thrown.
at EnterpriseDT.Net.Ftp.FTPClient.GetBinary(Stream destStream, String remoteFile)
at EnterpriseDT.Net.Ftp.FTPClient.Get(Stream destStream, String remoteFile)
at EnterprisDT.Net.Ftp.FTPConnection.DownloadStream(Stream destStream, String remoteFile)
at MediaManager.CopyToFTP.FTPDownloadStream(Int32 index, Int32 numFiles)

Where MediaManager is my application and the FTPDownloadStream is a method that wraps the EDTFTP FTPConnection object Download Stream method.

I know that the system.OutOfMemory exception is not specifically an FTP error but it is indirectly caused by a method in the FTPconnection object. Is there a way that I can somehow monitor the Download Stream method to make sure that I am not running out of memory.

I suppose as a last resort I could copy the file from the server to my HD using DownloadFile method and then upload it to the destination server using UploadFile method but I would like to avoid having to do 2 transfers.

Here is the code I am using to implement the DownloadStream and UploadStream methods. The first method FTPDownloadStream is spun off in a new thread -
private void FTPDownloadStream(int index, int numFiles)
{
string fileName = RemoteFiles[index];
string serverDir = _ftpDestinationConnection.ServerDirectory;
bool fileExists = _ftpDestinationConnection.Exists(serverDir + fileName);
if(fileExists)
{
_ftpDestinationConnection.DeleteFile(serverDir + fileName);
}


_ftpSourceConnection.CloseStreamAfterTransfer = false;
_ftpMemoryStream = new MemoryStream();

try
{
_ftpSourceConnection.DownloadStream(_ftpMemoryStream, RemoteFiles[index]);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message + " " + ex.StackTrace);
}

_ftpMemoryStream.Seek(0, SeekOrigin.Begin);
}



And this method is the callback for the above method which is executed when the above method finishes

private void FTPDownloadStreamCallback(IAsyncResult iar)
{
_ftpStreamToStream = new FTPStreamToStreamTransferDelegate(FTPStreamToStream);
_ftpStreamToStream.BeginInvoke(RemoteFiles[_index], new AsyncCallback(FTPStreamToStreamCallback, null);
}

Which launches this method
private void FTPStreamToStream(string fileName)
{
_ftpDestinationConnection.UplaodStream(_ftpMemoryStream, fileName, true);
}

and this is the callback for the above function
private void FTPStreamToStreamCallback(IAsyncResult iar)
{
if(_index < RemoteFiles.Length - 1)
{
_index++;
_ftpDownloadStream = new FtPDownloadStreamDelegate(FTPDownloadStream);
_ftpDownloadStream.BeginInvoke(_index, RemoteFiles.Length, new AsyncCallback(FTPDownloadStreamCallback), null);
}
else
{
// we're done
_index = 0;
}
}

Thanks,
Ira Idelson

1 Answer

0 votes
by (162k points)
In effect you are downloading the entire file to memory, which is why you run out of memory for larger files. You may as well download to a temporary file.

The other alternative is to use FXP if that is supported by both servers. That isn't supported in edtFTPnet, but it isn't that hard to implement if you understand FTP. Alternatively, it is supported in edtFTPnet/PRO.

Categories

...