Я создаю прототип утилиты ftp, которая сохранит прогресс пользователя и повторно загрузит заданный файл с того места, где он начал, если его интернет отключится. (Это для клиентов с более медленными соединениями).
Идея состоит в том, чтобы открыть поток файлов и поток ftp и записать в поток ftp куски памяти. Если возникает исключение (то есть IOException от разъединения), то число байтов, записанных на ftp-сервер, будет сохранено в файле журнала и прочитано при запуске.
Этот код прекрасно работает, если транзакция отменена, но если клиент должен отключиться, то поток ftp никогда не очищается на стороне сервера - поэтому я получаю ...
Удаленный сервер возвратил ошибку: (550) Файл недоступен (например, файл не найден, нет доступа).
При повторном запросе потока ftp для данного файла. Код выглядит как
//Create FTP Web Request
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(builder.ToString()));
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
reqFTP.UsePassive = true;
reqFTP.UseBinary = false;
reqFTP.KeepAlive = false;
reqFTP.ContentLength = fileInf.Length;
reqFTP.ReadWriteTimeout = 5000;
reqFTP.Timeout = 5000;
using (ProgressDialog progressDialog = new ProgressDialog())
{
progressDialog.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
progressDialog.backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
progressDialog.backgroundWorker1.FileName = filename;
progressDialog.ShowDialog();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
FTPBackgroundWorker worker = sender as FTPBackgroundWorker;
//Get file progress (if user canceled or crashed)
worker.NumBytesRead = GetFileProgress(worker.FileName);
reqFTP.ContentOffset = worker.NumBytesRead;
const int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
using (worker.FileStream = fileInf.OpenRead())
{
worker.FileStream.Position = worker.NumBytesRead;
worker.FTPStream = reqFTP.GetRequestStream(); //Exception occurs
while (true)
{
bool throwException = false;
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
contentLen = worker.FileStream.Read(buff, 0, buffLength);
if (contentLen == 0)
break;
//write file to ftp stream
worker.FTPStream.Write(buff, 0, contentLen);
worker.NumBytesRead += contentLen;
//For testing purposes
if (throwException)
throw new Exception("user disconnected!");
worker.ReportProgress((int)(((double)worker.NumBytesRead / fileInf.Length) * 100));
}
worker.FileStream.Close();
worker.FTPStream.Close();
}
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
FTPBackgroundWorker worker = sender as FTPBackgroundWorker;
if (e.Error != null)
{
MessageBox.Show(String.Format("Error occured uploading {0}: {1}",worker.FileName, e.Error), "Error");
if (worker.FileStream != null)
worker.FileStream.Close();
if (worker.FTPStream != null)
worker.FTPStream.Close();
if(worker.NumBytesRead > 0)
{
MessageBox.Show("Progress has been saved", "Notification");
WriteToLogFile(worker.FileName, worker.NumBytesRead);
}
}
else if (e.Cancelled)
{
if (worker.FileStream != null)
worker.FileStream.Close();
if (worker.FTPStream != null)
worker.FTPStream.Close();
MessageBox.Show("Upload Canceled", "Cancel");
if (worker.NumBytesRead > 0 && MessageBox.Show("Would you like to save your upload progress?", "Notification", MessageBoxButtons.YesNo) == DialogResult.Yes)
WriteToLogFile(worker.FileName, worker.NumBytesRead);
}
else
{
RemoveFromLogFile(worker.FileName);
MessageBox.Show("Upload Complete", "Success");
}
}
Мой вопрос: есть ли способ проверить, есть ли дескриптор на стороне сервера, который не отпускает путь к файлу и удаляет его? Или я подхожу к проблеме с неправильной методологией?
Спасибо