【C#】【VB.NET】StreamReaderでスキップして1行先を読み込む方法
CSVを読み込むときに、ループの現在行を変えずに次の行をカンニングしたいケースがあります。
StreamReaderはランダムアクセスできないものですが、継承クラスを利用することで可能だったのでメモします。
この力、マリアンヌ様以外に使うことがあろうとはな!!
参考サイト
stackoverflow.com
C#の場合
using System.IO; public class PositionableStreamReader : StreamReader { public PositionableStreamReader(string path) : base(path) { } private int myLineEndingCharacterLength = Environment.NewLine.Length; public int LineEndingCharacterLength { get { return myLineEndingCharacterLength; } set { myLineEndingCharacterLength = value; } } public override string ReadLine() { string line = base.ReadLine(); if (null != line) myStreamPosition += base.CurrentEncoding.GetByteCount(line) + myLineEndingCharacterLength; return line; } private long myStreamPosition = 0; public long Position { get { return myStreamPosition; } set { myStreamPosition = value; this.BaseStream.Position = value; this.DiscardBufferedData(); } } } /// <summary> /// 使用例 /// </summary> private static void ReadFile(string file) { using (PositionableStreamReader positionableStreamReader = new PositionableStreamReader(file)) { while (positionableStreamReader.Peek() >= 0) { // 1行読み込みする string readLine = positionableStreamReader.ReadLine(); string[] split = readLine.Split(','); // 処理・・・ // 1行先をカンニングする if (positionableStreamReader.Peek() < 0) { // 最終行まで到達した } else { // ストリームの現在位置を記録する long position = positionableStreamReader.Position; // 1行先を取得する string nextLine = positionableStreamReader.ReadLine(); // ストリームの現在位置を戻す positionableStreamReader.Position = position; // 処理・・・ } } } }
VB.NETの場合
Imports System.IO Class PositionableStreamReader Inherits StreamReader Sub New(path As String) MyBase.New(path) End Sub Private myLineEndingCharacterLength As Integer = Environment.NewLine.Length Public Property LineEndingCharacterLength() As Integer Get Return myLineEndingCharacterLength End Get Set(ByVal value As Integer) myLineEndingCharacterLength = value End Set End Property Public Overrides Function ReadLine() As String Dim line As String = MyBase.ReadLine() If line IsNot Nothing Then myStreamPosition += MyBase.CurrentEncoding.GetByteCount(line) + myLineEndingCharacterLength End If Return line End Function Private myStreamPosition As Long = 0 Public Property Position() As Long Get Return myStreamPosition End Get Set(ByVal value As Long) myStreamPosition = value MyBase.BaseStream.Position = value MyBase.DiscardBufferedData() End Set End Property End Class ''' <summary> ''' 使用例 ''' </summary> Private Sub ReadFile(file As String) Using positionableStreamReader As New PositionableStreamReader(file) While (positionableStreamReader.Peek() >= 0) ' 1行読み込みする Dim readLine As String = positionableStreamReader.ReadLine() Dim split As String() = readLine.Split(","c) ' 処理・・・ ' 1行先をカンニングする If (positionableStreamReader.Peek() < 0) Then ' 最終行まで到達した Else ' ストリームの現在位置を記録する Dim position As Long = positionableStreamReader.Position ' 1行先を取得する Dim nextLine As String = positionableStreamReader.ReadLine() ' ストリームの現在位置を戻す positionableStreamReader.Position = position ' 処理・・・ End If End While End Using End Sub