質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

2509閲覧

Documentsディレクトリにファイルをまとめてコピーする方法

tactaco

総合スコア15

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/09/20 11:44

編集2021/09/22 02:59

前提・実現したいこと

Documents(ディレクトリ)内に保存をしている複数のファイルを全て一旦Librry(ディレクトリ)内に作ったサブディレクトリの中に入れております。その後ボタン一つで全てのファイルをまたDocumentsにコピーする処理をさせたいと思っております。
ですが、戻す処理の際に”Cannot make directory”と”File exists”とエラーが出て上手く行きません。
シミュレーター上では問題なくコピー出来るのですが実機だと上記エラーとなってしまいます。
最近ネットで調べながら独学で学んでいるのですがどうにもならずにお手上げです。
ご存知の方がいましたら何卒お知恵をお貸しください。
宜しくお願い致します。

発生している問題・エラーメッセージ

”Cannot make directory” ”File exists”

該当のソースコード

func CopyTest() {
do {
let fileManager = FileManager.default

//コピー元
let documentPath1 = NSHomeDirectory() + "/Library" + "/backUP" + "/Documents/"
let fileURL1 = URL(fileURLWithPath: documentPath1)
let filePath1 = fileURL1.path
//コピー先
let documentPath2 = NSHomeDirectory() + "/Documents/"
let fileURL2 = URL(fileURLWithPath: documentPath2)
let filePath2 = fileURL2.path

do {
try fileManager.copyItem(atPath: filePath1, toPath: filePath2)
print("コピー完了")
} catch {
do {
try fileManager.removeItem(atPath: filePath2)
print("一旦削除")
} catch {
print("エラー1")
}
do {
try fileManager.copyItem(atPath: filePath1, toPath: filePath2)
print("削除後コピー完了)
} catch {
print("エラー2")
}
}
}
}

**

**

swift Xcode

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2021/09/20 12:13

質問文は編集できます 無駄に質問建てないで、追記修正しよう
tactaco

2021/09/20 12:41

もう片方が投稿されているとは知りませんでした。削除させて戴きます。申し訳ございませんでした。
guest

回答1

0

ベストアンサー

~/Documents フォルダを ~/Library/backUP/Documents にコピーした前提であれば。

ファイルやフォルダのコピー・移動は、先のパスに既にアイテムが存在すると失敗します。
~/Library/backUP/Documents フォルダを ~/Documents へ戻そうとしても既に ~/Documents が存在しているので File exists になったと考えられます。


FileManager には replaceItemAt(_:withItemAt:backupItemName:options:) メソッド(公式リファレンス)もあります。

コピーではなく置き換えなので、置き換え先(~/Documents)の既存内容は全て無くなり、置き換えが成功した場合は置き換え元(~/Library/backUP/Documents)が削除されますが、ニーズに近い機能ではないかと。

swift

1func CopyTest() { 2 let fileManager = FileManager.default 3 let libraryUrl = fileManager.urls(for: .libraryDirectory, in: .userDomainMask)[0] 4 let backupUrl = libraryUrl.appendingPathComponent("backUP/Documents", isDirectory: true) 5 6 // バックアップファイルがなければ実行しない 7 var isDirectory = ObjCBool(false) 8 if (!fileManager.fileExists(atPath: backupUrl.path, isDirectory: &isDirectory) || 9 !isDirectory.boolValue) { 10 print("バックアップがないか、フォルダではありません。") 11 return 12 } 13 14 // バックアップと既存のフォルダを置き換える 15 let documentUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] 16 let temporaryName = "Replaced_Documents" 17 do { 18 _ = try fileManager.replaceItemAt(documentUrl, withItemAt: backupUrl, backupItemName: temporaryName, options: .usingNewMetadataOnly) 19 print("バックアップに置き換えました。") 20 21 } catch { 22 print("置き換えに失敗しました。", error.localizedDescription) 23 24 // 失敗したにも関わらず一時退避したファイルが元に戻されていない場合 25 if (!fileManager.fileExists(atPath: documentUrl.path)) { 26 let userInfo = (error as NSError).userInfo 27 do { 28 if let temporaryUrl = userInfo["NSFileOriginalItemLocationKey"] as? URL { 29 // エラーに格納されたURLから元の場所に移動する 30 try fileManager.moveItem(at: temporaryUrl, to: documentUrl) 31 print("置き換え前のフォルダを復旧しました。") 32 } 33 } catch { 34 print("作業の失敗からの復旧に失敗しました。", error.localizedDescription) 35 } 36 } 37 } 38}

フォルダそのものではなく、フォルダの中身 を別の場所に移したい場合、一括して行ってくれる機能はない ので、フォルダの中身のリストを取得し、ひとつひとつコピー先のパスを作成して実行することになります。

次の例では ~/Library/backUP/Documents の中身を取得してひとつひとつ ~/Documents へコピーしていますが、~/Documents に元々あるアイテムは削除されません。同名のファイルがある場合どうするかも考える必要があります。

swift

1func CopyTest() { 2 let fileManager = FileManager.default 3 let libraryUrl = fileManager.urls(for: .libraryDirectory, in: .userDomainMask)[0] 4 let backupUrl = libraryUrl.appendingPathComponent("backUP/Documents", isDirectory: true) 5 let documentUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] 6 7 // バックアップフォルダの中身を取得する 8 if let itemUrls = try? fileManager.contentsOfDirectory( 9 at: backupUrl, 10 includingPropertiesForKeys: nil, 11 options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles] 12 ) { 13 // アイテムのURLをひとつひとつ取得して`~/Documents`の中へコピーする 14 for itemUrl in itemUrls { 15 let toUrl = documentUrl.appendingPathComponent(itemUrl.lastPathComponent) 16 if (fileManager.fileExists(atPath: toUrl.path)) { 17 // 同名のファイルが存在する場合の処理 18 // ... 19 } else { 20 do { 21 try fileManager.copyItem(at: itemUrl, to: toUrl) 22 } catch { 23 print("コピーに失敗", error.localizedDescription) 24 } 25 } 26 } 27 } 28}

投稿2021/09/20 17:02

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tactaco

2021/09/21 03:09 編集

ycv57u6y様 とてもわかりやすい説明と更なる例までお教えいただきありがとうざいました! 早速置き換えを試させて頂いたところ、今回もシミュレーター上だと上手くいくのですが、実機上だと"置き換えに失敗しました You don’t have permission to save the file “Documents” in the folder “758B84E1-45A5-44AF-B929-B8E160A71906”.”と出てしまい上手く行きませんでした。 エラーで権限がないとありますが、実機上でもファイル名を指定して単体でコピーの場合は問題なく出来る事を考えると、Documents内にファイルを移動や保存をさせる事自体は問題無いと思うのですが・・・。 宜しければお知恵をお貸しくださいませ。
退会済みユーザー

退会済みユーザー

2021/09/21 06:37

だとすると iOS デバイスの実機においてはアプリに与えられたホームフォルダ以下のお決まりのフォルダ(`Documents` や `Library` といった役割が決められているもの)はアプリで削除できない仕様かもしれませんね。シミュレータの場合はただの Mac 上のフォルダなので権限問題が起きないと推測が立ちます。 個別にコピーする方法をとるか、`~/Documents/MainData` のように一つ下の権限に問題ないフォルダを用意してそれをメインのデータ置き場にして、フォルダ丸ごと置き換えの対象にするなどがあるかと。
tactaco

2021/09/21 09:35

ycv57u6y様 返答ありがとうございます。 やはりその様な仕様かも知れないのですね。承知致しました。 ですが、ご提示頂いたもう一つの方法を使ってみたところ希望に近い形で実現出来ました! お教え頂いたやり方の同名ファイルがあった場合の処理を自分なりに上記ソースコード欄に追加記入させて頂いた形でやってみたところ、一度消してからコピーといった形で問題なく出来たのですが、ycv57u6y様が書かれていた様に元々ある同名ファイル以外が全て残ってしまいます。 この残ってしまっているファイルを消す方法などは御座いませんでしょうか? このファイル達の名前はランダムとしているので同名ファイルの様に指定して消すと言った事も出来ないのです。 重ね重ね恐縮ですが宜しければお知恵をお貸しいただければ幸いです。 何卒宜しくお願い致します。
退会済みユーザー

退会済みユーザー

2021/09/21 10:31

バックアップされたファイルを戻す前に、コード例のように `fileManager.contentsOfDirectory()` を使って `~/Documents` ディレクトリのアイテムリストを取得し、全て削除すればいいでしょう。
tactaco

2021/09/21 11:18

なるほどですね! それに気づけなかった自分がお恥ずかしい・・・ 今回は本当にありがとうございました。 また一つ学ばせて頂きました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問