会社での困りごと
仕事上、資料のバックアップを残すことが、頻繁にあります。主な理由は、ファイルのバージョン管理です。
そのやり方は、最新版に手を加える前に、エクスプローラー上でファイルをコピーしたうえで、ファイル名に日付・時刻を入れ、各ファイルの更新日時が分かるようにする、というものです。こんな(↓)感じです。

世の中には、Boxのように、ファイルのバージョン管理を便利に行えるサービスはたくさんあり、活用している人も多いと思います。ただ、この方法にも、利点があります。
- ファイル名を見ただけで、いつ更新したものかが分かる。
- バージョンごとにファイル名が異なるので、区別しやすい(Boxなどでは、同一ファイル名でバージョン管理される)。
- 当たり前ですが、無料。
一方で、この管理方法の面倒な点は、次のように、手順が煩雑なところです。
- 「企画書.docx」をコピー&ペースト([Ctrl]+[C]→[Ctrl]+[V])
- 「企画書 - コピー.docx」という名前のファイルができる。
- そのファイル名の「 - コピー」部分を、日付と時刻に変更する。ファイルの更新日付を確認しながら入力するので、面倒。
一度くらいなら気になりませんが、これを毎日・何度も繰り返すうちに、かなり面倒に感じるようになりました。
また、タイプミスで日付を誤ったりすると、ファイル名で並べた時に更新順序が崩れる点にも、困っていました。
ツールを作って、一瞬でバックアップできるようにした
そこで、ツールを作り、楽をすることにしました。
「企画書_-latest_.docx」のように、ファイル拡張子の直前が「-latest」という名前のファイルであることが条件です。
そのファイルを、エクスプローラー上で、ツールにドラッグ&ドロップすると、自動的にバックアップ&ファイル名更新を行います。
backup.batというバッチファイルがツールで、対象のファイルを、バッチファイルにドラッグ&ドロップするだけです。
バッチファイルの中では、Javaのプログラムを実行しています。

下の図が、実行結果です。
バックアップをワンクリックで実行できるので、便利になりました。

ソースコード
ソースコードは、こんな感じです。Javaとバッチファイルの組み合わせで動きます。
Javaプログラムをコンパイルし、Classファイルとバッチファイルを同じフォルダに置いてください。
実行時は、上の図のように、バックアップしたいファイルを、エクスプローラー上で、バッチファイルにドラッグ&ドロップしてください。対象のファイルと同じフォルダに、バックアップを作ります。
あと自分の場合は、ツール(バッチファイル)のショートカットをデスクトップに作っておき、そのショートカットに対してドラッグ&ドロップするようにしています。
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);
    }
  }
}
@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社のサービス」であるという、間違った記述がありましたので、修正しました。お詫びして訂正します。