Saturday, December 23, 2006

C# .Net StreamReader Seek

Today’s development problems gave me more trouble than it should have, so I’m going to post the solution. The problem was using the C# StreamReader to pull a small number of characters from a particular position in a very large file. The methods exposed by the class allowed me to read the stream until the desired location was reached. This was taking too long. The first thing I tried was to use its basestream property, then its seek function. This allowed me to do exactly what I wanted, set the file pointer to a position in the file. This lead me to the next problem.

After the StreamReader.basestream.seek() function was implemented, the usual StreamReader functions are being used to read the file. Unfortunately, the StreamReader does a little processing on its own to cache data itself and speed up its expected method of use. I found that the size of its cache is 1024 characters. It reads the file in chunks of this size. So, now I have to seek to the position of the file that I want, less a number. Yada yada yada… this is my finally code. I’m not going to bother describing every variable. I'm sure you're bright enough.



reader = new StreamReader(_fileName);
buffer = new char[_recordLength];
///...stuff...
if(_InvalidInitalFileRecordCount != 0)

{
if(reader.Peek()!=-1)
{
//need to close because the peek moves the position on its own. easier to start over.
reader.Close();
reader = new StreamReader(fileName);
long actualPosition = 0;
if(_firstRecordStartPosition > 0)
{
actualPosition = ((_invalidInitalFileRecordCount * _recordLength)+(( _firstRecordStartPosition-1 )));
}
else
{
actualPosition = ((_nvalidInitalFileRecordCount * _recordLength ));
}
int num = (int)(actualPosition / 1024);
long usePosition = num * 1024;
reader.BaseStream.Seek( usePosition ,System.IO.SeekOrigin.Begin);
buffer = new char[(int)(actualPosition - usePosition)];
numberOfCharactersRead = reader.Read(buffer,0,(int)(actualPosition - usePosition));
}
}
buffer = new char[this.RecordLength];
while(reader.Peek()!=-1)
{
newRecord = new StringBuilder();
fileRecord = string.Empty;
numberOfCharactersRead = reader.Read(buffer,0,_recordLength);
newRecord.Append(buffer);
fileRecord = newRecord.ToString();
actualLineNumber++;
///...other stuff....
}

No comments: