仕事で使うファイルを、簡単にバックアップしたい

# 会社での困りごと

仕事上、資料のバックアップを残すことが、頻繁にあります。主な理由は、ファイルのバージョン管理です。

そのやり方は、最新版に手を加える前に、エクスプローラー上でファイルをコピーしたうえで、ファイル名に日付・時刻を入れ、各ファイルの更新日時が分かるようにする、というものです。こんな（↓）感じです。
![pic-20190705T1416.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455014/dd7e5837-54d1-e536-28c3-4fb79a8f7214.png)

世の中には、Boxのように、ファイルのバージョン管理を便利に行えるサービスはたくさんあり、活用している人も多いと思います。ただ、この方法にも、利点があります。

- ファイル名を見ただけで、いつ更新したものかが分かる。
- バージョンごとにファイル名が異なるので、区別しやすい（Boxなどでは、同一ファイル名でバージョン管理される）。
- **当たり前ですが、無料**。

一方で、この管理方法の**面倒な点**は、次のように、手順が煩雑なところです。

1. 「企画書.docx」をコピー＆ペースト（`[Ctrl]+[C]`→`[Ctrl]+[V]`）
1. 「企画書 - コピー.docx」という名前のファイルができる。
1. そのファイル名の「 - コピー」部分を、日付と時刻に変更する。ファイルの更新日付を確認しながら入力するので、面倒。

一度くらいなら気になりませんが、これを毎日・何度も繰り返すうちに、かなり面倒に感じるようになりました。
また、タイプミスで日付を誤ったりすると、ファイル名で並べた時に更新順序が崩れる点にも、困っていました。

# ツールを作って、一瞬でバックアップできるようにした
そこで、ツールを作り、楽をすることにしました。
「企画書_-latest_.docx」のように、ファイル拡張子の直前が「-latest」という名前のファイルであることが条件です。

そのファイルを、エクスプローラー上で、ツールにドラッグ＆ドロップすると、自動的にバックアップ＆ファイル名更新を行います。
`backup.bat`というバッチファイルがツールで、対象のファイルを、バッチファイルにドラッグ＆ドロップするだけです。

バッチファイルの中では、Javaのプログラムを実行しています。
![pic-20190705T1556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455014/c3b801aa-651f-8178-dfbc-c5fb86907342.png)

下の図が、実行結果です。
バックアップをワンクリックで実行できるので、便利になりました。
![pic-20190705T1435.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455014/7bfe4aec-d9f3-ba9f-0057-2e5270dea842.png)

# ソースコード

ソースコードは、こんな感じです。Javaとバッチファイルの組み合わせで動きます。
Javaプログラムをコンパイルし、Classファイルとバッチファイルを同じフォルダに置いてください。

実行時は、上の図のように、バックアップしたいファイルを、エクスプローラー上で、バッチファイルにドラッグ＆ドロップしてください。対象のファイルと同じフォルダに、バックアップを作ります。

あと自分の場合は、ツール（バッチファイル）のショートカットをデスクトップに作っておき、そのショートカットに対してドラッグ＆ドロップするようにしています。

```CopyAndBackupFile.java
import java.net.*;
import java.nio.file.*;
import java.text.*;
import java.util.*;

public class CopyAndBackupFile {
  private static final String DEFAULT_PLACE_HOLDER = "latest";
  private static final SimpleDateFormat FORMAT_PREFIX = new SimpleDateFormat("YYYYMMdd");
  private static final SimpleDateFormat FORMAT_SUFFIX = new SimpleDateFormat("HHmm");

  public static void main(String[] args) throws Exception {
    int argc = 0;
    String placeHolder;
    
    if (args[argc].equals("-p")) {
      placeHolder = args[++argc];
      ++argc;
    } else {
      placeHolder = DEFAULT_PLACE_HOLDER;
    }

    assert placeHolder != null : "Placeholder is null";

    Path[] paths = new Path[args.length - argc];
    for (int i = 0; i < paths.length; i++, argc++) {
      paths[i] = Paths.get(args[argc]);
    }

  rename_loop:
    for (int i = 0; i < paths.length; i++) {
      Path pathOrg = Paths.get(paths[i].toString());
      Path dir = pathOrg.getParent();
      Path file = pathOrg.getFileName();

      String sFile = file.toString();
      
      int phStart = sFile.lastIndexOf(placeHolder);
      if (phStart < 0) {
        System.err.printf("ERROR: %s does not include \"%s\"%n", sFile, placeHolder);
        continue rename_loop;
      }
      int phEnd = phStart + placeHolder.length();
      
      long lastModified = pathOrg.toFile().lastModified();
      Date date = new Date(lastModified);
      
      String backupDate = FORMAT_PREFIX.format(date)
                                       .concat("T")
                                       .concat(FORMAT_SUFFIX.format(date));
      

      String sFileNew = sFile.substring(0, phStart)
                             .concat(backupDate)
                             .concat(sFile.substring(phEnd));
      
      Path pathNew = Paths.get(dir.toString(), sFileNew);
      
      System.out.printf("%s -> %s%n", pathOrg, pathNew);
      Files.copy(pathOrg, pathNew);
    }
  }
}
```

```backup.bat
@echo off
setlocal

rem
rem The top directory of the tool
rem
set __tools_dir=%~d0%~p0
set __last_char=%__tools_dir:~-1%
if "%__last_char%"=="\" set __tools_dir=%__tools_dir:~0,-1%


rem
rem Environment variables
rem
set __java_bin_dir=C:\ProgramData\Oracle\Java\javapath
set __classpath=%__tools_dir%

if "%JAVA_HOME%"=="" (
  echo WARNING: JAVA_HOME is empty. Using %__java_bin_dir%
) else ( 
  set __java_bin_dir=%JAVA_HOME:"=%\bin
)

if not exist "%__java_bin_dir%\java.exe" (
  echo ERROR: %__java_bin_dir%\java.exe does not exist
  echo ERROR: set JAVA_HOME to the top directory of Java SE 7 or later
  goto :EOF
)

set __java_options=


rem 
rem Run
rem
@echo on
"%__java_bin_dir%\java.exe" %__java_options% -classpath "%__classpath%" CopyAndBackupFile %*
@echo off

@endlocal
```

# 記事訂正（2019年7月14日）

「Box」が「Microsoft社のサービス」であるという、間違った記述がありましたので、修正しました。お詫びして訂正します。