Google Cloud Storageで、サブディレクトリ内のファイル一覧を取得して、それらのファイルの処理をしようとしました。
しかし、ファイルがおかしいとエラーが出るので見てみたら、取得したファイル一覧に、サブディレクトリが含まれていました。
原因
前に勘違いしてハマったのですが、Googleに限らず、AWSやAzureなど、この手のクラウドストレージには、本当はディレクトリというものはありません。
ファイル名はフルパスが正式名で、UIでは「/」で区切られた部分を、擬似的にディレクトリとして表現してるに過ぎません。
そのあたりの説明はこちら。
空のディレクトリ
Google Cloud StorageのポータルサイトのUIでは、ディレクトリだけを作成することができます。
ディレクトリという概念が無いはずなのに、ディレクトリが作成できるのはおかしな話で、実際はUIでディレクトリを作成すると、「<ディレクトリ名>/」のファイルが作成されていました。(名前の最後が「/」なところがミソです)
また、UIでは、「<ディレクトリ名>/」のファイルがあると、それをディレクトリのように見せるようになっています。
今回ハマったのは、最初、UIでディレクトリを作ってから、その中にファイルを入れたため、ディレクトリがファイルとして取得されて処理しようとしたためでした。
解決方法
では本題の、取得したファイルが、ファイルなのかディレクトリなのかを区別する方法ですが、
ファイル名の最後が「/」か否かで識別
になります。
本当にそうなのか調査
- 名前しか判断方法ないの!?
- 取得したファイルの属性に識別情報があるのでは!?
と、にわかに信じがたかったのでテストしてみました。
名前が「test/」で終わるファイルをGoogle Cloud Storage上に作成して、中身に「TESTですよ!」と書き込み、再度そのGoogle Cloud Storageのファイルを読み込んで中身を表示してみます。
import { Storage } from '@google-colud/storage'; const storage = new Storage(); const bucket = storage.bucket('xxxx'); async function writeDirectory(){ const file = await bucket.file('test/'); const stream = file.createWriteStream(); return new Promise((resolve, reject)=>{ stream.on('finish', ()=> resolve()); stream.write('TESTですよ!'); stream.end(); }); } async function readDirectory(){ const file = await bucket.file('test/'); const stream = file.createReadStream(); return new Promise((resolve, reject)=>{ stream.on('end', ()=> resolve()); stream.on('data', (data)=>{ console.log(data.toString()); }); }); } async (()=>{ console.log('writeDirectory'); await writeDirectory(); console.log('readDirectory'); await readDirectory(); })();
結果
ファイルをアップしたのに、「test/」ディレクトリが出来ています。
「test」ディレクトリの中身を表示すると、書き込んだ内容のファイルでした…。
writeDirectory readDirectory TESTですよ!
ディレクトリなのに、ファイルとしても間違ってはいないので、名前以外に区別しようがありません。
結論
ファイル名の最後が「/」はディレクトリ!
感想など
面倒ですが、ファイルを取得した時は、ファイル名の最後が「/」かを必ずチェックした方がいいですね。
よく見たらドキュメントに書いてありました…。
関連記事
www.kwbtblog.com www.kwbtblog.com www.kwbtblog.com