今回はファイルを開いて中身を読み込んだり、データを書き込んだりしてみようと思います。
ゲームの会話部分を外部のテキストファイルに保存しておいて、それを読みだして利用する時などに使うと思います。
ファイルの作成については前回やりましたので、そちらの記事を参照してください。
ファイルを開いてデータを読み込む
ファイルを開いて読み込む方法は色々ありますので、その中でいくつか見ていきます。
データの中身を一括で読み込む
まずはデータの中身を一括で読み込む方法です。
File.ReadAllLinesメソッド
FileクラスのReadAllLinesメソッドを使用するとファイルのデータを全て読み込んで文字列型の配列を返してくれます。
1 2 3 | string[] allText1 = File.ReadAllLines (filePath); |
ファイルの各行を分割して使用したい時に便利ですが、データが多い時は一括して処理する為、処理の負荷が大きくなります。
File.ReadAllText
FileクラスのReadAllTextメソッドを使用するとファイルの中身を取り出して文字列として返してくれます。
1 2 3 | string allText2 = File.ReadAllText (filePath); |
こちらは一つの文字列として扱う為、改行文字もその中に含まれます。
これらを使ったサンプルを作成してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | using UnityEngine; using System.Collections; using System.IO; public class OpenFileTest1 : MonoBehaviour { // Use this for initialization void Start () { string filePath = Application.dataPath + @"\Scripts\File\test.txt"; // ファイルが存在しなければ作成 if (!File.Exists (filePath)) { using (File.Create (filePath)) { } } string[] allText1 = File.ReadAllLines (filePath); foreach (var text in allText1) { Debug.Log ("各行表示: " + text); } string allText2 = File.ReadAllText (filePath); Debug.Log ("全行表示: " + allText2); } } |
Assets→Scripts→Fileにtest.txtファイルが存在しなければtest.txtファイルを作成します。
その後ReadAllLinesとReadAllTextを使った処理を記述しています。
test.txtファイルを開いて中に何か文字を書くとコンソールに文字列が表示されます。
データをストリームで徐々に読み込む
データが大きい場合に一括で取得すると処理負荷が大きくなります。
そこでデータが大きい時には徐々に読み込めるストリームを使ってデータを読み込むようにします。
1 2 3 | StreamReader streamReader = new StreamReader (filePath, Encoding.UTF8) |
↑のように第1引数にファイルパス、第2引数にエンコードを指定します。
第1引数はStreamを指定する事も出来るので、Stream型を継承する他のストリームを指定する事も出来ます。
例えばFileクラスのOpenを使うと戻り値にFileStream型を取得出来るので、
1 2 3 4 | FileStream fileStream = File.Open (filePath, FileMode.Open, FileAccess.Read); StreamReader streamReader = new StreamReader (fileStream, Encoding.UTF8); |
↑のように指定する事も出来ます。
それではサンプルを作成してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using UnityEngine; using System.Collections; using System.IO; using System.Text; public class OpenFileTest2 : MonoBehaviour { // Use this for initialization void Start () { string filePath = Application.dataPath + @"\Scripts\File\test.txt"; using (StreamReader streamReader = new StreamReader (filePath, Encoding.UTF8)) { while(!streamReader.EndOfStream) { Debug.Log("ストリームで読み込み:" + streamReader.ReadLine ()); } } } } |
ファイルの読み込みが完了したかどうかはEndOfStreamプロパティを使用して判定し、ファイルの読み込みが完了するまでコンソールにデータを表示しています。
ReadLineで1行分を取得出来ます。
ファイルへの書き込み
次はファイルにデータを書き込んでみたいと思います。
読み込みの時と同じで書き込み時も一括で行う方法とストリームを使う方法がありますのでそれぞれ見ていきましょう。
一括してデータを書き込む
まずは一括してデータを書き込む方法です。
File.AppendAllText
FileクラスのAppendAllTextを使うと一括でファイルに追記してデータを書き込む事が出来ます。
1 2 3 | File.AppendAllText (filePath, "あいう"); |
↑の例ではファイルの末尾に あいう という文字列を追記します。
File.AppendAllLinesという配列を追記するメソッドも.Net FrameWork4.0以降で使えるようですが、わたくしの環境だと3.5っぽいので使えません・・・(T_T)/~~~
File.WriteAllLines
FileクラスのWriteAllLinesを使うと新しくファイルを作成し、文字列型の配列をデータに書き込むことが出来ます。
1 2 3 4 | string[] myStringArray = { "あいうえお", "かきくけこ", "さしすせそ" }; File.WriteAllLines (filePath, myStringArray); |
↑の例では配列の要素をファイルに書き込みます。
File.WriteAllText
FileクラスのWriteAllTextメソッドを使うと新しくファイルを作成し、文字列をファイルに書き込むことが出来ます。
1 2 3 4 | string myString2 = "あいうえお\nかきくけこ\nさしすせそ\nたちつてと\nなにぬねの"; File.WriteAllText (filePath, myString2); |
これらを使ってサンプルを作成してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using UnityEngine; using System.Collections; using System.IO; public class WriteFileTest1 : MonoBehaviour { // Use this for initialization void Start () { string filePath = Application.dataPath + @"\Scripts\File\WriteText1.txt"; string myString1 = "かきくけこ\nさしすせそ\n"; File.AppendAllText (filePath, myString1); string[] myStringArray = { "あいうえお", "かきくけこ", "さしすせそ" }; File.WriteAllLines (filePath, myStringArray); string myString2 = "あいうえお\nかきくけこ\nさしすせそ\nたちつてと\nなにぬねの"; File.WriteAllText (filePath, myString2); } } |
AppendAllTextは追記、WriteAllLinesとWriteAllTextは新しくファイルを作り書き込むので、最終的にはWriteText1.txtには
あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
が書き込まれます。
ストリームを使って徐々に書き込む
ストリームを使って徐々にデータを書き込む方法も見ていきましょう。
File.AppendText
FileクラスのAppendTextメソッドを使用するとStreamWriterを取得する事がファイルに追記する事が出来ます。
1 2 3 | StreamWriter streamWriter = File.AppendText (filePath); |
ファイルがすでに存在する場合は末尾から書き込むことが出来ます。
StreamWriterのインスタンス化
StreamWriterをインスタンス化しファイルにデータを書き込む事も出来ます。
1 2 3 | StreamWriter streamWriter = new StreamWriter (filePath, append : true) |
インスタンス化する時に第1引数にファイルのパスを指定し、第2引数に追記するかどうかのbool値を指定します。
第2引数がない、もしくはfalseの時はファイルに上書きをします。
同一ファイルの読み込みと書き込みを同時に行う
ファイルの読み書きが出来るようになったので、同一ファイルの読み書きを一緒に行ってみます。
1 2 3 4 5 6 7 8 9 10 11 | using (FileStream fileStream = File.Open (filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { using (StreamReader streamReader = new StreamReader (fileStream)) using (StreamWriter streamWriter = new StreamWriter (fileStream)) { string preString = streamReader.ReadToEnd (); streamWriter.WriteLine ("文字列の追加"); fileStream.Position = 0; streamWriter.WriteLine (preString); } } |
最初にFileStreamで読み書き両方出来るストリームを作成します。
その後、読み込みと書き込みのストリームをFileStreamを元に作成します。
streamReader.ReadToEndでファイルの全データを取得しpreStringに入れています。
その後streamWriter.WriteLineでファイルに文字列を追記した後、fileStream.Positionに0を入れてストリームの位置を先頭に移動させます。
その後streamWriter.WriteLine(preString)で元の文字列を書き込んでいるので、先頭に元の文字列が挿入される事になります。
CSVファイルの読み込みと書き込み
最後に、ここまで学んだ事を使って、UnityでCSVファイルの読み込みと書き込みを行ってみようと思います。
テキストファイルをUnityに取り込み、中身をカンマで区切ったデータ群を使う事も出来ますが(中身は,で区切られてるがファイル形式はtxt)、エクセルで出力したCSVファイル自体をUnityに取り込んで使用する事にします(こちらのファイル形式はcsv)。
Assetsフォルダで右クリック→Import New Assetを選択し、エクセルで出力したCSVファイルを選択し取り込みます。
ただし、Unityに取り込んだCSVファイルはMonoDevelopで表示すると本来のデータ以外のものが入ります。スクリプトで処理する分には問題ありません。
ファイルから一括でCSVデータを読み込む
ファイルのデータが少なければ簡単に一括で読み込む事が出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | using UnityEngine; using System.Collections; using System.IO; using System.Collections.Generic; using System.ComponentModel; using System; public class ReadWriteCSVFile : MonoBehaviour { // Use this for initialization void Start () { string CSVFilePath = Application.dataPath + @"\Scripts\File\CSVFile.csv"; // 一括で取得 string[] texts = File.ReadAllText (CSVFilePath).Split (new char[]{ ',', '\n'}, StringSplitOptions.RemoveEmptyEntries); foreach (var text in texts) { Debug.Log (text); } } } |
File.ReadAllTextを使ってCSVファイルを取得し、それをSplitメソッドでcharの配列で区切り文字 , \n を指定します。
第2引数では区切り文字で分割した文字列型の配列で空白が入ったものは除外しておきます。
CSVファイルから読み込みと別ファイルへの書き込み
次はストリームを使ってCSVファイルを読み込み、それを別のファイルに書き込んでみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | using UnityEngine; using System.Collections; using System.IO; using System.Collections.Generic; using System.ComponentModel; using System; public class ReadWriteCSVFile : MonoBehaviour { // Use this for initialization void Start () { string CSVFilePath = Application.dataPath + @"\Scripts\File\CSVFile.csv"; string CSVWriteFilePath = Application.dataPath + @"\Scripts\File\CSVWriteFile.csv"; // ストリームで読み込みと書き込み using (StreamReader streamReader = new StreamReader(CSVFilePath)) using (StreamWriter streamWriter = new StreamWriter(CSVWriteFilePath)) { List<string> lists = new List<string>(); while (!streamReader.EndOfStream) { lists.AddRange (streamReader.ReadLine ().Split (',')); } int count = 0; foreach (var list in lists) { streamWriter.Write (list.ToString () + ','); count++; if (count % 5 == 0) { streamWriter.WriteLine (); } } foreach (var list in lists) { Debug.Log (list); } } } } |
まずは,を区切り文字として読み込んだstring型の配列をリストのAddRangeメソッドで追加します。
ここまででCSVファイルを,を区切り文字にしてデータを取り出しリストに登録する読み込みが出来ています。
その後リストのデータに,を付けて新しいCSVファイルに書き込んでいます。
5行毎に改行をする為、countが5で割り切れる時にWriteLineを使い改行するようにしています。
別ファイルに書き込んだCSVファイルを再度読み込んで確認
別のCSVファイルに書き込みは出来ましたが、それを再度読み込んでデータとして使えるかどうかを確認してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | using UnityEngine; using System.Collections; using System.IO; using System.Collections.Generic; using System.ComponentModel; using System; public class ReadWriteCSVFile : MonoBehaviour { // Use this for initialization void Start () { string CSVFilePath = Application.dataPath + @"\Scripts\File\CSVFile.csv"; string CSVWriteFilePath = Application.dataPath + @"\Scripts\File\CSVWriteFile.csv"; // 書き込んだCSVファイルの読み込み using(StreamReader streamReader = new StreamReader(CSVWriteFilePath)) { List<string> newLists = new List<string> (); while (!streamReader.EndOfStream) { newLists.AddRange (streamReader.ReadLine ().Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries)); } foreach (var newList in newLists) { Debug.Log ("再読み込みリスト: " + newList); } } } } |
先ほどやったCSVファイルの読み込み処理と同じですね。
別のCSVファイルに書き込んだデータも同じように取り込む事が出来ました。
終わりに
今回の記事を作成した事で、だいぶファイル操作の処理に慣れてきました。
ファイル操作で気を付ける事はリソースの解放を忘れずにする事ですね・・・・、これを忘れるとどこが原因で不具合出ているのかわからない状態になります・・・。
身をもって体験しました・・・・(ーー;)