2009年08月07日

SimpleCopy

SDカードにmp3を入れてナビに刺すと音楽再生出来る機能がゴリラにはあるのですが、何故かファイルのソート方法がPCからSDカードにファイルを転送した順番になるという仕様。windowsは必ずしもアルファベット順でファイル転送が行われるわけではないので、ソートしつつコピーできるソフトをC#で書いてみました。

作っていてハマったのはプログレスバーの表示。BackgroundWorkerを使ってコピーしつつ、どこまでコピーできたかを表示させるようにしたのですが、そのままではプログラスバーが更新されず、すべて処理が終わってから一気に更新されるといった動作になってしまいました。backgroundWorker1_ProgressChangedメソッド内でRefreshメソッドを呼ぶように作っていたのですが、そのあとApplication.DoEvents()を呼ぶのが肝だったようです。

コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;

namespace SimpleCopy
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.folderBrowserDialog1.ShowDialog();
            this.textBox1.Text = this.folderBrowserDialog1.SelectedPath;
            if (this.textBox1.Text.Length > 0)
                if (textBox1.Text[this.textBox1.Text.Length - 1] != Path.DirectorySeparatorChar)
                    this.textBox1.Text += "\\";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.folderBrowserDialog2.ShowDialog();
            this.textBox2.Text = this.folderBrowserDialog2.SelectedPath;
            if (this.textBox2.Text.Length > 0)
                if (textBox2.Text[this.textBox2.Text.Length - 1] != Path.DirectorySeparatorChar)
                    this.textBox2.Text += "\\";
        }

        private void button3_Click(object sender, EventArgs e)
        {
            this.button1.Enabled = false;
            this.button2.Enabled = false;
            this.button3.Enabled = false;
            this.backgroundWorker1.RunWorkerAsync();
        }

        private string MakePath(string path)
        {
            string targetPath = path.Replace(this.textBox1.Text, this.textBox2.Text);
            return targetPath;
        }

        private List<string> GetFileList(string path)
        {
            string[] dirArr = Directory.GetDirectories(path);
            List<string> filePathList = new List<string>();
            filePathList.AddRange(Directory.GetFiles(path));
            foreach (string dirPath in dirArr)
            {
                filePathList.AddRange(this.GetFileList(dirPath));
            }

            return filePathList;
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            if ((this.textBox1.Text != "") && (this.textBox2.Text != ""))
            {
                List<string> fileList = this.GetFileList(this.textBox1.Text);
                fileList.Sort();
                int count =1;
                object[] objArr = new object[3];

                foreach (string path in fileList)
                {
                    string destFilePath = this.MakePath(path);
                    if (!Directory.Exists(Path.GetDirectoryName(destFilePath))) Directory.CreateDirectory(Path.GetDirectoryName(destFilePath));
                    File.Copy(path, destFilePath);
                    objArr[0] = count++;
                    objArr[1] = fileList.Count;
                    objArr[2] = path;
                    this.backgroundWorker1.ReportProgress(0, objArr);
                }
                
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = (int)((object[])e.UserState)[0];
            this.progressBar1.Maximum = (int)((object[])e.UserState)[1];
            this.richTextBox1.Text = (string)((object[])e.UserState)[2];
            this.progressBar1.Refresh();
            this.richTextBox1.Refresh();
            Application.DoEvents();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.button1.Enabled = true;
            this.button2.Enabled = true;
            this.button3.Enabled = true;
            this.richTextBox1.Text = "Complete!";
        }
    }
}