다음 두 함수는 동일한 내용을 동기버전과 비동기버전으로 구현한 코드이다.
동기버전
static long CopySync(string FromPath, string ToPath)
{
using(var fromStream = new FileStream(FromPath,FileMode.Open))
{
long totalCopied = 0;
using(var toStream = new FileStream(ToPath,FileMode.Create))
{
byte[] buffer = new byte[1024];
int nRead = 0;
while((nRead = fromStream.Read(buffer, 0, buffer.Length)) != 0)
{
toStream.Write(buffer,0, nRead);
totalCopied += nRead;
}
}
return totalCopied;
}
}
비동기버전
async Task<long> CopySync(string FromPath, string ToPath)
{
using (var fromStream = new FileStream(FromPath, FileMode.Open))
{
long totalCopied = 0;
using (var toStream = new FileStream(ToPath, FileMode.Create))
{
byte[] buffer = new byte[1024];
int nRead = 0;
while ((nRead = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await toStream.WriteAsync(buffer, 0, nRead);
totalCopied += nRead;
}
}
return totalCopied;
}
}
1.FileStream.Read 이 메서드의 형태는 다음과 같다.
public virtual int Read(byte[] buffer, int offset, int count);
-> buffer : 읽은 데이터를 저장할 배열
-> offset : 저장을 시작할 숫자 (EX: 0이면 0부터 저장함)
-> count : 읽을 최대 바이트 수
-> 반환값 : 읽은 바이트 수
2.FileStream.Write 이 메서드의 형태는 다음과 같다.
public virtual void Write(byte[] buffer, int offset, int count);
-> buffer : 데이터를 저장한 배열
-> offset : 쓰기 시작할 숫자 (EX: 0이면 0부터 씀)
-> count : 쓸 바이트 수
3.두 메서드는 파일을 복사하고, 복사를 마친 뒤에는 파일의 크기를 반환한다.
4.동기버전은 메서드가 호출되면 실행이 종료될 때까지 사용자 인터페이스가 응답을 못하지만
비동기버전은 응답을 한다.
5. 위 두 메서드를 이용해서 실습을 해보았다. 소스코드는 아래와 같다.
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Asyncfile
{
public partial class Form1 : Form
{
long CopySync(string FromPath, string ToPath)
{
SyncCopy.Enabled = false;
long totalCopied = 0;
using (var fromStream = new FileStream(FromPath, FileMode.Open))
{
using (var toStream = new FileStream(ToPath, FileMode.Create))
{
byte[] buffer = new byte[1024];
int nRead = 0;
while ((nRead = fromStream.Read(buffer, 0, buffer.Length)) != 0)
{
toStream.Write(buffer, 0, nRead);
totalCopied += nRead;
pbCopy.Value = (int)(((double)totalCopied/(double)fromStream.Length)*pbCopy.Maximum);
}
}
SyncCopy.Enabled = true;
return totalCopied;
}
}
async Task<long> CopyAsync(string FromPath, string ToPath)
{
AsyncCopy.Enabled = false;
using (var fromStream = new FileStream(FromPath, FileMode.Open))
{
long totalCopied = 0;
using (var toStream = new FileStream(ToPath, FileMode.Create))
{
byte[] buffer = new byte[1024];
int nRead = 0;
while ((nRead = await fromStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await toStream.WriteAsync(buffer, 0, nRead);
totalCopied += nRead;
pbCopy.Value = (int)(((double)totalCopied / (double)fromStream.Length) * pbCopy.Maximum);
}
}
AsyncCopy.Enabled = true;
return totalCopied;
}
}
public Form1()
{
InitializeComponent();
}
private void btnFindSource_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if(dlg.ShowDialog() == DialogResult.OK )
{
txtSource.Text = dlg.FileName;
}
}
private void btnFindTarget_Click(object sender, EventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
if (dlg.ShowDialog() == DialogResult.OK)
{
txtTarget.Text = dlg.FileName;
}
}
private async void AsyncCopy_Click(object sender, EventArgs e)
{
long totalCopied = await CopyAsync(txtSource.Text,txtTarget.Text);
}
private void SyncCopy_Click(object sender, EventArgs e)
{
long totalCopied = CopySync(txtSource.Text, txtTarget.Text);
}
private void Cancel_Click(object sender, EventArgs e)
{
MessageBox.Show("UI 반응 테스트 성공");
}
private void button1_Click(object sender, EventArgs e)
{
pbCopy.Value = 0;
}
}
}
동기로 파일을 복사하면 Cancel이 반응을 잘 하지 못하고 비동기로 파일을 복사하면 Cancel이 잘 반응한다.
좋은 글 감사합니다!