Swift4.2 CSVファイル関連

# Swift4.2 最初にディレクトリを作成と削除の話 ?
2018/11/24

CSVファイルと書いてありますが? 例えばとしてCSVファイルを扱いました。

動画ですが? 見てもよくわからないでしょうから解説したいと思います

- iPadの録画ボタンを押している
- ファイルのこのiPad内のKessanフォルダを削除している
- 自作のアプリを起動している
- それぞれのコードが実行されている
- バンドルの貸借対照表.csvが読み込まれている
- テーブルにCSVファイルの内容が表示されている
- 資産の部を選択して内容変更画面へ遷移する
- 0を108に変更してテーブルの画面へ遷移する
- 自作アプリを終了してこのiPad内のKessanフォルダ内に保存された貸借対照表.csvをEXCELで開いている


[![ビデオが開けなかった場合に表示されるテキスト](http://papassan.starfree.jp/qiita/print.png)](https://www.youtube.com/watch?v=OPK58k9JyYk&feature=youtu.be)

[ビデオが開けなかった場合](https://www.youtube.com/watch?v=OPK58k9JyYk&feature=youtu.be)



目的

> iPhoneとかiPadとかの純正アプリの「ファイル」にiPhoneならブラウズの場所の中に「このiPhone内」とかがありますね? その中にCSVファイルを保存したり読み込んだり削除したりフォルダを作成したりできますよね? 

最初にデバイスのDocumentsのパスを取得します

[引用先・Developer by Apple Documentation](https://developer.apple.com/documentation/foundation/1414224-nssearchpathfordirectoriesindoma?language=objc)

```Declaration.swift

NSArray<NSString *> * NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);

```

これのObjective-Cの参考コードをXcodeに貼り付けると? 当然エラーになりますので

> let pass = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory, NSSearchPathDomainMask, true)

としましたら?

- NSSearchPathDirectory -> Replace 'NSSearchPathDirectory' with 'FileManager.SearchPathDirectory'
- NSSearchPathDomainMask -> Replace 'NSSearchPathDomainMask' with 'FileManager.SearchPathDomainMask'

っと修正するように指示されましたよ、なので

- Manager.SearchPathDirectoryは、[ここのサイト](https://developer.apple.com/documentation/foundation/filemanager/searchpathdirectory/documentdirectory)の解説によりますと

FileManager.SearchPathDirectory.documentDirectoryとなりますね?

- FileManager.SearchPathDomainMaskも同様に[ここのサイト](https://developer.apple.com/documentation/foundation/filemanager/searchpathdomainmask/1408037-userdomainmask)の解説によりますとプロパティに.userDomainMaskを指定して

FileManager.SearchPathDomainMask.userDomainMaskとするとエラーは消えました、そしてコードは以下です、そして基本は長いコードは削除してエラーがでなければOKの考えで、SearchPathDirectoryやFileManager.SearchPathDomainMaskは省略できます


```Declaration.swift

let pass = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        var docDir: String = pass[0]
        docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]

//ご存知でしょうが上記は以下と同じです

let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print("実行結果・docDir -> \(docDir)")

//これも結果は同じ
let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
print("実行結果・docDir -> \(docDir)")

//実行結果・docDir -> /var/mobile/Containers/Data/Application/815FE3B6-8497-42B0-9BEE-8CFE63A6C77A/Documents



```

### 次にディレクトリーを作成します

[引用先・Developer by Apple Documentation](https://developer.apple.com/documentation/foundation/filemanager/1407884-createdirectory)

> createDirectory(atPath:withIntermediateDirectories:attributes:)

パラメーター
- path -> 作成するディレクトリを識別するパス文字列
- createIntermediates -> trueはpathにディレクトリを作成する際に存在しない親ディレクトリを作成します、でfalseは中間の親ディレクトリが存在しない場合、このメソッドは失敗します、また、中間パス要素のいずれかがディレクトリではなくファイルに対応する場合にも失敗します、っと書いてあります? 私には意味不明ですが、多分、pathの文字列の中に中間にというか途中にディレクトリーがない場合の話だと思います

trueの場合 -> 存在しない中間に親ディレクトリーを作成する
falseの場合 -> 存在しない中間に親ディレクトリーがないと失敗になる

- attributes -> 新しいディレクトリと新しく作成された中間ディレクトリのファイル属性。 所有者とグループ番号、ファイルのアクセス許可、および変更日を設定できます。 このパラメータにnilを指定するか、または特定の値を省略すると、ディスカッションで説明されているように、1つ以上のデフォルト値が使用されます。 このディクショナリに含めることができるキーのリストについては[「サポートする型」](https://developer.apple.com/documentation/foundation/filemanager#1652398)を参照してください。っと書いてあります、これも私には意味不明です

ディスカッション
attributesパラメーターにnilを指定した場合、このメソッドはパス内の新しく作成されたディレクトリーの所有者、グループ、および許可にデフォルトの値セットを使用します。 同様に、特定の属性を省略すると、デフォルト値が使用されます。 新しく作成されるディレクトリのデフォルト値は次のとおりです。
パーミッションは、現在のプロセスのumaskに従って設定されます。 詳細については、umaskを参照してください。
所有者IDはプロセスの実効ユーザーIDに設定されます。
グループIDは、親ディレクトリのグループIDに設定されます。

```Declaration.swift

        do {
            try FileManager.default.createDirectory(atPath: docDir + "/Kessan", withIntermediateDirectories: false, attributes: nil)
        } catch {
            // エラー
        }

```

```Declaration.swift

        let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/Kessan"
print("実行結果・docDir -> \(docDir)")
        do {
            // ディレクトリが存在するかどうかの判定
        if !FileManager.default.fileExists(atPath: docDir) {
            // ディレクトリが無い場合ディレクトリを作成する
            try FileManager.default.createDirectory(atPath: docDir, withIntermediateDirectories: false , attributes: nil)
        }
    } catch {
    // エラー処理
    }

//実行結果・docDir -> /var/mobile/Containers/Data/Application/EE2F4F22-F8EE-4712-BD0E-4AFFE65F1067/Documents/Kessan

```

### 更にディレクトリーを削除します

[引用先・Developer by Apple Documentation](https://developer.apple.com/documentation/foundation/filemanager/1408573-removeitem)

```Declaration.swift

        do {
            try FileManager.default.removeItem(atPath: docDir)
        } catch {
            //エラー処理
            print("error")
        }

```

### やっとCSVファイルの読込と書込みです

用意するもの
- アプリ内にCSVファイルを設置する ファイル名 -> 貸借対照表.csv とします

```貸借対照表.csv

1,資産の部,0
1,現金,4026649
2,当座預金,94214
3,普通預金,1593493
4,売掛金,824199
5,商品,901404
6,未収収益,1142099
7,車両運搬具,4448194
8,工具器具備品,507510
9,繰越資産,954045
1,負債の部,0
10,買掛金,197316
11,未払金,8457713
12,短期借入金,100000
13,預り金,41100
14,長期借入金,1300000
1,純資産の部,0
15,資本金,10000000
16,利益準備金,3000000
17,繰越利益剰余金,1189906
17,papassan,2090356

```

```Declaration.swift

        do {
            //ユーザーが保存したCSVファイルのパス
            userPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/Kessan/" + "貸借対照表" + ".csv"
            var path = userPath
print("1 通過・path -> \(path!)")
            if (fileManager.fileExists(atPath: path!) == false) {
                //ユーザーが保存したCSVファイルが無い場合は、初期CSVファイルから読み込む。
                path = Bundle.main.path(forResource: "貸借対照表", ofType: "csv")!
            }
            
            //CSVファイルのデータを取得する。
            let csvData = try String(contentsOfFile:path!, encoding:String.Encoding.utf8)
//print("csvData = \(csvData)")//2018/05/15
            //改行区切りでデータを分割して配列に格納する。
            dataList = csvData.components(separatedBy: "\n")
print("dataList = \(dataList)")//2018/05/15
            //print("\(String(describing: dataList))")
            //テーブルビューを編集モードにする。
            //testTableView.isEditing = true//削除アイコンが出る
            testTableView.isEditing = false//削除アイコンが出ない、スワイプで削除アイコンが出ます
            //CSVファイルの出力先を確認する。
print("2 通過・userPath -> \(userPath!)")
        } catch {
            print(error)
        }
    }

/*

実行結果・docDir -> /var/mobile/Containers/Data/Application/60088266-A122-40D0-B93F-FA786A7CE017/Documents/Kessan
1 通過・path -> /var/mobile/Containers/Data/Application/60088266-A122-40D0-B93F-FA786A7CE017/Documents/Kessan/貸借対照表.csv
dataList = ["1,資産の部,0", "1,現金,4026649", "2,当座預金,94214", "3,普通預金,1593493", "4,売掛金,824199", "5,商品,901404", "6,未収収益,1142099", "7,車両運搬具,4448194", "8,工具器具備品,507510", "9,繰越資産,954045", "1,負債の部,0", "10,買掛金,197316", "11,未払金,8457713", "12,短期借入金,100000", "13,預り金,41100", "14,長期借入金,1300000", "1,純資産の部,0", "15,資本金,10000000", "16,利益準備金,3000000", "17,繰越利益剰余金,1189906", "17,papassan,2090356", ""]
2 通過・userPath -> /var/mobile/Containers/Data/Application/60088266-A122-40D0-B93F-FA786A7CE017/Documents/Kessan/貸借対照表.csv

*/


```

### 書込みです

```Declaration.swift

        let outputStr = dataList.joined(separator: "\n")
print("3 通過・outputStr -> \(outputStr)")
        do {
            if(outputStr == "") {
                //部活配列が空の場合はユーザーが保存したCSVファイルを削除する。
                try fileManager.removeItem(atPath: userPath)
            } else {
                //ファイルを出力する。
                try outputStr.write(toFile: userPath, atomically: false, encoding: String.Encoding.utf8 )
            }
        } catch {
            print(error)
        }
    }

/*

実行結果
3 通過・outputStr -> 1,資産の部,108
1,現金,4026649
2,当座預金,94214
3,普通預金,1593493
4,売掛金,824199
5,商品,901404
6,未収収益,1142099
7,車両運搬具,4448194
8,工具器具備品,507510
9,繰越資産,954045
1,負債の部,0
10,買掛金,197316
11,未払金,8457713
12,短期借入金,100000
13,預り金,41100
14,長期借入金,1300000
1,純資産の部,0
15,資本金,10000000
16,利益準備金,3000000
17,繰越利益剰余金,1189906
17,papassan,2090356

*/

```

ここまで