Edited at

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


会社での困りごと

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

そのやり方は、最新版に手を加える前に、エクスプローラー上でファイルをコピーしたうえで、ファイル名に日付・時刻を入れ、各ファイルの更新日時が分かるようにする、というものです。こんな(↓)感じです。

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


  • ファイル名を見ただけで、いつ更新したものかが分かる。

  • バージョンごとにファイル名が異なるので、区別しやすい(Boxなどでは、同一ファイル名でバージョン管理される)。


  • 当たり前ですが、無料

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


  1. 「企画書.docx」をコピー&ペースト([Ctrl]+[C][Ctrl]+[V]

  2. 「企画書 - コピー.docx」という名前のファイルができる。

  3. そのファイル名の「 - コピー」部分を、日付と時刻に変更する。ファイルの更新日付を確認しながら入力するので、面倒。

一度くらいなら気になりませんが、これを毎日・何度も繰り返すうちに、かなり面倒に感じるようになりました。

また、タイプミスで日付を誤ったりすると、ファイル名で並べた時に更新順序が崩れる点にも、困っていました。


ツールを作って、一瞬でバックアップできるようにした

そこで、ツールを作り、楽をすることにしました。

「企画書-latest.docx」のように、ファイル拡張子の直前が「-latest」という名前のファイルであることが条件です。

そのファイルを、エクスプローラー上で、ツールにドラッグ&ドロップすると、自動的にバックアップ&ファイル名更新を行います。

backup.batというバッチファイルがツールで、対象のファイルを、バッチファイルにドラッグ&ドロップするだけです。

バッチファイルの中では、Javaのプログラムを実行しています。

下の図が、実行結果です。

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


ソースコード

ソースコードは、こんな感じです。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社のサービス」であるという、間違った記述がありましたので、修正しました。お詫びして訂正します。