0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ファイルが更新される度に自動でバックアップを保存する Windows アプリケーションを公開してみる

Last updated at Posted at 2024-07-03

ファイルのバックアップを自動で保存する
Windows アプリケーションを作成したため
皆さんの役に立てればと思い
ソースと本体を公開したいと思います。

かなり便利なアプリケーションである自信があるため
是非活用頂けると嬉しいです。

本体はこちら(BOOTH)
本体はこちら(Google Drive)

<利用規約>
・自作発言のみ禁止とさせて下さい。
 禁止内容には我々に対し著作権を主張する事を含みます。
・再配布・販売 OK です。
・加工後の再配布・販売も OK です。
・再配布・販売の際に
 独自のライセンスを付与する事も許可します。
 ただし自作発言禁止のルールに関してのみ
 反しないようにお願いします。
・自作発言をしないならば
 アプリケーション名を変えて
 再配布・販売をして頂いてもかまいません。

<免責事項>
当アプリケーションのダウンロード、およびご利用に伴い発生した事象については責任を負いかねます。ご利用は自己責任でお願いします。

<クレジット表記について>
特に必要ありません。気軽にお使いください。


このアプリケーションの説明

「バックアップ対象」にフォルダを指定すると
その中のファイルの更新があった場合に
自動でバックアップを保存します。

例えば Folder フォルダの中に
index.php があったとすると
Folder フォルダをバックアップ対象に指定しておけば
index.php が更新された時に
自動でバックアップファイルが生成されます。

バックアップファイルの書式は
更新日_ファイル名.zip です。
例えば 20240401-123021_index.php.zip のような
ファイル名になります。

FolderA フォルダを
バックアップ対象にしている場合は
FolderA フォルダと同じ場所に
FolderA_BackUP フォルダが生成されて
その中にバックアップが生成されます。

index.php ファイルを
バックアップ対象にしている場合は
index.php ファイルと同じ場所に
index_BackUP フォルダが生成されて
その中にバックアップが生成されます。

バックアップ対象のフォルダの中に
フォルダがあるならば
そのフォルダもバックアップ対象です。
つまり子要素孫要素が対象になります。

ファイルをドラッグ&ドロップする事で
ファイルをバックアップ対象にする事もできます。

バックアップファイルの
容量が膨れすぎないように
4 作業日以上前の古いバックアップファイルは
アプリを起動したタイミングで
自動的に一部削除されます。
(各ファイルのその日最後に編集した内容だけが残ります)
(これは v2.0.0 で追加された機能です)

仮に実行時にエラーが出たとしても
バックアップ対象のフォルダ内のデータが
書き換えられることは決してありません。
バックアップフォルダのみを触ります。
安心してご利用下さい。

活用出来そうな場面:
・Excel Word の編集作業
・Unity の Assets フォルダ
・容量の少ないイラストレーターのファイル
・html の作成作業
・動画編集作業
・プログラミング作業
・その他様々な場面で活躍出来ると思います。

PC 起動時のスタートアップアプリケーションに
このアプリケーションを設定する事で
バックアップを完全自動化する事ができます。

あくまでもファイルが保存されている場合に
バックアップを定期的に実行するだけなので
ファイルを保存する機能自体はありません。
Ctrl + S など保存自体は
手動で行う必要があります。

1 ファイルが 1GB 程度の大容量の場合は
ファイルのバックアップを自動で保存する Windows アプリケーションを公開してみる
の方をご利用下さい。
そちらは保存するファイル数の上限と
保存間隔を決める事が出来ます。


このアプリケーションのソースコード

v2.2.0 のプロジェクトは下記の URL からダウンロード頂けます。
Visual Studio で開く事ができます。
SephirothAutoBackUP ver2.2.0 プロジェクトファイル

v3.0.2 のプロジェクトは下記の URL からダウンロード頂けます。
Visual Studio で開く事ができます。
SephirothAutoBackUP v3.0.2 プロジェクトファイル

Visual Studio の Windows フォームで作成しています。
v1.6.1 のソースコードは下記の内容です。
(最新版の v3.0.2 はコードが長いため、ここには載せません)
(v3.0.2 のコードが知りたい方は上記 URL からダウンロードして下さい)

使用したコード
using System.IO;
using System.IO.Compression;

namespace SephirothAutoBackUP
{
    public partial class Form1 : Form
    {
        private bool isExecuteing = false;

        delegate void SetLabelDelegate();

        public Form1()
        {
            InitializeComponent();

            if (!File.Exists(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\NumText.txt"))
            {
                File.WriteAllText(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\NumText.txt", "1");
            }
            textBox1.Text = File.ReadAllText(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\NumText.txt");
        }

        private void panel1_DragDrop(object sender, DragEventArgs e)
        {
            if (isExecuteing)
            {
                MessageBox.Show(
                    "現在既に監視中のためドラック&ドロップできません。。他のフォルダを監視したい場合はアプリを再起動して下さい。", "確認",
                    MessageBoxButtons.OK, MessageBoxIcon.Question
                    );
                return;
            }
            if (e.Data == null)
            {
                return;
            }
            object? data = e.Data.GetData(DataFormats.FileDrop, false);
            if (data == null)
            {
                return;
            }

            string[] files1 = (string[])data;

            if (files1.Length != 1)
            {
                string show = string.Join('\n', files1) + "\nを監視中です。";

                label1.Text = show;
            }
            else
            {
                string fileKindString = "フォルダ";

                if (System.IO.File.Exists(files1[0]))
                {
                    if (!files1[0].Substring(files1[0].LastIndexOf("\\") + 1).Contains("."))
                    {
                        MessageBox.Show(
                        "拡張子のないファイルは登録できません。", "確認",
                        MessageBoxButtons.OK, MessageBoxIcon.Question
                        );
                        return;
                    }

                    if (files1[0].Substring(files1[0].LastIndexOf("\\") + 1).StartsWith("."))
                    {
                        MessageBox.Show(
                        "コンマから始まるファイルは登録できません。", "確認",
                        MessageBoxButtons.OK, MessageBoxIcon.Question
                        );
                        return;
                    }

                    fileKindString = "ファイル";
                }

                label1.Text = files1[0] + fileKindString + "を監視中です。監視を終了する場合はアプリケーションを終了して下さい。";
            }

            File.WriteAllText(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\OldPath.txt", string.Join('\n', files1));

            isExecuteing = true;

            Task.Run(() => Execute(files1));

            button1.Enabled = false;
        }

        private void Execute(string[] files)
        {
            try
            {
                while(true)
                {
                    ExecuteOneTime(files);
                    Thread.Sleep(int.Parse(textBox1.Text) * 1000);
                }
            }
            catch
            {
                Invoke(new SetLabelDelegate(SetLabel));
                isExecuteing = false;
            }
        }

        private void ExecuteOneTime(string[] files)
        {
            foreach(string file in files)
            {
                if (System.IO.File.Exists(file))
                {
                    string fileName = file.Substring(file.LastIndexOf("\\") + 1);
                    string zipFileName = file.Substring(0, file.LastIndexOf("\\") + 1) + System.IO.File.GetLastWriteTime(file).ToString("yyyyMMdd-HHmmss") + "_" + fileName + ".zip";

                    if (!System.IO.File.Exists(zipFileName))
                    {

                        bool isCreateFolder = false;

                        string oneTimeDirectoryName = file.Substring(0, file.LastIndexOf("."));
                        if (!System.IO.Directory.Exists(oneTimeDirectoryName))
                        {
                            isCreateFolder = true;
                            System.IO.Directory.CreateDirectory(oneTimeDirectoryName);
                        }
                        System.IO.File.Copy(file, oneTimeDirectoryName + "\\" + fileName);
                        ZipFile.CreateFromDirectory(oneTimeDirectoryName, zipFileName);
                        if (isCreateFolder)
                        {
                            System.IO.File.Delete(oneTimeDirectoryName + "\\" + fileName);
                            System.IO.Directory.Delete(oneTimeDirectoryName);
                        }
                    }

                    return;
                }
                foreach (string oneFilePath in System.IO.Directory.GetFiles(file, "*", SearchOption.AllDirectories))
                {
                    if (oneFilePath.EndsWith(".zip"))
                    {
                        continue;
                    }

                    string fileName = oneFilePath.Substring(oneFilePath.LastIndexOf("\\") + 1);

                    if (!fileName.Contains("."))
                    {
                        continue;
                    }

                    if (fileName.StartsWith(".") || fileName.StartsWith("~"))
                    {
                        continue;
                    }

                    string folderPath = file + "_BackUP";
                    string[] pathMove = oneFilePath.Substring(file.Length + 1).Split("\\");

                    for (int i = 0; i < pathMove.Length - 1; i++)
                    {
                        folderPath = folderPath + "\\" + pathMove[i];
                        if (System.IO.Directory.Exists(folderPath))
                        {
                            System.IO.Directory.CreateDirectory(folderPath);
                        }
                    }

                    string zipFileName = folderPath + "\\" + System.IO.File.GetLastWriteTime(oneFilePath).ToString("yyyyMMdd-HHmmss") + "_" + fileName + ".zip";

                    if (!System.IO.File.Exists(zipFileName))
                    {

                        bool isCreateFolder = false;

                        string oneTimeDirectoryName = folderPath + "\\" + fileName.Substring(0, fileName.LastIndexOf("."));
                        if (!System.IO.Directory.Exists(oneTimeDirectoryName))
                        {
                            isCreateFolder = true;
                            System.IO.Directory.CreateDirectory(oneTimeDirectoryName);
                        }
                        System.IO.File.Copy(oneFilePath, oneTimeDirectoryName + "\\" + fileName);
                        ZipFile.CreateFromDirectory(oneTimeDirectoryName, zipFileName);
                        if (isCreateFolder)
                        {
                            System.IO.File.Delete(oneTimeDirectoryName + "\\" + fileName);
                            System.IO.Directory.Delete(oneTimeDirectoryName);
                        }
                    }
                }
            }
        }

        private void SetLabel()
        {
            label1.Text = "エラーが発生したため監視を終了します。";
        }

        private void panel1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data == null)
            {
                return;
            }
            if (e.Data.GetDataPresent(DataFormats.FileDrop) && !isExecuteing)
            {
                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            try
            {
                File.WriteAllText(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\NumText.txt", "" + int.Parse(textBox1.Text));
            }
            catch
            {
                textBox1.Text = File.ReadAllText(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\NumText.txt");
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if(isExecuteing)
            {
                MessageBox.Show(
                "既に監視中のため実行できませんでした。", "確認",
                MessageBoxButtons.OK, MessageBoxIcon.Question
                );
                return;
            }

            try
            {
                string loadPath = File.ReadAllText(Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\")) + "\\OldPath.txt");

                string[] paths = loadPath.Split("\n");

                foreach(string path in paths)
                {

                    if (!System.IO.Directory.Exists(path) && !System.IO.File.Exists(path))
                    {
                        MessageBox.Show(
                        "前回のパスが存在しなかったため、監視できませんでした。", "確認",
                        MessageBoxButtons.OK, MessageBoxIcon.Question
                        );
                        return;
                    }
                }

                if(paths.Length != 1)
                {
                    string show = string.Join('\n', paths) + "\nを監視中です。";

                    label1.Text = show;
                }
                else
                {
                    string fileKindString = "フォルダ";

                    if (System.IO.File.Exists(paths[0]))
                    {
                        fileKindString = "ファイル";
                    }

                    label1.Text = paths[0] + fileKindString + "を監視中です。監視を終了する場合はアプリケーションを終了して下さい。";
                }

                isExecuteing = true;

                Task.Run(() => Execute(paths));

                button1.Enabled = false;
            }
            catch
            {
                MessageBox.Show(
                "前回のパスが存在しなかったため、監視できませんでした。", "確認",
                MessageBoxButtons.OK, MessageBoxIcon.Question
                );
            }
        }
    }
}

以上 Windows アプリケーションを公開しました。

Visual Studio の Windows フォームは
フォルダ整理をしたい時等に
補助用のアプリケーションを
簡単に作成する事ができます。

皆さんもフォルダ整理の際は
Visual Studio を活用してみては
いかがでしょうか?

皆さんの開発の助けになれますように
閲覧ありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?