FTP서버에 있는 특정 폴더에 생성되는 파일을 로컬에 동기화하는 기능이 필요하여 구현하였다.
해당 기능은 FTP 서버와 연결이 끊어졌다 다시 연결되었을때 이어받을 수 있는 코드이며 시퀀스는 다음과 같다.
1. FTP 서버의 타겟 폴더의 파일리스트 가져오기
2. 다운로드 카운트를 통해 몇개의 파일을 진행했는지 기록
3. 서버와 연결이 끊겼다가 재연결됐을때 로컬의 마지막 다운로드 받은 파일이 FTP서버의 파일과 같은지(file size)체크하여 다르면 이어받도록한다.
//전체 코드중 file download에 대한 코드
private void DownloadFiles(List<string> fileList, FTPStatus ftpState)
{
//파일리스트에 있는것 전부
while (ftpState.DownloadCount < fileList.Count )
{
if (MainWindow.Instance.FTPStatus.isStop)
{
break;
}
//파일 이어받기 위해서는 FTP서버와 연결이 끊어졌을때 close 처리 해주어야함 (바로 using을 사용하지 않은 이유)
FileStream outputStream = null;
FtpWebResponse response = null;
Stream responseStream = null;
if (!isConnect) // isConnect ftp연결 상태에 대한 전역변수
{
try
{
//FTP 서버 파일
long ftpFileSize = 0;
//{ftpState.Server}{ftpState.TargetFolderPath} ftp서버의 파일이 존재하는 폴더 경로
FtpWebRequest request = CreateFtpWebRequest($"{ftpState.Server}{ftpState.TargetFolderPath}/{fileList[ftpState.DownloadCount-1]}");
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.Timeout = 1000;
request.ReadWriteTimeout = 3000;
request.UsePassive = true;
using (response = (FtpWebResponse)request.GetResponse())
using (responseStream = response.GetResponseStream())
{
ftpFileSize = response.ContentLength;
Console.WriteLine($"받을 파일 크기: { ftpFileSize} bytes");
}
//다운받은 파일
string localFilePath = ftpState.LocalPath + "\\" + fileList[ftpState.DownloadCount-1];
// 로컬 파일 정보 가져오기
FileInfo fileInfo = new FileInfo(localFilePath);
if (fileInfo.Exists)
{
// 파일이 존재하면 크기 가져오기
ftpState.LastSize = fileInfo.Length;
Console.WriteLine($"이전에 받은 파일 크기: { ftpState.LastSize} bytes");
}
if (ftpFileSize == ftpState.LastSize)
{
ftpState.LastSize = 0;
ftpState.DownloadCount += 1;
isConnect = true;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error downloading file: {ex.ToString()}");
}
}
else
{
}
try
{
string localFilePath = ftpState.LocalPath + "\\" + fileList[ftpState.DownloadCount-1]; //fileList ex) 00001_S00001_240108
if (ftpState.LastSize != 0)
{
outputStream = new FileStream(localFilePath, FileMode.Append, FileAccess.Write);
}
else
{
outputStream = new FileStream(localFilePath, FileMode.Create);
}
FtpWebRequest request = CreateFtpWebRequest($"{ftpState.Server}{ftpState.TargetFolderPath}/{fileList[ftpState.DownloadCount-1]}");
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Timeout = 1000;
request.ReadWriteTimeout = 3000;
request.UsePassive = true;
request.ContentOffset = ftpState.LastSize;
response = (FtpWebResponse)request.GetResponse();
responseStream = response.GetResponseStream();
Console.WriteLine(localFilePath);
int bufferSize = 99999;
int readCount;
byte[] buffer = new byte[bufferSize];
Stopwatch sw = new Stopwatch();
sw.Start();
do
{
readCount = responseStream.Read(buffer, 0, bufferSize);
if(readCount > 0) outputStream.Write(buffer, 0, readCount);
} while (readCount > 0);
sw.Stop();
TimeSpan elapsedTime = sw.Elapsed;
responseStream.Close();
response.Close();
outputStream.Close();
MainWindow.Instance.TitlebarObj.SetFTPSpeed(new System.IO.FileInfo(localFilePath).Length / elapsedTime.TotalSeconds / 1024);
ftpState.DownloadCount += 1;
while (checkingMission != MainWindow.Instance._SceneID && !MainWindow.Instance.FTPStatus.isMissionEnd)
{
Thread.Sleep(300);
}
}
catch (Exception ex)
{
//FTP서버와 연결이 끊겨 예외처리 되어도 이어받을 수 있도록
isconnect = false;
Console.WriteLine($"Error downloading file: {ex.ToString()}");
outputStream.Close();
responseStream.Close();
response.Close();
}
}
}