退屈なことはRubyにやらせよう ~ファイル整理を自動化する~

# やりたいこと

8桁の日付が含まれている大量のファイルを、日付ごとのディレクトリに分類したい。

これを、、、
<img width="400" alt="Screenshot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499119/aceb5e73-d940-5218-aecc-bab34a3f8301.png">

こうしたい。
<img width="400" alt="Screenshot 1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499119/5fc90fc0-eae2-24d0-a165-2243c272673f.png">
<img width="400" alt="Screenshot 2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499119/54cdcab9-42b1-ac24-2b17-cfaff12e7594.png">


膨大な量あるので。手動でカチカチなんてやってられない！
### 退屈なことはRubyにやらせよう。



# コードと出力結果

```ruby
require "date"
require "fileutils"

# 操作したいファイルの親ディレクトリを絶対パスで指定
PATH = "/Users/xxxx/整理したいビデオたち"
# 操作したいファイルをワイルドカードで指定
PATTERN = ["*.mp4", "*.mov"]

# ファイル名を取得
file_names = Dir.glob(PATTERN, base: PATH)

file_names.each do |file_name|
  # ファイル名から日付を抽出できた場合のみ処理を行う
  if date = file_name.slice(/(19|20)\d\d[01]\d[0-3]\d/)
    # 日付を任意の形式に変換
    dir_name = DateTime.parse(date).strftime("%Y年%-m月%-d日")
    
    # 日付ごとのディレクトリを作成
    Dir.mkdir("#{PATH}/#{dir_name}") if !Dir.exist?("#{PATH}/#{dir_name}")
    # ファイルを移動
    FileUtils.mv("#{PATH}/#{file_name}", "#{PATH}/#{dir_name}/#{file_name}")
    
	# 成功時のメッセージ出力
    puts "「#{file_name}」を「#{dir_name}」フォルダへ移動しました。"
  else
	# エラー時のメッセージ出力
    puts "「#{file_name}」のファイル名に日付が含まれていません。"
  end
end
```

```
% ruby sample.rb
「VID_20150221_124847.mp4」を「2015年2月21日」フォルダへ移動しました。
「VID_20150228_113337.mp4」を「2015年2月28日」フォルダへ移動しました。
「VID_20150228_145755.mp4」を「2015年2月28日」フォルダへ移動しました。
「VID_20150228_150005.mp4」を「2015年2月28日」フォルダへ移動しました。
「VID_20150302_144855.mp4」を「2015年3月2日」フォルダへ移動しました。
「VID_20150302_162343.mp4」を「2015年3月2日」フォルダへ移動しました。
「VID_20150302_172950.mp4」を「2015年3月2日」フォルダへ移動しました。
「VID_20150302_175424.mp4」を「2015年3月2日」フォルダへ移動しました。
「VID_20150311_160326.mp4」を「2015年3月11日」フォルダへ移動しました。
「VID_20150311_160452.mp4」を「2015年3月11日」フォルダへ移動しました。
「VID_20150318_160749.mp4」を「2015年3月18日」フォルダへ移動しました。
「VID_20150318_163331.mp4」を「2015年3月18日」フォルダへ移動しました。
「VID_20150318_163356.mp4」を「2015年3月18日」フォルダへ移動しました。
「VID_20150318_165508.mp4」を「2015年3月18日」フォルダへ移動しました。
「VID_20150404_180851.mp4」を「2015年4月4日」フォルダへ移動しました。
「VID_20150404_181140.mp4」を「2015年4月4日」フォルダへ移動しました。
「VID_20150405_182323.mp4」を「2015年4月5日」フォルダへ移動しました。
「VID_20150405_192210.mp4」を「2015年4月5日」フォルダへ移動しました。
「VID_20150405_202445.mp4」を「2015年4月5日」フォルダへ移動しました。
```

# 説明

## ファイル名を配列に格納する

```ruby
# 操作したいファイルの親ディレクトリを絶対パスで指定
PATH = "/Users/xxxx/整理したいビデオたち"
# 操作したいファイルをワイルドカードで指定
PATTERN = ["*.mp4", "*.mov"]

# ファイル名を取得
file_names = Dir.glob(PATTERN, base: PATH)
```
```ruby
p file_names
# => ["VID_20150221_124847.mp4", "VID_20150228_113337.mp4", "VID_20150228_145755.mp4", "VID_20150228_150005.mp4", "VID_20150302_144855.mp4", "VID_20150302_162343.mp4", "VID_20150302_172950.mp4", "VID_20150311_160326.mp4", "VID_20150311_160452.mp4", "VID_20150318_160749.mp4", "VID_20150318_163331.mp4", "VID_20150318_163356.mp4", "VID_20150318_165508.mp4", "VID_20150404_180851.mp4", "VID_20150404_181140.mp4", "VID_20150405_182323.mp4", "VID_20150405_192210.mp4", "VID_20150405_202445.mp4"]
```

ディレクトリ以下のファイルのファイル名を、配列`file_names`に入れます。
隠しファイル（`.`で始まるファイル。Macだと厄介な`.DS_STORE`など）は入りません。

ワイルドカードは配列なので複数指定可能です。

## 日付の抽出
```ruby
/(19|20)\d\d[01]\d[0-3]\d/

(19|20)\d\d # 1900年から2099年
[01]\d      # 01月から12月
[0-3]\d     # 01日から31日
```

正規表現で、ファイル名から日付を抽出しています。

32日~39日が含まれてしまったりはしますが、個人で使う分にはこのくらいで問題ないかと。

ググるともっと精密なのが色々出てきます。

## 日付の無いファイルがあるときのエラー回避

```ruby
if date = file_name.slice(/(19|20)\d\d[01]\d[0-3]\d/)
```

ファイルから日付が抽出できた場合のみ、処理を続けます。

抽出できない場合はエラーメッセージを出力して終わりです。

## 日付形式の変換
```ruby
# 日付を任意の形式に変換
dir_name = DateTime.parse(date).strftime("%Y年%-m月%-d日")
```

日付の形式を変換。「○年○月○日」という形式で、月と日に0が付く場合は0を無くします。

例）
「20010401」
→ o「2001年4月1日」
→ x「2001年04月01日」

iCloud写真からデータを書き出しすると、この形式でサブディレクトリを作ってくれるので、それに倣っているだけです。

## ディレクトリ作成とファイル移動

```ruby
# 日付ごとのディレクトリを作成
Dir.mkdir("#{PATH}/#{dir_name}") if !Dir.exist?("#{PATH}/#{dir_name}")
# ファイルを移動
FileUtils.mv("#{PATH}/#{file_name}", "#{PATH}/#{dir_name}/#{file_name}")
```

日付ディレクトリの作成と、各ファイルの移動。

全て絶対パスで指定。

ディレクトリが存在していない場合のみ、ディレクトリを作成するようにして、重複を避けています。

# 最後に

Pythonで自動化する本を何冊か読んでみて、自分でも書きたかったのでRubyで書いてみました。やはり、自力で1から作るのが一番勉強になりますね！

ご指摘等ありましたら、お気軽にコメントください。