Я создал класс для работы с определенным формальным файлом, и его конструктор просматривает файл и ищет ключевую информацию, которая мне нужна — идея состоит в том, что символы пишутся в несколько строк, и я хочу прочитать первый символ каждой строки, второй символ каждой строки и так далее.
У меня есть конструктор и определение ниже (возможно, ужасно — я впервые пишу что-то серьезное на 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, а затем получает символ и возвращает его обратно в вектор, этот вектор передается моему конструктору 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 все время?
Спасибо,
Бен.
Если вы получите конец файла в потоке, seekg
может не очистить это. Вам нужно позвонить clear()
в потоке первым. Поскольку вы читаете до EOF, вам, вероятно, нужно позвонить clear()
, (Ссылка: en.wikipedia.org/wiki/Seekg)
Других решений пока нет …