Index: src/Common/NetTopologySuite/IO/GeoTools/Dbase/DbaseFileReader.cs =================================================================== diff -u -r8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9 -r5fc71a385897af92ccb092f2f969b5709afab85a --- src/Common/NetTopologySuite/IO/GeoTools/Dbase/DbaseFileReader.cs (.../DbaseFileReader.cs) (revision 8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9) +++ src/Common/NetTopologySuite/IO/GeoTools/Dbase/DbaseFileReader.cs (.../DbaseFileReader.cs) (revision 5fc71a385897af92ccb092f2f969b5709afab85a) @@ -6,51 +6,130 @@ namespace GisSharpBlog.NetTopologySuite.IO { - /// - /// Class that allows records in a dbase file to be enumerated. - /// - public class DbaseFileReader : IEnumerable - { + /// + /// Class that allows records in a dbase file to be enumerated. + /// + public class DbaseFileReader : IEnumerable + { + private DbaseFileHeader _header = null; + private readonly string _filename; + + #region Constructors + /// + /// Initializes a new instance of the DbaseFileReader class. + /// + /// + public DbaseFileReader(string filename) + { + if (filename == null) + { + throw new ArgumentNullException(filename); + } + // check for the file existing here, otherwise we will not get an error + //until we read the first record or read the header. + if (!File.Exists(filename)) + { + throw new FileNotFoundException(String.Format("Could not find file \"{0}\"", filename)); + } + _filename = filename; + } + + #endregion + + #region Methods + + /// + /// Gets the header information for the dbase file. + /// + /// DbaseFileHeader contain header and field information. + public DbaseFileHeader GetHeader() + { + if (_header == null) + { + FileStream stream = new FileStream(_filename, FileMode.Open, FileAccess.Read); + BinaryReader dbfStream = new BinaryReader(stream); + + _header = new DbaseFileHeader(); + // read the header + _header.ReadHeader(dbfStream); + + dbfStream.Close(); + stream.Close(); + } + return _header; + } + + #endregion + + #region Implementation of IEnumerable + + /// + /// Gets the object that allows iterating through the members of the collection. + /// + /// + /// An object that implements the IEnumerator interface. + /// + public IEnumerator GetEnumerator() + { + return new DbaseFileEnumerator(this); + } + + #endregion + + /// /// /// - private class DbaseFileEnumerator : IEnumerator, IDisposable - { - DbaseFileReader _parent; - ArrayList _arrayList; - int _iCurrentRecord=0; - private BinaryReader _dbfStream = null; - private int _readPosition = 0; - private DbaseFileHeader _header = null; - protected string[] _fieldNames = null; + private class DbaseFileEnumerator : IEnumerator, IDisposable + { + protected string[] _fieldNames = null; + private DbaseFileReader _parent; + private ArrayList _arrayList; + private int _iCurrentRecord = 0; + private readonly BinaryReader _dbfStream = null; + private int _readPosition = 0; + private DbaseFileHeader _header = null; /// /// Initializes a new instance of the class. /// /// public DbaseFileEnumerator(DbaseFileReader parent) - { - _parent = parent; - FileStream stream = new FileStream(parent._filename, FileMode.Open, FileAccess.Read, FileShare.Read); - _dbfStream = new BinaryReader(stream, Encoding.Default); - ReadHeader(); - } + { + _parent = parent; + FileStream stream = new FileStream(parent._filename, FileMode.Open, FileAccess.Read, FileShare.Read); + _dbfStream = new BinaryReader(stream, Encoding.Default); + ReadHeader(); + } - #region Implementation of IEnumerator + #region IDisposable Members /// + /// Performs application-defined tasks associated with freeing, releasing, + /// or resetting unmanaged resources. + /// + public void Dispose() + { + _dbfStream.Close(); + } + + #endregion + + #region Implementation of IEnumerator + + /// /// Sets the enumerator to its initial position, which is /// before the first element in the collection. /// /// /// The collection was modified after the enumerator was created. /// - public void Reset() - { + public void Reset() + { _dbfStream.BaseStream.Seek(_header.HeaderLength, SeekOrigin.Begin); _iCurrentRecord = 0; - //throw new InvalidOperationException(); - } + //throw new InvalidOperationException(); + } /// /// Advances the enumerator to the next element of the collection. @@ -62,19 +141,21 @@ /// /// The collection was modified after the enumerator was created. /// - public bool MoveNext() - { - _iCurrentRecord++; - if (_iCurrentRecord <= _header.NumRecords) - _arrayList = this.Read(); - bool more= true; - if (_iCurrentRecord > _header.NumRecords) - { - //this._dbfStream.Close(); - more = false; - } - return more; - } + public bool MoveNext() + { + _iCurrentRecord++; + if (_iCurrentRecord <= _header.NumRecords) + { + _arrayList = Read(); + } + bool more = true; + if (_iCurrentRecord > _header.NumRecords) + { + //this._dbfStream.Close(); + more = false; + } + return more; + } /// /// Gets the current element in the collection. @@ -85,226 +166,156 @@ /// The enumerator is positioned before the first element of the collection /// or after the last element. /// - public object Current - { - get - { - return _arrayList; - } - } + public object Current + { + get + { + return _arrayList; + } + } /// /// /// - protected void ReadHeader() - { - _header = new DbaseFileHeader(); - // read the header - _header.ReadHeader(_dbfStream); + protected void ReadHeader() + { + _header = new DbaseFileHeader(); + // read the header + _header.ReadHeader(_dbfStream); - // how many records remain - _readPosition = _header.HeaderLength; - } + // how many records remain + _readPosition = _header.HeaderLength; + } - /// - /// Read a single dbase record - /// - /// - /// The read shapefile record, - /// or null if there are no more records. - /// - private ArrayList Read() - { - ArrayList attrs = null; - - bool foundRecord = false; - while (!foundRecord) - { - // retrieve the record length - int tempNumFields = _header.NumFields; - - // storage for the actual values - attrs = new ArrayList(tempNumFields); - - // read the deleted flag - char tempDeleted = (char)_dbfStream.ReadChar(); - - // read the record length - int tempRecordLength = 1; // for the deleted character just read. - - // read the Fields - for (int j = 0; j < tempNumFields; j++) - { - // find the length of the field. - int tempFieldLength = _header.Fields[j].Length; - tempRecordLength = tempRecordLength + tempFieldLength; - - // find the field type - char tempFieldType = _header.Fields[j].DbaseType; - - // read the data. - object tempObject = null; - switch (tempFieldType) - { - case 'L': // logical data type, one character (T,t,F,f,Y,y,N,n) - char tempChar = (char)_dbfStream.ReadByte(); - if ((tempChar == 'T') || (tempChar == 't') || (tempChar == 'Y') || (tempChar == 'y')) - tempObject = true; - else tempObject = false; - break; + /// + /// Read a single dbase record + /// + /// + /// The read shapefile record, + /// or null if there are no more records. + /// + private ArrayList Read() + { + ArrayList attrs = null; - case 'C': // character record. - char[] sbuffer = new char[tempFieldLength]; - sbuffer = _dbfStream.ReadChars(tempFieldLength); - // use an encoding to ensure all 8 bits are loaded - // tempObject = new string(sbuffer, "ISO-8859-1").Trim(); + bool foundRecord = false; + while (!foundRecord) + { + // retrieve the record length + int tempNumFields = _header.NumFields; - //HACK: this can be made more efficient - tempObject = new string(sbuffer).Trim().Replace("\0",String.Empty); //.ToCharArray(); - break; - - case 'D': // date data type. - char[] ebuffer = new char[8]; - ebuffer = _dbfStream.ReadChars(8); - string tempString = new string(ebuffer, 0, 4); + // storage for the actual values + attrs = new ArrayList(tempNumFields); - int year; - if (!Int32.TryParse(tempString, NumberStyles.Integer, CultureInfo.InvariantCulture, out year)) - break; - tempString = new string(ebuffer, 4, 2); + // read the deleted flag + char tempDeleted = (char) _dbfStream.ReadChar(); - int month; - if (!Int32.TryParse(tempString, NumberStyles.Integer, CultureInfo.InvariantCulture, out month)) - break; - tempString = new string(ebuffer, 6, 2); - - int day; - if (!Int32.TryParse(tempString, NumberStyles.Integer, CultureInfo.InvariantCulture, out day)) - break; + // read the record length + int tempRecordLength = 1; // for the deleted character just read. - tempObject = new DateTime(year, month, day); - break; - - case 'N': // number - case 'F': // floating point number - char[] fbuffer = new char[tempFieldLength]; - fbuffer = _dbfStream.ReadChars(tempFieldLength); - tempString = new string(fbuffer); - try - { - tempObject = Double.Parse(tempString.Trim(), CultureInfo.InvariantCulture); - } - catch (FormatException) - { - // if we can't format the number, just save it as a string - tempObject = tempString; - } - break; - - default: - throw new NotSupportedException("Do not know how to parse Field type "+tempFieldType); - } - attrs.Add(tempObject); - } - - // ensure that the full record has been read. - if (tempRecordLength < _header.RecordLength) - { - byte[] tempbuff = new byte[_header.RecordLength-tempRecordLength]; - tempbuff = _dbfStream.ReadBytes(_header.RecordLength-tempRecordLength); - } - - // add the row if it is not deleted. - if (tempDeleted != '*') - { - foundRecord = true; - } - } - return attrs; - } + // read the Fields + for (int j = 0; j < tempNumFields; j++) + { + // find the length of the field. + int tempFieldLength = _header.Fields[j].Length; + tempRecordLength = tempRecordLength + tempFieldLength; - #endregion + // find the field type + char tempFieldType = _header.Fields[j].DbaseType; - #region IDisposable Members + // read the data. + object tempObject = null; + switch (tempFieldType) + { + case 'L': // logical data type, one character (T,t,F,f,Y,y,N,n) + char tempChar = (char) _dbfStream.ReadByte(); + if ((tempChar == 'T') || (tempChar == 't') || (tempChar == 'Y') || (tempChar == 'y')) + { + tempObject = true; + } + else + { + tempObject = false; + } + break; - /// - /// Performs application-defined tasks associated with freeing, releasing, - /// or resetting unmanaged resources. - /// - public void Dispose() - { - _dbfStream.Close(); - } + case 'C': // character record. + char[] sbuffer = new char[tempFieldLength]; + sbuffer = _dbfStream.ReadChars(tempFieldLength); + // use an encoding to ensure all 8 bits are loaded + // tempObject = new string(sbuffer, "ISO-8859-1").Trim(); - #endregion - } + //HACK: this can be made more efficient + tempObject = new string(sbuffer).Trim().Replace("\0", String.Empty); //.ToCharArray(); + break; - private DbaseFileHeader _header = null; - private string _filename; + case 'D': // date data type. + char[] ebuffer = new char[8]; + ebuffer = _dbfStream.ReadChars(8); + string tempString = new string(ebuffer, 0, 4); - #region Constructors + int year; + if (!Int32.TryParse(tempString, NumberStyles.Integer, CultureInfo.InvariantCulture, out year)) + { + break; + } + tempString = new string(ebuffer, 4, 2); - /// - /// Initializes a new instance of the DbaseFileReader class. - /// - /// - public DbaseFileReader(string filename) - { - if (filename==null) - { - throw new ArgumentNullException(filename); - } - // check for the file existing here, otherwise we will not get an error - //until we read the first record or read the header. - if (!File.Exists(filename)) - { - throw new FileNotFoundException(String.Format("Could not find file \"{0}\"",filename)); - } - _filename = filename; - - } - - #endregion + int month; + if (!Int32.TryParse(tempString, NumberStyles.Integer, CultureInfo.InvariantCulture, out month)) + { + break; + } + tempString = new string(ebuffer, 6, 2); - #region Methods + int day; + if (!Int32.TryParse(tempString, NumberStyles.Integer, CultureInfo.InvariantCulture, out day)) + { + break; + } - /// - /// Gets the header information for the dbase file. - /// - /// DbaseFileHeader contain header and field information. - public DbaseFileHeader GetHeader() - { - if (_header==null) - { - FileStream stream = new FileStream(_filename, FileMode.Open, FileAccess.Read); - BinaryReader dbfStream = new BinaryReader(stream); + tempObject = new DateTime(year, month, day); + break; - _header = new DbaseFileHeader(); - // read the header - _header.ReadHeader(dbfStream); + case 'N': // number + case 'F': // floating point number + char[] fbuffer = new char[tempFieldLength]; + fbuffer = _dbfStream.ReadChars(tempFieldLength); + tempString = new string(fbuffer); + try + { + tempObject = Double.Parse(tempString.Trim(), CultureInfo.InvariantCulture); + } + catch (FormatException) + { + // if we can't format the number, just save it as a string + tempObject = tempString; + } + break; - dbfStream.Close(); - stream.Close(); + default: + throw new NotSupportedException("Do not know how to parse Field type " + tempFieldType); + } + attrs.Add(tempObject); + } - } - return _header; - } - - #endregion + // ensure that the full record has been read. + if (tempRecordLength < _header.RecordLength) + { + byte[] tempbuff = new byte[_header.RecordLength - tempRecordLength]; + tempbuff = _dbfStream.ReadBytes(_header.RecordLength - tempRecordLength); + } - #region Implementation of IEnumerable + // add the row if it is not deleted. + if (tempDeleted != '*') + { + foundRecord = true; + } + } + return attrs; + } - /// - /// Gets the object that allows iterating through the members of the collection. - /// - /// - /// An object that implements the IEnumerator interface. - /// - public IEnumerator GetEnumerator() - { - return new DbaseFileEnumerator(this); - } - - #endregion - } -} + #endregion + } + } +} \ No newline at end of file