【C#】【book】「実戦で役立つ C# プログラミングのイディオム/定石&パターン」の学習記録(9)

下記の「実戦で役立つ C#プログラミングのイディオム/定石&パターン」を使った学習記録のページです。
本ページのプログラムは「実戦で役立つ C#プログラミングのイディオム/定石&パターン」をもとにして作成したものも多数あります。
実戦で役立つ C#プログラミングのイディオム/定石&パターン

9.1 テキストファイルの入力

9.1.1 テキストファイルを1行ずつ読み込む

  • 「using 使用、 EndOfStream 使用」パターン
    • Program.cs の StreamReader_1_a() メソッドを参照
  • 「using 使用、 EndOfStream 不使用」パターン
    • Program.cs の StreamReader_1_b() メソッドを参照
  • 「using 不使用、EndOfStream 使用」パターン
    • Program.cs の StreamReader_1_c() メソッドを参照

9.1.2 テキストファイルを一気に読み込む

9.1.3 テキストファイルを IEnumerable として扱う

  • File.ReadLines メソッドを使って IEnumerable として全行を表示する
    • 下記 Program.cs の StreamReader_3 メソッドを参照
  • LINQ を使って先頭の n行を取り出す
    • 下記 Program.cs の StreamReader_3_a メソッドを参照
  • LINQ を使って条件に一致した行数をカウントする
    • 下記 Program.cs の StreamReader_3_b メソッドを参照
  • LINQ を使って条件に一致した行を取り出す
    • 下記 Program.cs の StreamReader_3_c メソッドを参照
  • LINQ を使って条件に一致した行が存在しているか調べる
    • 下記 Program.cs の StreamReader_3_d メソッドを参照
  • LINQ を使って重複行を取り除き並び替える
    • 下記 Program.cs の StreamReader_3_e メソッドを参照
  • LINQ を使って各行に行番号を付与する
    • 下記 Program.cs の StreamReader_3_f メソッドを参照

 

Program.cs
#define MYTEST

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace StreamReaderSample
{
  class Program
  {
    static void Main( string[] args )
    {
      // 9.1.1 テキストファイルを1行ずつ読み込む
      StreamReader_1_a(); // using 使用、  EndOfStream 使用
      StreamReader_1_b(); // using 使用、  EndOfStream 不使用
      StreamReader_1_c(); // using 不使用、EndOfStream 使用

      // 9.1.2 テキストファイルを一気に読み込む
      StreamReader_2();

      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      StreamReader_3();
      StreamReader_3_a(); // LINQ を使って先頭 n行を取り出す
      StreamReader_3_b(); // LINQ を使って条件に一致した行数をカウントする
      StreamReader_3_c(); // LINQ を使って条件に空行や空白行以外を取り出す
      StreamReader_3_d(); // LINQ を使って条件に一致した行が存在するか調べる
      StreamReader_3_e(); // LINQ を使って全行に対して uniq, sort をする
      StreamReader_3_f(); // LINQ を使って各行に行番号を付与する
    }

    static void StreamReader_1_a()
    {
      // 9.1.1 テキストファイルを1行ずつ読み込む
      // - EndOfStream で終端判定をするパターン(推奨)
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt"; // <your project>\bin\Debug\*\. 辺りのコードと一緒に置く
      if ( File.Exists( filePath ) )
      {
        // もしも Shift_JIS を扱う場合は Encoding.GetEncoding("shift_jis") とする
        // リソース解放(ここではファイルクローズ)を確実にするために using を使う (4.7.7 参照)
        using ( var reader = new StreamReader( filePath, Encoding.UTF8 ) )
        {
          while ( !reader.EndOfStream ) // ファイルの最後に逹っしたか?
          {
            var line = reader.ReadLine();
            Console.WriteLine( line );
          }
        }
      }
    }

    static void StreamReader_1_b()
    {
      // 9.1.1 テキストファイルを1行ずつ読み込む
      // - line != null で終端判定をするパターン (非推奨)
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt"; // <your project>\bin\Debug\*\. 辺りのコードと一緒に置く
      if ( File.Exists( filePath ) )
      {
        // もしも Shift_JIS を扱う場合は Encoding.GetEncoding("shift_jis") とする
        using ( var reader = new StreamReader( filePath, Encoding.UTF8 ) )
        {
          string line = null;
          while ( (line = reader.ReadLine()) != null ) // ファイルの最後に逹っしたか?
          {
            Console.WriteLine( line );
          }
        }
      }
    }

    static void StreamReader_1_c()
    {
      // 9.1.1 テキストファイルを1行ずつ読み込む
      // - リソース解放に using を使わず、try-finally で対応するパターン
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt"; // <your project>\bin\Debug\*\. 辺りのコードと一緒に置く
      if ( File.Exists( filePath ) )
      {
        // もしも Shift_JIS を扱う場合は Encoding.GetEncoding("shift_jis") とする
        StreamReader reader = new StreamReader( filePath, Encoding.UTF8 );
        try
        {
          while ( !(reader.EndOfStream) )
          {
            string line = reader.ReadLine();
            Console.WriteLine( line );
          }
        }
        finally
        {
          reader.Dispose();
        }
      }
    }

    static void StreamReader_2()
    {
      // 9.1.2 テキストファイルを一気に読み込む
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadAllLines( filePath, Encoding.UTF8 );
        foreach ( var line in lines )
        {
          Console.WriteLine( line );
        }
      }
    }

    static void StreamReader_3()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - 見た目は上述の 9.1.2 の File.ReadAllLines を File.ReadLines に変えただけだが、
      //   内部では StreamReader クラスの ReadLine メソッドに近い。
      // - IEnumerable により LINQ が使えるようになる。
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadLines( filePath, Encoding.UTF8 );
        foreach ( var line in lines )
        {
          Console.WriteLine( line );
        }
      }
    }

    static void StreamReader_3_a()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - LINQ を使って先頭の n行を取り出す
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadLines( filePath, Encoding.UTF8 )
          .Take( 10 )
          .ToArray();
        Console.WriteLine( lines );
      }
    }

    static void StreamReader_3_b()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - LINQ を使って条件に一致した行数をカウントする
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadLines( filePath, Encoding.UTF8 )
          .Count( s => s.Contains( "http" ) ); // http を含む行数をカウントする
        Console.WriteLine( lines );
      }
    }

    static void StreamReader_3_c()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - LINQ を使って条件に一致した行を取り出す
      // - LINQ の Where メソッドはフィルタに通すか否かを判定する
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadLines( filePath, Encoding.UTF8 )
          .Where( s => !String.IsNullOrWhiteSpace( s ) ) // 空行や空白行以外を取り出す
          .ToArray();
        foreach ( var line in lines )
        {
          Console.WriteLine( line );
        }
      }
    }

    static void StreamReader_3_d()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - LINQ を使って条件に一致した行が存在しているか調べる
      // - LINQ の Any メソッドは条件に一致したものが1つでも存在すれば true を返す
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var isExist = File.ReadLines( filePath, Encoding.UTF8 )
          .Where( s => !String.IsNullOrWhiteSpace( s ) ) // 空行や空白行以外を取り出す
#if MYTEST
          .Any( s => s.All( c => Char.IsDigit( c ) ) );  // 数字が存在しているか?
#else
          .Any( s => s.All( c => Char.IsLetterOrDigit( c ) ) ); // 数字・英字が存在しているか?
#endif
        Console.WriteLine( isExist );
      }
    }

    static void StreamReader_3_e()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - LINQ を使って重複行を取り除き並び替える
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadLines( filePath, Encoding.UTF8 )
          .Distinct()               // 重複を削除
          .OrderBy( s => s.Length ) // 文字列長順にソート
          .ToArray();
        foreach ( var line in lines )
        {
          Console.WriteLine( line );
        }
      }
    }

    static void StreamReader_3_f()
    {
      // 9.1.3 テキストファイルを IEnumerable<string> として扱う
      // - LINQ を使って各行に行番号を付与する
      // - LINQ の Select メソッドは,コレクションから要素を1つ取り出して変換した結果を返す
      var methodName = MethodBase.GetCurrentMethod().Name;
      Console.WriteLine( "\n********* {0} *********", methodName );

      var filePath = @"greeting.txt";
      if ( File.Exists( filePath ) )
      {
        var lines = File.ReadLines( filePath, Encoding.UTF8 )
          .Select( ( s, ix ) => String.Format( "{0,4}: {1}", ix + 1, s ) )
          .ToArray();
        foreach ( var line in lines )
        {
          Console.WriteLine( line );
        }
      }
    }
  }
}