0

特定のファイル形式を処理するためのクラスを作成しました。そのコンストラクターはファイルを調べて、必要な重要な情報を検索します。つまり、文字は複数の行に書かれているので、すべての行の最初の文字を読みたいのです。すべての行の 2 番目の文字など。

以下にコンストラクターと定義を示します (おそらく恐ろしい - C++ で本格的なものを書くのはこれが初めてです)。

class AlignmentStream{
private:
    const char* FileName;
    std::ifstream FileStream;
    std::vector<int> NamesStart;
    std::vector<int> SequencesStart;
    std::vector<int> SequenceLengths;
    int CurrentPosition;
    int SequenceNum;


public:
    AlignmentStream(const char* Filename);
    std::vector<int> tellSeqBegins();
    std::vector<int> tellNamesStart();
    std::vector<int> tellSequenceLengths();
    int getSequenceNum();
    AlignedPosition get();
};


AlignmentStream::AlignmentStream(const char* Filename)
{
    FileName = Filename;
    FileStream.open(FileName);
    std::cout << "Filestream is open: " << FileStream.is_open() << std::endl;
    std::cout << "Profiling the alignment file..." << std::endl;
    if (FileStream.is_open() == false)
        throw StreamClosed(); // Make sure the stream is indeed open else throw an exception.
    if (FileStream.eof())
        throw FileEnd();
    char currentchar;
    // Let's check that the file starts out in the correct fasta format.
    currentchar = FileStream.get();
    if (FileStream.eof())
        throw FileEnd();
    if (currentchar != '>')
        throw FormatError();
    NamesStart.push_back(FileStream.tellg());
    bool inName = true;
    bool inSeq = false;
    int currentLength = 0;
    while(!FileStream.eof()){
        while (!FileStream.eof() && inName == true) {
            if (currentchar == '\n') {
                inName = false;
                inSeq = true;
                SequencesStart.push_back(FileStream.tellg());
            } else {
                currentchar = FileStream.get();
            }
        }
        while (!FileStream.eof() && inSeq == true) {
            if (currentchar == '>') {
                inName = true;
                inSeq = false;
                NamesStart.push_back(FileStream.tellg());
            } else {
                if (currentchar != '\n') {
                    currentLength++;
                }
                currentchar = FileStream.get();
            }
        }
        SequenceLengths.push_back(currentLength); // Sequence lengths is built up here - (answer to comment)
        currentLength = 0;
    }
    SequenceNum = (int)SequencesStart.size();
    // Now let's make sure all the sequence lengths are the same.
    std::sort(SequenceLengths.begin(), SequenceLengths.end());
    //Establish an iterator.
    std::vector<int>::iterator it;
    //Use unique algorithm to get the unique values.
    it = std::unique(SequenceLengths.begin(), SequenceLengths.end());
    SequenceLengths.resize(std::distance(SequenceLengths.begin(),it));
    if (SequenceLengths.size() > 1) {
        throw FormatError();
    }
    std::cout << "All sequences are of the same length - good!" << std::endl;
    CurrentPosition = 1;
    FileStream.close();
}

とにかく、コンストラクターは char ごとに char を調べて、読み取る各行の開始点を取得します。get 関数 (図示されていません) は、メンバー変数 CurrentPos によって指定された、各行の先頭 + 正しい文字に到達するまでの残りの数を探します。次に、AlignedPosition という別のカスタム オブジェクトを作成して返します。

AlignedPosition AlignmentStream::get()
{
    std::vector<char> bases;
    for (std::vector<int>::iterator i = SequencesStart.begin(); i != SequencesStart.end(); i++) {
        // cout messages are for debugging purposes.
        std::cout << "The current filestream position is " << FileStream.tellg() << std::endl;
        std::cout << "The start of the sequence is " << *i << std::endl;
        std::cout << "The position is " << CurrentPosition << std::endl;
        FileStream.seekg((int)(*i) + (CurrentPosition - 1) );
        std::cout << "The Filestream has been moved to " << FileStream.tellg() << std::endl;
        bases.push_back(FileStream.get());
    }
    CurrentPosition++;
    //this for loop is just to print the chars read in for debugging purposes.
    for (std::vector<char>::iterator i = bases.begin(); i != bases.end(); i++) {
        std::cout << *i << std::endl;
    }
    return AlignedPosition(CurrentPosition, bases);
}

ご覧のとおり、最初のループは各行の開始位置 + CurrentPosition を繰り返し処理し、char を取得してベクターにプッシュします。このベクターは、AlignedPosition コンストラクターに渡されます。それ以外はすべてデバッグ用のメッセージです。ただし、実行すると次のように表示されます。

eduroam-180-37:libHybRIDS wardb$ ./a.out
Filestream is open: 1
Profiling the alignment file...
All sequences are of the same length - good!
SeqNum: 3
Let's try getting an aligned position
The current filestream position is -1
The start of the sequence is 6
The position is 1
The Filestream has been moved to -1
The current filestream position is -1
The start of the sequence is 398521
The position is 1
The Filestream has been moved to -1
The current filestream position is -1
The start of the sequence is 797036
The position is 1
The Filestream has been moved to -1
?
?
?
Error, an invalid character was present
Couldn't get the base, caught a format error! 

要するに、ファイル ストリームの位置が -1 であり、シークが使用されても変更されないことがわかります。これにより、無効な文字が発生し、AlignedPosition コンストラクターで例外がスローされます。これは、コンストラクターで最後までファイルを既にナビゲートしたことと関係がありますか? 入力ストリームでの位置が常に -1 のままなのはなぜですか?

ありがとう、ベン。

4

1 に答える 1

1

ストリームでファイルの終わりを取得した場合、seekgそれをクリアできない場合があります。clear()最初にストリームを呼び出す必要があります。EOF まで読み取るため、おそらく呼び出す必要がありますclear()。(参照: en.wikipedia.org/wiki/Seekg )

于 2013-11-30T16:48:56.880 に答える