📄 dbasereader.cs
字号:
// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Note:
// Good stuff on DBase format: http://www.clicketyclick.dk/databases/xbase/format/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;
namespace SharpMap.Data.Providers
{
internal class DbaseReader : IDisposable
{
private struct DbaseField
{
public string ColumnName;
public Type DataType;
public int Address;
public int Length;
public int Decimals;
}
private DateTime _lastUpdate;
private int _NumberOfRecords;
private Int16 _HeaderLength;
private Int16 _RecordLength;
private string _filename;
private DbaseField[] DbaseColumns;
private FileStream fs;
private BinaryReader br;
private bool HeaderIsParsed;
public DbaseReader(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException(String.Format("Could not find file \"{0}\"", filename));
_filename = filename;
HeaderIsParsed = false;
}
private bool _isOpen;
public bool IsOpen
{
get { return _isOpen; }
set { _isOpen = value; }
}
public void Open()
{
fs = new FileStream(_filename, FileMode.Open, FileAccess.Read);
br = new BinaryReader(fs);
_isOpen = true;
if (!HeaderIsParsed) //Don't read the header if it's already parsed
ParseDbfHeader(_filename);
}
public void Close()
{
br.Close();
fs.Close();
_isOpen = false;
}
public void Dispose()
{
if(_isOpen)
this.Close();
br = null;
fs = null;
}
// Binary Tree not working yet on Mono
// see bug: http://bugzilla.ximian.com/show_bug.cgi?id=78502
#if !MONO
/// <summary>
/// Indexes a DBF column in a binary tree [NOT COMPLETE]
/// </summary>
/// <typeparam name="T">datatype to be indexed</typeparam>
/// <param name="ColumnId">Column to index</param>
/// <returns></returns>
public SharpMap.Utilities.Indexing.BinaryTree<T, UInt32> CreateDbfIndex<T>(int ColumnId) where T:IComparable<T>
{
SharpMap.Utilities.Indexing.BinaryTree<T, UInt32> tree = new SharpMap.Utilities.Indexing.BinaryTree<T, uint>();
for (uint i = 0; i < ((this._NumberOfRecords>10000)?10000:this._NumberOfRecords); i++)
tree.Add(new SharpMap.Utilities.Indexing.BinaryTree<T, uint>.ItemValue((T)GetValue(i, ColumnId), i));
return tree;
}
#endif
/*
/// <summary>
/// Creates an index on the columns for faster searching [EXPERIMENTAL - Requires Lucene dependencies]
/// </summary>
/// <returns></returns>
public string CreateLuceneIndex()
{
string dir = this._filename + ".idx";
if (!System.IO.Directory.Exists(dir))
System.IO.Directory.CreateDirectory(dir);
Lucene.Net.Index.IndexWriter iw = new Lucene.Net.Index.IndexWriter(dir,new Lucene.Net.Analysis.Standard.StandardAnalyzer(),true);
for (uint i = 0; i < this._NumberOfRecords; i++)
{
FeatureDataRow dr = GetFeature(i,this.NewTable);
Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document();
// Add the object-id as a field, so that index can be maintained.
// This field is not stored with document, it is indexed, but it is not
// tokenized prior to indexing.
//doc.Add(Lucene.Net.Documents.Field.UnIndexed("SharpMap_oid", i.ToString())); //Add OID index
foreach(System.Data.DataColumn col in dr.Table.Columns) //Add and index values from DBF
{
if(col.DataType.Equals(typeof(string)))
// Add the contents as a valued Text field so it will get tokenized and indexed.
doc.Add(Lucene.Net.Documents.Field.UnStored(col.ColumnName,(string)dr[col]));
else
doc.Add(Lucene.Net.Documents.Field.UnStored(col.ColumnName, dr[col].ToString()));
}
iw.AddDocument(doc);
}
iw.Optimize();
iw.Close();
return this._filename + ".idx";
}
*/
/// <summary>
/// Gets the date this file was last updated.
/// </summary>
public DateTime LastUpdate
{
get { return _lastUpdate; }
}
private void ParseDbfHeader(string filename)
{
if (br.ReadByte() != 0x03)
throw new NotSupportedException("Unsupported DBF Type");
_lastUpdate = new DateTime((int)br.ReadByte() + 1900, (int)br.ReadByte(), (int)br.ReadByte()); //Read the last update date
_NumberOfRecords = br.ReadInt32(); // read number of records.
_HeaderLength = br.ReadInt16(); // read length of header structure.
_RecordLength = br.ReadInt16(); // read length of a record
fs.Seek(29, SeekOrigin.Begin); //Seek to encoding flag
_FileEncoding = GetDbaseLanguageDriver(br.ReadByte()); //Read and parse Language driver
fs.Seek(32, SeekOrigin.Begin); //Move past the reserved bytes
int NumberOfColumns = (_HeaderLength - 31) / 32; // calculate the number of DataColumns in the header
DbaseColumns = new DbaseField[NumberOfColumns];
for (int i = 0; i < DbaseColumns.Length;i++)
{
DbaseColumns[i] = new DbaseField();
DbaseColumns[i].ColumnName = System.Text.Encoding.UTF7.GetString((br.ReadBytes(11))).Replace("\0", "").Trim();
char fieldtype = br.ReadChar();
switch (fieldtype)
{
case 'L':
DbaseColumns[i].DataType = typeof(bool);
break;
case 'C':
DbaseColumns[i].DataType = typeof(string);
break;
case 'D':
DbaseColumns[i].DataType = typeof(DateTime);
break;
case 'N':
DbaseColumns[i].DataType = typeof(double);
break;
case 'F':
DbaseColumns[i].DataType = typeof(float);
break;
case 'B':
DbaseColumns[i].DataType = typeof(byte[]);
break;
default:
throw (new NotSupportedException("Invalid or unknown DBase field type '" + fieldtype +
"' in column '" + DbaseColumns[i].ColumnName + "'"));
}
DbaseColumns[i].Address = br.ReadInt32();
int Length = (int)br.ReadByte();
if (Length < 0) Length = Length + 256;
DbaseColumns[i].Length = Length;
DbaseColumns[i].Decimals = (int)br.ReadByte();
//If the double-type doesn't have any decimals, make the type an integer
if (DbaseColumns[i].Decimals == 0 && DbaseColumns[i].DataType == typeof(double))
if (DbaseColumns[i].Length <= 2)
DbaseColumns[i].DataType = typeof(Int16);
else if(DbaseColumns[i].Length<=4)
DbaseColumns[i].DataType = typeof(Int32);
else
DbaseColumns[i].DataType = typeof(Int64);
fs.Seek(fs.Position + 14, 0);
}
HeaderIsParsed = true;
CreateBaseTable();
}
private System.Text.Encoding GetDbaseLanguageDriver(byte dbasecode)
{
switch (dbasecode)
{
case 0x01: return System.Text.Encoding.GetEncoding(437); //DOS USA code page 437
case 0x02: return System.Text.Encoding.GetEncoding(850); // DOS Multilingual code page 850
case 0x03: return System.Text.Encoding.GetEncoding(1252); // Windows ANSI code page 1252
case 0x04: return System.Text.Encoding.GetEncoding(10000); // Standard Macintosh
case 0x08: return System.Text.Encoding.GetEncoding(865); // Danish OEM
case 0x09: return System.Text.Encoding.GetEncoding(437); // Dutch OEM
case 0x0A: return System.Text.Encoding.GetEncoding(850); // Dutch OEM Secondary codepage
case 0x0B: return System.Text.Encoding.GetEncoding(437); // Finnish OEM
case 0x0D: return System.Text.Encoding.GetEncoding(437); // French OEM
case 0x0E: return System.Text.Encoding.GetEncoding(850); // French OEM Secondary codepage
case 0x0F: return System.Text.Encoding.GetEncoding(437); // German OEM
case 0x10: return System.Text.Encoding.GetEncoding(850); // German OEM Secondary codepage
case 0x11: return System.Text.Encoding.GetEncoding(437); // Italian OEM
case 0x12: return System.Text.Encoding.GetEncoding(850); // Italian OEM Secondary codepage
case 0x13: return System.Text.Encoding.GetEncoding(932); // Japanese Shift-JIS
case 0x14: return System.Text.Encoding.GetEncoding(850); // Spanish OEM secondary codepage
case 0x15: return System.Text.Encoding.GetEncoding(437); // Swedish OEM
case 0x16: return System.Text.Encoding.GetEncoding(850); // Swedish OEM secondary codepage
case 0x17: return System.Text.Encoding.GetEncoding(865); // Norwegian OEM
case 0x18: return System.Text.Encoding.GetEncoding(437); // Spanish OEM
case 0x19: return System.Text.Encoding.GetEncoding(437); // English OEM (Britain)
case 0x1A: return System.Text.Encoding.GetEncoding(850); // English OEM (Britain) secondary codepage
case 0x1B: return System.Text.Encoding.GetEncoding(437); // English OEM (U.S.)
case 0x1C: return System.Text.Encoding.GetEncoding(863); // French OEM (Canada)
case 0x1D: return System.Text.Encoding.GetEncoding(850); // French OEM secondary codepage
case 0x1F: return System.Text.Encoding.GetEncoding(852); // Czech OEM
case 0x22: return System.Text.Encoding.GetEncoding(852); // Hungarian OEM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -