'파일복사'에 해당되는 글 1건

  1. 2017.12.18 C# Winform 파일 복사시 프로그레스바 표시하기
개발팁2017. 12. 18. 13:10

C# 에서 파일을 복사하는 방법은

 

간단하게,

 

System.IO.File.Copy 메서드를 이용하는 방법이다.

 

System.IO.File.Copy( source_file_nm, target_file_nm, is_overwrite);

 

단순하면서도, 적절한 Exception 처리만 해준다면, 아주 강력하다.

 

하지만, 한줄의 명령어로, Synchronous 작업이기 때문에, 파일이 복사 되는 동안에는 아무것도 하지 못한다.

 

파일이 복사되는 동안에, 진행률을 표시하기 위해서는, 위의 파일 복사 방법이 아닌, 비동기 작업 또는 쓰레드 작업이 필요하다.

 

파일이 복사 되는 동안에, 진행률도 표시해야 하고, 프로그레스바도 움직여줘야 하기 때문이다.

 

위의 방법은 한번에 파일복사 명령을 주고, 진행이 끝나면, 알려주는 방법이라면,

 

아래의 방법은, 우리가 직접 파일 복사를 주도하게 될것이다.

 

복사할 source_file_nm 의 경로에서 파일을 조금씩(buffer) 읽어서,  target_file_nm 에다가 write 해주는 방법이며,

 

이것은, loop 를 통해서, 파일의 내용을 모두 복사할때까지, 반복으로 작업을 진행하며,

 

진행하는 중간에 진행률과, 프로그레스바를 같이 움직여 줄것이다.

 

        byte[] buf = new byte[1024 * 512];  // 0.5M

 

        FileInfo file = new FileInfo(source_file_nm);

 

        if (!Directory.Exists(target_path))
                Directory.CreateDirectory(target_path);

 

        FileStream strIn = new FileStream(source_file_nm, FileMode.Open);
        FileStream strOut = new FileStream(Path.Combine(target_path, target_file_nm), FileMode.Create); 

 

 

버퍼를 0.5M 로 했으나, 1M로 해도 상관이 없다.

 

source 파일을 읽기용으로 Open 하고, target 파일을 쓰기용으로 Open 했다.

 

                while (strIn.Position < strIn.Length)
                {
                        int len = strIn.Read(buf, 0, buf.Length);
                        strOut.Write(buf, 0, len);
                }

 

                strOut.Flush();

                strIn.Close();
                strOut.Close();

 

source 를 버퍼로 (0.5M씩) 읽어서, target 파일에다 쓰기를 하고, 완료가 되면, 스트림을 모두 닫아준다.

 

이렇게 하면, 버퍼로 읽어서, 파일에 쓰는 작업은 완료가 되었다.

 

이제, 작업 중간에, 진행률과 프로그레스 바를 움직일 것이다.

 

진행률 표시를 위해 Label 을 하나 만들고, ProgressBar 를 하나 만들어 준다.

 

그리고, 아래와 같이 미리 설정을 해둔다.

 

progressBar.Maximum = Int32.MaxValue;


 

        byte[] buf = new byte[1024 * 512];  // 0.5M

        FileInfo file = new FileInfo(source_file_nm);

 

        if (!Directory.Exists(target_path))
                Directory.CreateDirectory(target_path);

 

        FileStream strIn = new FileStream(source_file_nm, FileMode.Open);
        FileStream strOut = new FileStream(Path.Combine(target_path, target_file_nm), FileMode.Create);

 

        try
        {
                while (strIn.Position < strIn.Length)
                {
                        int len = strIn.Read(buf, 0, buf.Length);
                        strOut.Write(buf, 0, len);

 

                        progressBar.Value = (int)(Int32.MaxValue * strIn.Position / strIn.Length);

                        this.lblBytes.Text = string.Format("{0:N0} / {1:N0}", strIn.Position, strIn.Length);
                }
        }
        catch (Exception ex)
        {
                MessageBox.Show("Error Occured : " + ex.Message, "Error");
                this.DialogResult = System.Windows.Forms.DialogResult.Abort;
        }
        finally
        {
                strOut.Flush();

                strIn.Close();
                strOut.Close();
        }

 

 

이렇게 버퍼로 복사하는 중간에 진행률과 프로그레스바를 표시하도록 수정했다.

그러나, 실제 파일이 복사되는 과정에서, 복사과 완료될동안, 응답없음 상태로 나왔다가, 파일 복사가 끝나야 결과가 나올 것이다.

 

위 작업을 쓰레드로 처리하거나, 백그라운드워커로 실행해줘야 한다.

 

BackgroundWorker 객체를 하나 만들고, 아래와 같이 이벤트 처리를 해준다.

 

this.bg_filecopy = new BackgroundWorker();
this.bg_filecopy.WorkerSupportsCancellation = true;
this.bg_filecopy.DoWork += new DoWorkEventHandler(bg_filecopy_DoWork);
this.bg_filecopy.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_filecopy_RunWorkerCompleted);

위에서 만들어준 코드는 bg_filecopy_DoWork 메서드 안에 넣어주면 된다.

 

이로써, 파일이 복사되는 중간에 상태표시가 되는것을 확인할 수 있다.

하지만, 뭔가 이상한 점이 있다.

 

위에서 만들어준 byte 버퍼를 사용하였지만, 실제 시스템에서는 또다른 버퍼가 있다는 것이다.

 

위에서 마지막 Flush 는 버퍼에 있는것을 모두 파일로 쓸 것이다.

하지만, Loop 안에 strOut.Write(buf, 0, len); 가 있지만, 시스템은 계속 버퍼에 쌓아두었다가 일정 시점 이후에 쓰기를 하는 것을 볼 수 있다.

 

따라서, Loop 안에서도 일정 시점마다  Flush 를 하도록 수정하는것이 좋다.

 

 

 

 

 

Posted by 헝개