【问题标题】:Reading from a file that has Fixed Length Records从具有固定长度记录的文件中读取
【发布时间】:2013-04-03 14:07:48
【问题描述】:

假设您有一个包含以下内容的文件:

  • 文件头包含:a) 第一个空记录号,b) 每条记录的大小,以及 c) 文件可以容纳的最大记录数。
  • 记录包含:a) 指示记录是空闲还是占用的字节,b) 固定数量的字段。

当我想读取一条随机记录时,我使用这个函数:

int FixedLengthRecordFile :: read (int numRec, FixedLengthFieldsRecord & rec) 

问题是,为了让这个函数工作,我必须事先创建一个FixedLengthFieldsRecord,这意味着指定这条记录所具有的字段数......这不是我想要的。我希望文件处理程序足够“智能”以识别记录有多少个字段,并在读取时动态创建FixedLengthFieldsRecord

我怎样才能做到这一点?该函数必须返回一个int,因为我将它用作退出代码(错误/成功)。

【问题讨论】:

    标签: c++ file fixed-length-record


    【解决方案1】:

    您可以定义 FixedLengthFieldsRecord 类,以便该类本身强制执行正确的记录长度,但允许每条记录中包含任意数量的字段。一个可能的好方法是让 CONSTRUCTOR 从文件中读取下一条记录。

    该类(减去一些必要的错误检查,您可以添加)可以以与以下类似的方式编写(该类假定您在创建此类的对象之前阅读了文件的第一行):

    using namespace std;
    class FixedLengthFieldsRecord
    {
    
        public:
    
            FixedLengthFieldsRecord(int const recordLength, istream & s); // Set the length of the record in the constructor
            bool IsEmpty() const;
            int FieldCount() const; // variable number of fields allowed; but LENGTH of record is enforced (see below)
    
            bool IsValidRecord(); // Does the record contain the correct number of bytes?
            string GetField(int const index) const; // This could throw an exception if the record is not valid
    
        protected:
            // Could have sophisticated functions here to replace fields, remove fields, reorder fields, etc.
    
        // This section contains the actual implementation.
        private:
            vector<string> fields; // The vector contains a VARIABLE number of fields
            bool is_empty;
            bool is_valid;
            int const record_length; // This contains the LENGTH of the record; it is set in the constructor and cannot be changed
    
        // The following variable and function store (and access) ALL the records
        static vector<FixedLengthFieldsRecord> records;
        static read(int numRec, FixedLengthFieldsRecord & rec);
    
    }
    
    FixedLengthFieldsRecord::FixedLengthFieldsRecord(int const recordLength_, istream & s)
        : record_length(recordLength)
    {
        // pseudocode provided here
        // this functionality could be factored into other functions that are called by the constructor
    
        is_valid = true;
    
        is_empty = ReadFirstByte(s); // ReadFirstByte (not shown) reads first byte of current line and returns true if it indicates an empty record
    
        if (!is_empty)
        {
            string field;
            int currentRecordLength = 0;
            while (ReadNextField(s, field)) // ReadNextField() returns true if another field was read from the line (i.e., not end-of-line
            {
                currentRecordLength+= field.length();
            }
            if (currentRecordLength != record_length)
            {
                is_valid = false;
            }
            if (currentRecordLength > record_length)
            {
                break;
            }
            if (is_valid)
            {
                fields.push_back(field);
            }
        }
        if (is_valid)
        {
            records.push_back(*this); // not efficient, nor thread safe - deep copy occurs here
        }
    }
    
    bool FixedLengthFieldsRecord::IsEmpty()
    {
        return is_empty();
    }
    
    bool FixedLengthFieldsRecord::IsValidRecord()
    {
        return is_valid;
    }
    
    string FixedLengthFieldsRecord::GetField(int const index)
    {
        if (!is_valid)
        {
            // throw an exception, or return an empty string
        }
        if (index < 0 || index >= fields.size())
        {
            // throw an exception, or return an empty string
        }
        return fields[index];
    }
    
    FixedLengthFieldsRecord::read(int numRec, FixedLengthFieldsRecord & rec)
    {
        if (numRec < 0 || numRec >= records.size())
        {
            // throw an exception, or just return
        }
        rec = records[numRec];
    }
    

    【讨论】:

      【解决方案2】:

      FixedLengthRecordFile 应该打开文件(或者更好,在构造函数中取一个std::istream),读取文件头,然后FixedLengthRecordFile::read(...) 成员函数可以使用std::istream::seekgstd::istream::read 来获取数据。

      现在,你的实际问题。为什么您希望FixedLengthRecordFile::read 函数在通过引用获取记录时返回int?签名不会像

      FixedLengthFieldsRecord FixedLengthRecordFile::read(size_t numRec, int& foo);
      

      更容易吗?

      如果您坚持您的原始签名,请让FixedLengthFieldsRecord 默认构造函数将对象初始化为无效状态(例如,添加设置为falsebool isValid 标志),并添加setData(size_t length, const char* data) 成员函数然后可以由FixedLengthRecordFile::read 函数调用。

      【讨论】:

        猜你喜欢
        • 2011-03-13
        • 1970-01-01
        • 1970-01-01
        • 2020-03-29
        • 1970-01-01
        • 1970-01-01
        • 2016-09-01
        • 2015-04-20
        • 1970-01-01
        相关资源
        最近更新 更多