你的位置:首页 > ASP.net教程

[ASP.net教程]C#生成DBF文件


C# 生成DBF,无需注册Microsoft.Jet.OLEDB。

 1 namespace ConsoleApplication 2 { 3   class Program 4   { 5     static void Main(string[] args) 6     { 7       Test(); 8       Console.ReadKey(); 9     }10 11     private static void Test()12     {13       string testPath = AppDomain.CurrentDomain.BaseDirectory;14       var odbf = new DbfFile(Encoding.GetEncoding(936));15       odbf.Open(Path.Combine(testPath, "test.dbf"), FileMode.Create);16 17       //创建列头18       odbf.Header.AddColumn(new DbfColumn("编号", DbfColumn.DbfColumnType.Character, 20, 0));19       odbf.Header.AddColumn(new DbfColumn("名称", DbfColumn.DbfColumnType.Character, 20, 0));20       odbf.Header.AddColumn(new DbfColumn("地址", DbfColumn.DbfColumnType.Character, 20, 0));21       odbf.Header.AddColumn(new DbfColumn("时间", DbfColumn.DbfColumnType.Date));22       odbf.Header.AddColumn(new DbfColumn("余额", DbfColumn.DbfColumnType.Number, 15, 3));23 24       var orec = new DbfRecord(odbf.Header) { AllowDecimalTruncate = true };25       List<User> list = User.GetList();26       foreach (var item in list)27       {28         orec[0] = item.UserCode;29         orec[1] = item.UserName;30         orec[2] = item.Address;31         orec[3] = item.date.ToString("yyyy-MM-dd HH:mm:ss");32         orec[4] = item.money.ToString();33         odbf.Write(orec, true);34       }35       odbf.Close();36     }37   }38 39   public class User40   {41     public string UserCode { get; set; }42     public string UserName { get; set; }43     public string Address { get; set; }44     public DateTime date { get; set; }45     public decimal money { get; set; }46 47     public static List<User> GetList()48     {49       List<User> list = new List<User>();50       list.Add(new User() { UserCode = "A1", UserName = "张三", Address = "上海杨浦", date = DateTime.Now, money = 1000.12m });51       list.Add(new User() { UserCode = "A2", UserName = "李四", Address = "湖北武汉", date = DateTime.Now, money = 31000.008m });52       list.Add(new User() { UserCode = "A3", UserName = "王子龙", Address = "陕西西安", date = DateTime.Now, money = 2000.12m });53       list.Add(new User() { UserCode = "A4", UserName = "李三", Address = "北京", date = DateTime.Now, money = 3000.12m });54       return list;55     }56   }57 58 }

生成的文件截图:

操作DBF文件的部分代码:

 1 /// 2 /// Author: Ahmed Lacevic 3 /// Date: 12/1/2007 4 /// Desc:  5 ///  6 /// Revision History: 7 /// ----------------------------------- 8 ///  Author: 9 ///  Date: 10 ///  Desc: 11  12  13 using System; 14 using System.Collections.Generic; 15 using System.Text; 16 using System.IO; 17 using System.Globalization; 18  19  20 namespace SocialExplorer.IO.FastDBF 21 { 22  23   /// <summary> 24   /// Use this class to create a record and write it to a dbf file. You can use one record object to write all records!! 25   /// It was designed for this kind of use. You can do this by clearing the record of all data  26   /// (call Clear() method) or setting values to all fields again, then write to dbf file.  27   /// This eliminates creating and destroying objects and optimizes memory use. 28   ///  29   /// Once you create a record the header can no longer be modified, since modifying the header would make a corrupt DBF file. 30   /// </summary> 31   public class DbfRecord 32   { 33  34     /// <summary> 35     /// Header provides information on all field types, sizes, precision and other useful information about the DBF. 36     /// </summary> 37     private DbfHeader mHeader = null; 38  39     /// <summary> 40     /// Dbf data are a mix of ASCII characters and binary, which neatly fit in a byte array. 41     /// BinaryWriter would esentially perform the same conversion using the same Encoding class. 42     /// </summary> 43     private byte[] mData = null; 44  45     /// <summary> 46     /// Zero based record index. -1 when not set, new records for example. 47     /// </summary> 48     private int mRecordIndex = -1; 49  50     /// <summary> 51     /// Empty Record array reference used to clear fields quickly (or entire record). 52     /// </summary> 53     private readonly byte[] mEmptyRecord = null; 54  55  56     /// <summary> 57     /// Specifies whether we allow strings to be truncated. If false and string is longer than we can fit in the field, an exception is thrown. 58     /// </summary> 59     private bool mAllowStringTruncate = true; 60  61     /// <summary> 62     /// Specifies whether we allow the decimal portion of numbers to be truncated.  63     /// If false and decimal digits overflow the field, an exception is thrown. 64     /// </summary> 65     private bool mAllowDecimalTruncate = false; 66  67     /// <summary> 68     /// Specifies whether we allow the integer portion of numbers to be truncated. 69     /// If false and integer digits overflow the field, an exception is thrown. 70     /// </summary> 71     private bool mAllowIntegerTruncate = false; 72  73  74     //array used to clear decimals, we can clear up to 40 decimals which is much more than is allowed under DBF spec anyway. 75     //Note: 48 is ASCII code for 0. 76     private static readonly byte[] mDecimalClear = new byte[] {48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, 77                                48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, 78                                48,48,48,48,48,48,48,48,48,48,48,48,48,48,48}; 79  80  81     //Warning: do not make this one static because that would not be thread safe!! The reason I have  82     //placed this here is to skip small memory allocation/deallocation which fragments memory in .net. 83     private int[] mTempIntVal = { 0 }; 84  85  86     //Ascii Encoder 87     private readonly Encoding encoding = Encoding.ASCII; 88  89     /// <summary> 90     /// Column Name to Column Index map 91     /// </summary> 92     private readonly Dictionary<string, int> mColNameToConIdx = new Dictionary<string, int>(StringComparer.InvariantCulture); 93  94  95  96     /// <summary> 97     ///  98     /// </summary> 99     /// <param name="oHeader">Dbf Header will be locked once a record is created 100     /// since the record size is fixed and if the header was modified it would corrupt the DBF file.</param>101     public DbfRecord(DbfHeader oHeader)102     {103       mHeader = oHeader;104       mHeader.Locked = true;105 106       //create a buffer to hold all record data. We will reuse this buffer to write all data to the file.107       mData = new byte[mHeader.RecordLength];108       mEmptyRecord = mHeader.EmptyDataRecord;109       encoding = oHeader.encoding;110 111       for (int i = 0; i < oHeader.mFields.Count; i++)112         mColNameToConIdx[oHeader.mFields[i].Name] = i;113     }114 115 116     /// <summary>117     /// Set string data to a column, if the string is longer than specified column length it will be truncated!118     /// If dbf column type is not a string, input will be treated as dbf column 119     /// type and if longer than length an exception will be thrown.120     /// </summary>121     /// <param name="nColIndex"></param>122     /// <returns></returns>123     public string this[int nColIndex]124     {125 126       set127       {128 129         DbfColumn ocol = mHeader[nColIndex];130         DbfColumn.DbfColumnType ocolType = ocol.ColumnType;131 132 133         //134         //if an empty value is passed, we just clear the data, and leave it blank.135         //note: test have shown that testing for null and checking length is faster than comparing to "" empty str :)136         //------------------------------------------------------------------------------------------------------------137         if (string.IsNullOrEmpty(value))138         {139           //this is like NULL data, set it to empty. i looked at SAS DBF output when a null value exists 140           //and empty data are output. we get the same result, so this looks good.141           Buffer.BlockCopy(mEmptyRecord, ocol.DataAddress, mData, ocol.DataAddress, ocol.Length);142 143         }144         else145         {146 147           //set values according to data type:148           //-------------------------------------------------------------149           if (ocolType == DbfColumn.DbfColumnType.Character)150           {151             if (!mAllowStringTruncate && value.Length > ocol.Length)152               throw new DbfDataTruncateException("Value not set. String truncation would occur and AllowStringTruncate flag is set to false. To supress this exception change AllowStringTruncate to true.");153 154             //BlockCopy copies bytes. First clear the previous value, then set the new one.155             Buffer.BlockCopy(mEmptyRecord, ocol.DataAddress, mData, ocol.DataAddress, ocol.Length);156             encoding.GetBytes(value, 0, value.Length > ocol.Length ? ocol.Length : value.Length, mData, ocol.DataAddress);157 158           }159           else if (ocolType == DbfColumn.DbfColumnType.Number)160           {161 162             if (ocol.DecimalCount == 0)163             {164 165               //integers166               //----------------------------------167 168               //throw an exception if integer overflow would occur169               if (!mAllowIntegerTruncate && value.Length > ocol.Length)170                 throw new DbfDataTruncateException("Value not set. Integer does not fit and would be truncated. AllowIntegerTruncate is set to false. To supress this exception set AllowIntegerTruncate to true, although that is not recomended.");171 172 173               //clear all numbers, set to [space].174               //-----------------------------------------------------175               Buffer.BlockCopy(mEmptyRecord, 0, mData, ocol.DataAddress, ocol.Length);176 177 178               //set integer part, CAREFUL not to overflow buffer! (truncate instead)179               //-----------------------------------------------------------------------180               int nNumLen = value.Length > ocol.Length ? ocol.Length : value.Length;181               encoding.GetBytes(value, 0, nNumLen, mData, (ocol.DataAddress + ocol.Length - nNumLen));182 183             }184             else185             {186 187               ///TODO: we can improve perfomance here by not using temp char arrays cDec and cNum,188               ///simply direcly copy from source string using encoding!189 190 191               //break value down into integer and decimal portions192               //--------------------------------------------------------------------------193               int nidxDecimal = value.IndexOf('.'); //index where the decimal point occurs194               char[] cDec = null; //decimal portion of the number195               char[] cNum = null; //integer portion196 197               if (nidxDecimal > -1)198               {199                 cDec = value.Substring(nidxDecimal + 1).Trim().ToCharArray();200                 cNum = value.Substring(0, nidxDecimal).ToCharArray();201 202                 //throw an exception if decimal overflow would occur203                 if (!mAllowDecimalTruncate && cDec.Length > ocol.DecimalCount)204                   throw new DbfDataTruncateException("Value not set. Decimal does not fit and would be truncated. AllowDecimalTruncate is set to false. To supress this exception set AllowDecimalTruncate to true.");205 206               }207               else208                 cNum = value.ToCharArray();209 210 211               //throw an exception if integer overflow would occur212               if (!mAllowIntegerTruncate && cNum.Length > ocol.Length - ocol.DecimalCount - 1)213                 throw new DbfDataTruncateException("Value not set. Integer does not fit and would be truncated. AllowIntegerTruncate is set to false. To supress this exception set AllowIntegerTruncate to true, although that is not recomended.");214 215 216 217               //clear all decimals, set to 0.218               //-----------------------------------------------------219               Buffer.BlockCopy(mDecimalClear, 0, mData, (ocol.DataAddress + ocol.Length - ocol.DecimalCount), ocol.DecimalCount);220 221               //clear all numbers, set to [space].222               Buffer.BlockCopy(mEmptyRecord, 0, mData, ocol.DataAddress, (ocol.Length - ocol.DecimalCount));223 224 225 226               //set decimal numbers, CAREFUL not to overflow buffer! (truncate instead)227               //-----------------------------------------------------------------------228               if (nidxDecimal > -1)229               {230                 int nLen = cDec.Length > ocol.DecimalCount ? ocol.DecimalCount : cDec.Length;231                 encoding.GetBytes(cDec, 0, nLen, mData, (ocol.DataAddress + ocol.Length - ocol.DecimalCount));232               }233 234               //set integer part, CAREFUL not to overflow buffer! (truncate instead)235               //-----------------------------------------------------------------------236               int nNumLen = cNum.Length > ocol.Length - ocol.DecimalCount - 1 ? (ocol.Length - ocol.DecimalCount - 1) : cNum.Length;237               encoding.GetBytes(cNum, 0, nNumLen, mData, ocol.DataAddress + ocol.Length - ocol.DecimalCount - nNumLen - 1);238 239 240               //set decimal point241               //-----------------------------------------------------------------------242               mData[ocol.DataAddress + ocol.Length - ocol.DecimalCount - 1] = (byte)'.';243 244 245             }246 247 248           }249           else if (ocolType == DbfColumn.DbfColumnType.Integer)250           {251             //note this is a binary Integer type!252             //----------------------------------------------253 254             ///TODO: maybe there is a better way to copy 4 bytes from int to byte array. Some memory function or something.255             mTempIntVal[0] = Convert.ToInt32(value);256             Buffer.BlockCopy(mTempIntVal, 0, mData, ocol.DataAddress, 4);257 258           }259           else if (ocolType == DbfColumn.DbfColumnType.Memo)260           {261             //copy 10 digits...262             ///TODO: implement MEMO263 264             throw new NotImplementedException("Memo data type functionality not implemented yet!");265 266           }267           else if (ocolType == DbfColumn.DbfColumnType.Boolean)268           {269             if (String.Compare(value, "true", true) == 0 || String.Compare(value, "1", true) == 0 ||270               String.Compare(value, "T", true) == 0 || String.Compare(value, "yes", true) == 0 ||271               String.Compare(value, "Y", true) == 0)272               mData[ocol.DataAddress] = (byte)'T';273             else if (value == " " || value == "?")274               mData[ocol.DataAddress] = (byte)'?';275             else276               mData[ocol.DataAddress] = (byte)'F';277 278           }279           else if (ocolType == DbfColumn.DbfColumnType.Date)280           {281             //try to parse out date value using Date.Parse() function, then set the value282             DateTime dateval;283             if (DateTime.TryParse(value, out dateval))284             {285               SetDateValue(nColIndex, dateval);286             }287             else288               throw new InvalidOperationException("Date could not be parsed from source string! Please parse the Date and set the value (you can try using DateTime.Parse() or DateTime.TryParse() functions).");289 290           }291           else if (ocolType == DbfColumn.DbfColumnType.Binary)292             throw new InvalidOperationException("Can not use string source to set binary data. Use SetBinaryValue() and GetBinaryValue() functions instead.");293 294           else295             throw new InvalidDataException("Unrecognized data type: " + ocolType.ToString());296 297         }298 299       }300 301       get302       {303         DbfColumn ocol = mHeader[nColIndex];304         return new string(encoding.GetChars(mData, ocol.DataAddress, ocol.Length));305 306       }307     }308 309     /// <summary>310     /// Set string data to a column, if the string is longer than specified column length it will be truncated!311     /// If dbf column type is not a string, input will be treated as dbf column 312     /// type and if longer than length an exception will be thrown.313     /// </summary>314     /// <param name="nColName"></param>315     /// <returns></returns>316     public string this[string nColName]317     {318       get319       {320         if (mColNameToConIdx.ContainsKey(nColName))321           return this[mColNameToConIdx[nColName]];322         throw new InvalidOperationException(string.Format("There's no column with name '{0}'", nColName));323       }324       set325       {326         if (mColNameToConIdx.ContainsKey(nColName))327           this[mColNameToConIdx[nColName]] = value;328         else329           throw new InvalidOperationException(string.Format("There's no column with name '{0}'", nColName));330       }331     }332 333     /// <summary>334     /// Get date value.335     /// </summary>336     /// <param name="nColIndex"></param>337     /// <returns></returns>338     public DateTime GetDateValue(int nColIndex)339     {340       DbfColumn ocol = mHeader[nColIndex];341 342       if (ocol.ColumnType == DbfColumn.DbfColumnType.Date)343       {344         string sDateVal = encoding.GetString(mData, ocol.DataAddress, ocol.Length);345         return DateTime.ParseExact(sDateVal, "yyyyMMdd", CultureInfo.InvariantCulture);346 347       }348       else349         throw new Exception("Invalid data type. Column '" + ocol.Name + "' is not a date column.");350 351     }352 353 354     /// <summary>355     /// Get date value.356     /// </summary>357     /// <param name="nColIndex"></param>358     /// <returns></returns>359     public void SetDateValue(int nColIndex, DateTime value)360     {361 362       DbfColumn ocol = mHeader[nColIndex];363       DbfColumn.DbfColumnType ocolType = ocol.ColumnType;364 365 366       if (ocolType == DbfColumn.DbfColumnType.Date)367       {368 369         //Format date and set value, date format is like this: yyyyMMdd370         //-------------------------------------------------------------371         encoding.GetBytes(value.ToString("yyyyMMdd"), 0, ocol.Length, mData, ocol.DataAddress);372 373       }374       else375         throw new Exception("Invalid data type. Column is of '" + ocol.ColumnType.ToString() + "' type, not date.");376 377 378     }379 380 381     /// <summary>382     /// Clears all data in the record.383     /// </summary>384     public void Clear()385     {386       Buffer.BlockCopy(mEmptyRecord, 0, mData, 0, mEmptyRecord.Length);387       mRecordIndex = -1;388 389     }390 391 392     /// <summary>393     /// returns a string representation of this record.394     /// </summary>395     /// <returns></returns>396     public override string ToString()397     {398       return new string(encoding.GetChars(mData));399     }400 401 402     /// <summary>403     /// Gets/sets a zero based record index. This information is not directly stored in DBF. 404     /// It is the location of this record within the DBF. 405     /// </summary>406     /// <remarks>407     /// This property is managed from outside this object,408     /// CDbfFile object updates it when records are read. The reason we don't set it in the Read() 409     /// function within this object is that the stream can be forward-only so the Position property 410     /// is not available and there is no way to figure out what index the record was unless you 411     /// count how many records were read, and that's exactly what CDbfFile does.412     /// </remarks>413     public int RecordIndex414     {415       get416       {417         return mRecordIndex;418       }419       set420       {421         mRecordIndex = value;422       }423     }424 425 426     /// <summary>427     /// Returns/sets flag indicating whether this record was tagged deleted. 428     /// </summary>429     /// <remarks>Use CDbf4File.Compress() function to rewrite dbf removing records flagged as deleted.</remarks>430     /// <seealso cref="CDbf4File.Compress() function"/>431     public bool IsDeleted432     {433       get { return mData[0] == '*'; }434       set { mData[0] = value ? (byte)'*' : (byte)' '; }435     }436 437 438     /// <summary>439     /// Specifies whether strings can be truncated. If false and string is longer than can fit in the field, an exception is thrown.440     /// Default is True.441     /// </summary>442     public bool AllowStringTurncate443     {444       get { return mAllowStringTruncate; }445       set { mAllowStringTruncate = value; }446     }447 448     /// <summary>449     /// Specifies whether to allow the decimal portion of numbers to be truncated. 450     /// If false and decimal digits overflow the field, an exception is thrown. Default is false.451     /// </summary>452     public bool AllowDecimalTruncate453     {454       get { return mAllowDecimalTruncate; }455       set { mAllowDecimalTruncate = value; }456     }457 458 459     /// <summary>460     /// Specifies whether integer portion of numbers can be truncated.461     /// If false and integer digits overflow the field, an exception is thrown. 462     /// Default is False.463     /// </summary>464     public bool AllowIntegerTruncate465     {466       get { return mAllowIntegerTruncate; }467       set { mAllowIntegerTruncate = value; }468     }469 470 471     /// <summary>472     /// Returns header object associated with this record.473     /// </summary>474     public DbfHeader Header475     {476       get477       {478         return mHeader;479       }480     }481 482 483     /// <summary>484     /// Get column by index.485     /// </summary>486     /// <param name="index"></param>487     /// <returns></returns>488     public DbfColumn Column(int index)489     {490       return mHeader[index];491     }492 493     /// <summary>494     /// Get column by name.495     /// </summary>496     /// <param name="index"></param>497     /// <returns></returns>498     public DbfColumn Column(string sName)499     {500       return mHeader[sName];501     }502 503     /// <summary>504     /// Gets column count from header.505     /// </summary>506     public int ColumnCount507     {508       get509       {510         return mHeader.ColumnCount;511       }512     }513 514     /// <summary>515     /// Finds a column index by searching sequentially through the list. Case is ignored. Returns -1 if not found.516     /// </summary>517     /// <param name="sName">Column name.</param>518     /// <returns>Column index (0 based) or -1 if not found.</returns>519     public int FindColumn(string sName)520     {521       return mHeader.FindColumn(sName);522     }523 524     /// <summary>525     /// Writes data to stream. Make sure stream is positioned correctly because we simply write out the data to it.526     /// </summary>527     /// <param name="osw"></param>528     protected internal void Write(Stream osw)529     {530       osw.Write(mData, 0, mData.Length);531 532     }533 534 535     /// <summary>536     /// Writes data to stream. Make sure stream is positioned correctly because we simply write out data to it, and clear the record.537     /// </summary>538     /// <param name="osw"></param>539     protected internal void Write(Stream obw, bool bClearRecordAfterWrite)540     {541       obw.Write(mData, 0, mData.Length);542 543       if (bClearRecordAfterWrite)544         Clear();545 546     }547 548 549     /// <summary>550     /// Read record from stream. Returns true if record read completely, otherwise returns false.551     /// </summary>552     /// <param name="obr"></param>553     /// <returns></returns>554     protected internal bool Read(Stream obr)555     {556       return obr.Read(mData, 0, mData.Length) >= mData.Length;557     }558 559     protected internal string ReadValue(Stream obr, int colIndex)560     {561       DbfColumn ocol = mHeader[colIndex];562       return new string(encoding.GetChars(mData, ocol.DataAddress, ocol.Length));563 564     }565 566   }567 }

View Code

 

完整代码下载(含FastDBF源代码):下载