FTPClient.Get(stream, filename) always closes the Stream. This is undesirable when working with MemoryStream because the Stream can't be re-used once Close() has been called.
Seeing as the stream is provided by the user, should Stream.Close() really be called by FTPClient.Get() ?
What if the stream was being used to concatenate several remote files?
Alternatively, Close() should not be called on instances of non-persistent streams such as MemoryStream.
C# code...
MemoryStream ms = new MemoryStream();
ftp.Get(ms, getUriPath(filename));
// return to start of stream ready for being read
ms.Seek(0, SeekOrigin.Begin);
xml = new XmlTextReader(ms);
// Exception: "Cannot access a closed Stream"
I have an application that has to be able to read file contents from a variety of sources, based on the filename URI given by the user.
I have a set of generic file read/write methods that identify a URI protocol of "filename" and then use FTPClient, HTTPClient, or regular File objects to read the contents of "filename" into a MemoryStream or String.
This allows my application logic to call one of my generic methods and not worry how the underlying file is accessed and retrieved.
E.g.
private MemoryStream fileOpenAsMemoryStream(string filename)
{
MemoryStream ret = new MemoryStream();
URIprotocol proto = getProtocol(filename);
if(this.ftpEnabled && proto == URIprotocol.FTP)
{
try
{
if(ftpConnect()) // ensure FTP connection is up
ftp.Get(ret, getUriPath(filename));
}
catch(Exception e1)
{ Error("FTP fileOpenAsMemoryStream", e1.Message); }
}
else if(proto == URIprotocol.HTTP)
{
}
else if(proto == URIprotocol.FILE || proto == URIprotocol.UNKNOWN)
{
try
{
// open file
FileStream fs = new FileStream(getUriPath(filename), FileMode.Open);
byte[] data = new byte[fs.Length]; // create same-sized array
fs.Read(data, 0, (int)fs.Length); // transfer into memory
fs.Close(); // finished with the file
// write into memory stream
ret.Write(data, 0, data.Length);
}
catch(Exception e2) {}
}
// return to start of stream ready for being read
ret.Seek(0, SeekOrigin.Begin);
return ret;
}
TJ.