VB のたまご

作成日: 2017/08/15, 更新日: 2017/08/15


テキスト系ファイルの読み書きまとめ


txt ファイルの読み書き

    Imports System.IO
    Imports System.Text
    
    Sub TextFile()
    
        ' 保存
        Dim items = New List(Of String) From {"aaa", "bbb", "ccc"}
        File.WriteAllText("data1.txt", "single")
        File.WriteAllLines("data2.txt", items)
    
        ' 読み込み
        Dim value As String = File.ReadAllText("data1.txt")
        Dim values As IEnumerable(Of String) = File.ReadLines("data2.txt")
    
        ' 編集
        Dim sb = New StringBuilder ' List(Of String) で扱っても OK
        For i As Integer = 0 To values.Count - 1
    
            If 0 < i AndAlso values(i - 1) = "aaa" Then
                sb.AppendLine($"{values(i)}_Ex")
                Continue For
            End If
    
            sb.AppendLine(values(i))
    
        Next
    
        Dim results = sb.ToString().Split(New String() {vbNewLine}, StringSplitOptions.RemoveEmptyEntries)
        Console.WriteLine(String.Join(", ", results))
    
    End Sub
    

    出力結果
    aaa, bbb_Ex, ccc
    

  •  読み込み時、ReadAllLines メソッドではなく、ReadLines メソッドを使っています。ソースを全行読み込むのを待つよりも、 1行取得したら返す、1行取得したら返す、・・・という Enumerable な方が速いそうです。

  •  ファイルの読み書きは遅いと言われていて、この間の CPU のファイル I/O 待ちが処理速度に影響するとか言われています。 遅いと言っても体感的には超速いですけどね。


csv ファイルの読み書き

    Imports System.IO
    Imports System.Text
    Imports Microsoft.VisualBasic.FileIO
    
    Sub CsvFile()
    
        ' 保存
    
        ' データの中にカンマ、改行が含まれている
        Dim item = "a1,b1,c1
    ""a2"",""b2,b2"",""c2""
    a3,b3,c3
    a4,""b4
    b4"",c4
    "
        File.WriteAllText("data.csv", item)
    
        ' 読み込み
        'item = File.ReadAllText("data.csv")
        'Console.WriteLine(item)
    
        Dim items = New List(Of Tuple(Of String, String, String))
        Dim parser = New TextFieldParser("data.csv")
        parser.Delimiters = New String() {","}
    
        While Not parser.EndOfData
            Dim row = parser.ReadFields()
            row = row.Select(Function(x) x.Replace(vbNewLine, "<br>")).ToArray()
            items.Add(Tuple.Create(row(0), row(1), row(2)))
        End While
    
        ' 編集
        For i As Integer = 0 To items.Count - 1
            Dim values = items(i)
            If values.Item1 = "a3" Then
                items(i) = Tuple.Create("xxx", "yyy", "zzz")
            End If
        Next
    
        Console.WriteLine(String.Join(" / ", items))
    
    End Sub
    

    出力結果
    (a1, b1, c1) / (a2, b2,b2, c2) / (xxx, yyy, zzz) / (a4, b4<br>b4, c4)
    

  •  csv の解析は、Microsoft.VisualBasic.FileIO.TextFieldParser クラスに頼りました。 扱おうと思っている csv データが、このクラスで賄えそうであれば、車輪の再開発はしないで頼るべきです。


xml ファイルの読み書き

    Sub XmlFile()
    
        ' 保存
        Dim xElem = <Users>
                        <User ID="1">
                            <Name>taro</Name>
                            <Age>23</Age>
                        </User>
                        <User ID="2">
                            <Name>jiro</Name>
                            <Age>32</Age>
                        </User>
                        <User ID="3">
                            <Name>hanako</Name>
                            <Age>36</Age>
                        </User>
                    </Users>
    
        xElem.Save("data.xml")
    
        ' 読み込み
        Dim xDoc = XDocument.Load("data.xml")
        'Console.WriteLine(xDoc)
    
        ' 編集
        ' ID=2 に該当する ID, Name タグそれぞれの値を書き換える
        Dim item = xDoc.
            Descendants("User").
            Where(Function(x) x.Attribute("ID").Value = "2").
            FirstOrDefault()
    
        item.SetAttributeValue("ID", 200)
        item.SetElementValue("Name", item.Element("Name").Value & "_Ex")
    
        ' ID の昇順から、年齢の降順にソート
        Dim items = xDoc.
            Descendants("User").
            OrderByDescending(Function(x) x.Element("Age").Value)
    
        ' 保存と確認
        xDoc.Element("Users").ReplaceAll(items)
        xDoc.Save("data.xml")
        Console.WriteLine(xDoc)
    
    End Sub
    

    出力結果
    <Users>
      <User ID="3">
        <Name>hanako</Name>
        <Age>36</Age>
      </User>
      <User ID="200">
        <Name>jiro_Ex</Name>
        <Age>32</Age>
      </User>
      <User ID="1">
        <Name>taro</Name>
        <Age>23</Age>
      </User>
    </Users>
    

  •  xml は、データ量がありますね。XmlDocument 系クラスは使わず XDocument 系クラスを使いました。 LINQ to XML でデータをフィルタしたりソートしたりしています。


json ファイルの読み書き

    Imports System.IO
    Imports Newtonsoft.Json.Linq
    
    Sub JsonFile()
    
        ' 保存
        Dim item = "
    {
    'name' : 'taro',
    'age' : 24,
    'food' : 'sushi'
    }
    "
        Dim obj = JObject.Parse(item)
        File.WriteAllText("data.json", obj.ToString())
    
        ' 読み込み
        item = File.ReadAllText("data.json")
        obj = JObject.Parse(item)
    
        ' 編集
        obj("age") = 32
        Console.WriteLine(obj.ToString())
    
    End Sub
    

    出力結果
    {
      "name": "taro",
      "age": 32,
      "food": "sushi"
    }
    

  •  xml のシンプル版って感じ。スクロールしなくても収まるコードの少なさが素敵です。 NuGet パッケージから 取得した Newtonsoft.Json ライブラリを使っています。 この他にも、定義クラスをシリアライズ/デシリアライズできますし、Json → Xml 相互変換も可能です。マジごいすー!


未記載のテキスト系ファイル

  •  ini ファイル、app.config ファイル、app.settings ファイルは、アプリケーションに関するデータを管理するもの、 というカテゴリに近いため、DB データに近いテキスト系ファイルではないと判断して外しました。


まとめ

  •  SQLite も載せようか迷いましたが、テキストファイル形式ではないため趣旨外と判断して外しました。

  •  一番最初の txt ファイルの編集ができるようになると、ソース生成したり変換したり、テキストファイル形式のデータなら、 何でもいじることができるようになります(エンコードには気を付けてね)。

  •  最後まで記事を読んでいただき、ありがとうございました。