JavaでS3のフォルダの存在チェックをする

2016.09.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

S3に特定のフォルダが存在するかどうかチェックするプログラムをJavaで作る機会がありました。 あまり実用性はないかと思いますが、公開します。

そもそもS3にフォルダという概念はない

いきなり当エントリがタイトル詐欺だという話となります。 S3使ってると、フォルダの作成というメニューがあるのでバケット内にフォルダを作っていくというイメージですが、人間から見てフォルダのように見えているだけで実際は違うみたいですね。

yura_20160905_001

Amazon S3における「フォルダ」という幻想をぶち壊し、その実体を明らかにする - Developpers IO

とはいえ、今回はフォルダと呼んでも差し支えはないのでフォルダと呼称しておきます。

なので厳密にはフォルダの存在チェックをしているというわけではないですが、近いことをやっているということでご容赦ください。

実装

JavaでS3オブジェクトの操作を行うにはAWS SDK の AmazonS3Clientクラスを使用するのがよいかと思います。 オブジェクトの存在チェックであれば、doesObjectExistメソッドを使用すればよいのですが、フォルダの存在チェックという意味で使うときには注意が必要です。 doesObjectExist(バケット名, オブジェクト名)で対象のオブジェクトが存在すればtrueを、存在しなければfalseを返します。

例として、cm-yura-testバケットにtestfolderというフォルダがあったとします。

フォルダー名を指定して、以下のようなコードでは、falseが表示されます。

AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(accessKey, secretAccessKey));
System.out.println(client.doesObjectExist("cm-yura-test", "testfolder"));

"testfolder"ではオブジェクトとしては認識されていないわけです。 ではどうするかというと、次の様にスラッシュを付けることで、trueと表示されるようになります。

System.out.println(client.doesObjectExist("cm-yura-test", "testfolder/"));

それでもfalseを返す場合

ただし、↑のようなコードでもfalseを返すケースがあります(引数の名称とS3のオブジェクト名は合っているものとします)。ここで少しハマりました。 上で紹介しました記事のケース2の場合が当てはまります。 AWSのコンソールを操作してファイルを置く場合はそれほど気にする必要はないかもしれませんが、S3上に存在しないフォルダにプログラムなどで直接ファイルを置いた場合(フォルダの作成とファイルのPutを同時に行った場合)は注意が必要です。

client.putObject("cm-yura-test", "test/test.csv", new File("/test.csv"));

Javaで書くとしたらこんな感じでしょうか。 testフォルダが存在しないときにこのような書き方でファイルを置いたた場合"test/"オブジェクトが作られず、"test/test.csv"のみが作られるため、doesObjectExistで"test/"と指定してフォルダの存在チェックはうまくいきません(もちろん"test/test.csv"と指定した場合はtrueが返ります)。

以下のように書けば、そういった場合でもtrueを返してくれます。

ObjectListing objectList = client.listObjects("cm-yura-test", "test/");
List<S3ObjectSummary> list = ol.getObjectSummaries();
boolean result = list.size() == 0? false : true;
return result;

listObjectsメソッドで頭に"test/"のつくオブジェクトの一覧を取得し、それが1つでもあればフォルダとして存在しているということなので、 このような書き方で書いておけば、フォルダの存在チェックという意味では確実かとは思います。