(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

アセットのコピー(AssetDatabase.CopyAsset VS File.Copy)【Unity】【エディタ拡張】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 2017.4.0f1


はじめに

Unityではアセット(ファイル)をコピーしたいと思った時に簡単に実装出来る方法が二つあります。

一つはUnityの機能であるAssetDatabase.CopyAsset、もう一つはC#(.NET)の機能であるFile.Copyです。

//using UnityEditor;が必要
AssetDatabase.CopyAsset("Assets/Resources/Corgi.png", "Assets/Resources/Corgi2.png");
//using System.IO;が必要
File.Copy("Assets/Resources/Corgi.png", "Assets/Resources/Corgi2.png");


二つも実装方法があると、どっちを使ったら良いのか気になりますよね?

という事で今回はAssetDatabase.CopyAssetとFile.Copyの比較です!


先に結論だけ言ってしまうと、基本的にAssetDatabase.CopyAssetを使えばOKです。


設定(.meta)のコピー

File.Copyのコピーされるのファイル本体だけで、.metaファイルはコピーされません。

これは、画像等の設定もコピーされないという事でもあります。


f:id:kan_kikuchi:20180403070822j:plain


それに対してAssetDatabase.CopyAssetは.metaファイルもコピーされるので、設定もコピー可能です。


f:id:kan_kikuchi:20180403070841j:plain


逆に言うと、

.metaファイル(設定)をコピーしたくない場合にはFile.Copyの方が適してるという事でもあります。


コピー後のリフレッシュ

上記の通りFile.Copyは.metaはコピーしないので、

ファイルコピー直後はProjectウィンドウで見えません。

File.Copy("Assets/Resources/Corgi.png", "Assets/Resources/CorgiCopy.png");

f:id:kan_kikuchi:20180403071842g:plain


なので、コピー後に.metaファイルを新規作成するために

AssetDatabase.RefreshまたはAssetDatabase.ImportAssetをする必要があります。

//ファイルをコピー
File.Copy("Assets/Resources/Corgi.png", "Assets/Resources/CorgiCopy.png");

//リフレッシュして.metaファイルを作成
AssetDatabase.Refresh();
//インポートでも可
//AssetDatabase.ImportAsset("Assets/Resources/CorgiCopy.png");


それに対して、AssetDatabase.CopyAssetはRefreshやImportAssetの必要がありません。

//アセットをコピー(.metaファイルもコピーされる)
AssetDatabase.CopyAsset("Assets/Resources/Corgi.png", "Assets/Resources/Corgi2.png");

f:id:kan_kikuchi:20180403072407g:plain


コピー失敗時の挙動

コピー元のファイルが無かったり、コピー先のディレクトリが無い等の失敗時に

File.Copyはエラーが出ますが、


f:id:kan_kikuchi:20180403073101j:plain


AssetDatabase.CopyAssetはエラーが出ず、変わりに返り値にfalseが返されます。

if (AssetDatabase.CopyAsset("Assets/Resources/Shiba.png", "Assets/Resources/CorgiCopy.png")) {
  //コピー成功
}
else{
  //コピー失敗
}



上書きコピー

コピー先のファイルが既に存在する場合、File.Copyは第三引数をtrueにしていれば上書き出来ます。

(デフォルトはfalse、falseの時は上書きせずにエラーが出る)

File.Copy("Assets/Resources/Corgi.png", "Assets/Resources/CorgiCopy.png", overwrite:true);


それに対して、AssetDatabase.CopyAssetは常に上書きします。


また、AssetDatabase.CopyAssetにはそもそも上書きという機能がなく、

上書き出来てしまうのはバグで、上書き時にはデータベースに不具合が生じていました。

AssetDatabase クラスには CopyAsset 関数がありますが、上書きするという機能はありません。厳密に言うと上書きできてしまうのですが、Unity のデータベースに不具合が生じます。


しかし、今(Unity 2017.4.0)は問題なく上書き出来るようになりました。

ただし、上書き可能に仕様が変わったのかどうかまでは分かりません。


ディレクトリのコピー

File.Copyはディレクトリをコピーしようとするとエラーが出ますが、

//エラー!(Assets/Resourcesがあって、Assets/Resources2がなくても)
File.Copy("Assets/Resources", "Assets/Resources2");


AssetDatabase.CopyAssetはディレクトリのコピーも可能です。

AssetDatabase.CopyAsset("Assets/Resources", "Assets/Resources2");

f:id:kan_kikuchi:20180403075050g:plain


ちなみにDirectoryというクラスはありますが、Directory.Copyというメソッドはありません。


フォルダをコピーする - .NET Tips (VB.NET,C#...)


おわりに

最後にAssetDatabase.CopyAsset と File.Copyの違いを表でまとめてみました。

項目 AssetDatabase.CopyAsset File.Copy
設定(.meta)のコピー される されない
コピー後のリフレッシュ 不必要 必要
コピー失敗時の挙動 falseが返る エラーが出る
上書きコピー 常に上書き 上書きするか設定可能
ディレクトリのコピー 出来る 出来ない


こうして見ると同じような機能でも結構違いがあるので、注意が必要ですね。