示例#1
0
文件: DbfFile.cs 项目: lankosa/io
        public bool ReadValue(int rowIndex, int columnIndex, out string result)
        {
            result = String.Empty;

            DbfColumn ocol = _header[columnIndex];

            //move to the specified record, note that an exception will be thrown is stream is not seekable!
            //This is ok, since we provide a function to check whether the stream is seekable.
            long nSeekToPosition = _header.HeaderLength + (rowIndex * _header.RecordLength) + ocol.DataAddress;

            //check whether requested record exists. Subtract 1 from file length (there is a terminating character 1A at the end of the file)
            //so if we hit end of file, there are no more records, so return false;
            if (rowIndex < 0 || _dbfFile.Length - 1 <= nSeekToPosition)
            {
                return(false);
            }

            //move to position and read
            _dbfFile.Seek(nSeekToPosition, SeekOrigin.Begin);

            //read the value
            byte[] data = new byte[ocol.Length];
            _dbfFile.Read(data, 0, ocol.Length);
            result = new string(encoding.GetChars(data, 0, ocol.Length));

            return(true);
        }
示例#2
0
        /// <summary>
        /// Get date value.
        /// </summary>
        /// <param name="nColIndex"></param>
        /// <returns></returns>
        public DateTime GetDateValue(int nColIndex)
        {
            DbfColumn ocol = _header[nColIndex];

            if (ocol.ColumnType == DbfColumn.DbfColumnType.Date)
            {
                string sDateVal = _encoding.GetString(_data, ocol.DataAddress, ocol.Length);
                return(DateTime.ParseExact(sDateVal, "yyyyMMdd", CultureInfo.InvariantCulture));
            }
            else
            {
                throw new Exception("Invalid data type. Column '" + ocol.Name + "' is not a date column.");
            }
        }
示例#3
0
        /// <summary>
        /// Get date value.
        /// </summary>
        /// <param name="nColIndex"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public void SetDateValue(int nColIndex, DateTime value)
        {
            DbfColumn ocol = _header[nColIndex];

            DbfColumn.DbfColumnType ocolType = ocol.ColumnType;


            if (ocolType == DbfColumn.DbfColumnType.Date)
            {
                //Format date and set value, date format is like this: yyyyMMdd
                //-------------------------------------------------------------
                _encoding.GetBytes(value.ToString("yyyyMMdd"), 0, ocol.Length, _data, ocol.DataAddress);
            }
            else
            {
                throw new Exception("Invalid data type. Column is of '" + ocol.ColumnType.ToString() + "' type, not date.");
            }
        }
示例#4
0
        /// <summary>
        /// Set string data to a column, if the string is longer than specified column length it will be truncated!
        /// If dbf column type is not a string, input will be treated as dbf column
        /// type and if longer than length an exception will be thrown.
        /// </summary>
        /// <param name="nColIndex"></param>
        /// <returns></returns>
        public string this[int nColIndex]
        {
            set
            {
                DbfColumn ocol = _header[nColIndex];
                DbfColumn.DbfColumnType ocolType = ocol.ColumnType;


                //
                //if an empty value is passed, we just clear the data, and leave it blank.
                //note: test have shown that testing for null and checking length is faster than comparing to "" empty str :)
                //------------------------------------------------------------------------------------------------------------
                if (string.IsNullOrEmpty(value))
                {
                    //this is like NULL data, set it to empty. i looked at SAS DBF output when a null value exists
                    //and empty data are output. we get the same result, so this looks good.
                    Buffer.BlockCopy(_emptyRecord, ocol.DataAddress, _data, ocol.DataAddress, ocol.Length);
                }
                else
                {
                    //set values according to data type:
                    //-------------------------------------------------------------
                    if (ocolType == DbfColumn.DbfColumnType.Character)
                    {
                        if (!_allowStringTruncate && value.Length > ocol.Length)
                        {
                            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.");
                        }

                        //BlockCopy copies bytes.  First clear the previous value, then set the new one.
                        Buffer.BlockCopy(_emptyRecord, ocol.DataAddress, _data, ocol.DataAddress, ocol.Length);
                        _encoding.GetBytes(value, 0, value.Length > ocol.Length ? ocol.Length : value.Length, _data, ocol.DataAddress);
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Number)
                    {
                        if (ocol.DecimalCount == 0)
                        {
                            //integers
                            //----------------------------------

                            //throw an exception if integer overflow would occur
                            if (!_allowIntegerTruncate && value.Length > ocol.Length)
                            {
                                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.");
                            }


                            //clear all numbers, set to [space].
                            //-----------------------------------------------------
                            Buffer.BlockCopy(_emptyRecord, 0, _data, ocol.DataAddress, ocol.Length);


                            //set integer part, CAREFUL not to overflow buffer! (truncate instead)
                            //-----------------------------------------------------------------------
                            int nNumLen = value.Length > ocol.Length ? ocol.Length : value.Length;
                            _encoding.GetBytes(value, 0, nNumLen, _data, (ocol.DataAddress + ocol.Length - nNumLen));
                        }
                        else
                        {
                            //simply directly copy from source string using encoding!


                            //break value down into integer and decimal portions
                            //--------------------------------------------------------------------------
                            int    nidxDecimal = value.IndexOf('.'); //index where the decimal point occurs
                            char[] cDec        = null;               //decimal portion of the number
                            char[] cNum;                             //integer portion

                            if (nidxDecimal > -1)
                            {
                                cDec = value.Substring(nidxDecimal + 1).Trim().ToCharArray();
                                cNum = value.Substring(0, nidxDecimal).ToCharArray();

                                //throw an exception if decimal overflow would occur
                                if (!_allowDecimalTruncate && cDec.Length > ocol.DecimalCount)
                                {
                                    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.");
                                }
                            }
                            else
                            {
                                cNum = value.ToCharArray();
                            }


                            //throw an exception if integer overflow would occur
                            if (!_allowIntegerTruncate && cNum.Length > ocol.Length - ocol.DecimalCount - 1)
                            {
                                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.");
                            }


                            //------------------------------------------------------------------------------------------------------------------
                            // NUMERIC TYPE
                            //------------------------------------------------------------------------------------------------------------------

                            //clear all decimals, set to 0.
                            //-----------------------------------------------------
                            Buffer.BlockCopy(DecimalClear, 0, _data, (ocol.DataAddress + ocol.Length - ocol.DecimalCount), ocol.DecimalCount);

                            //clear all numbers, set to [space].
                            Buffer.BlockCopy(_emptyRecord, 0, _data, ocol.DataAddress, (ocol.Length - ocol.DecimalCount));



                            //set decimal numbers, CAREFUL not to overflow buffer! (truncate instead)
                            //-----------------------------------------------------------------------
                            if (nidxDecimal > -1)
                            {
                                // ReSharper disable once PossibleNullReferenceException
                                int nLen = cDec != null && cDec.Length > ocol.DecimalCount ? ocol.DecimalCount : cDec.Length;
                                _encoding.GetBytes(cDec, 0, nLen, _data, (ocol.DataAddress + ocol.Length - ocol.DecimalCount));
                            }

                            //set integer part, CAREFUL not to overflow buffer! (truncate instead)
                            //-----------------------------------------------------------------------
                            int nNumLen = cNum.Length > ocol.Length - ocol.DecimalCount - 1 ? (ocol.Length - ocol.DecimalCount - 1) : cNum.Length;
                            _encoding.GetBytes(cNum, 0, nNumLen, _data, ocol.DataAddress + ocol.Length - ocol.DecimalCount - nNumLen - 1);


                            //set decimal point
                            //-----------------------------------------------------------------------
                            _data[ocol.DataAddress + ocol.Length - ocol.DecimalCount - 1] = (byte)'.';
                        }
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Float)
                    {
                        //------------------------------------------------------------------------------------------------------------------
                        // FLOAT TYPE
                        // example:   value=" 2.40000000000e+001"  Length=19   Decimal-Count=11
                        //------------------------------------------------------------------------------------------------------------------


                        // check size, throw exception if value won't fit:
                        if (value.Length > ocol.Length)
                        {
                            throw new DbfDataTruncateException("Value not set. Float value does not fit and would be truncated.");
                        }


                        if (!double.TryParse(value, out var parsedValue))
                        {
                            //value did not parse, input is not correct.
                            throw new DbfDataTruncateException("Value not set. Float value format is bad: '" + value + "'   expected format: ' 2.40000000000e+001'");
                        }

                        //clear value that was present previously
                        Buffer.BlockCopy(DecimalClear, 0, _data, ocol.DataAddress, ocol.Length);

                        //copy new value at location
                        char[] valueAsCharArray = value.ToCharArray();
                        _encoding.GetBytes(valueAsCharArray, 0, valueAsCharArray.Length, _data, ocol.DataAddress);
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Integer)
                    {
                        //note this is a binary Integer type!
                        //----------------------------------------------

                        //TODO: maybe there is a better way to copy 4 bytes from int to byte array. Some memory function or something.
                        _tempIntVal[0] = Convert.ToInt32(value);
                        Buffer.BlockCopy(_tempIntVal, 0, _data, ocol.DataAddress, 4);
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Memo)
                    {
                        //copy 10 digits...
                        //TODO: implement MEMO

                        throw new NotImplementedException("Memo data type functionality not implemented yet!");
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Boolean)
                    {
                        if (string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(value, "1", StringComparison.OrdinalIgnoreCase) == 0 ||
                            string.Compare(value, "T", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(value, "yes", StringComparison.OrdinalIgnoreCase) == 0 ||
                            string.Compare(value, "Y", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            _data[ocol.DataAddress] = (byte)'T';
                        }
                        else if (value == " " || value == "?")
                        {
                            _data[ocol.DataAddress] = (byte)'?';
                        }
                        else
                        {
                            _data[ocol.DataAddress] = (byte)'F';
                        }
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Date)
                    {
                        //try to parse out date value using Date.Parse() function, then set the value
                        if (DateTime.TryParse(value, out var dateval))
                        {
                            SetDateValue(nColIndex, dateval);
                        }
                        else
                        {
                            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).");
                        }
                    }
                    else if (ocolType == DbfColumn.DbfColumnType.Binary)
                    {
                        throw new InvalidOperationException("Can not use string source to set binary data. Use SetBinaryValue() and GetBinaryValue() functions instead.");
                    }

                    else
                    {
                        throw new InvalidDataException("Unrecognized data type: " + ocolType);
                    }
                }
            }

            get
            {
                DbfColumn ocol = _header[nColIndex];
                return(new string(_encoding.GetChars(_data, ocol.DataAddress, ocol.Length)));
            }
        }