Форум — Ответы     (  К темам )
 ?  NewBie: Обработка текстового файла (17-05-2003 07:20:43)
Здравствуйте,
такая задача, мне необходимо с текстового файла считывать порции по 428 байтов, находить поля "ID: " и считывать то что после него, следующие 3 байта.Предложите какой-нибудь эффективный способ плиз.
 Павел (18-05-2003 14:00:55)
Самый эффективный — держать данные не в текстовом файле, а в таблице
(например .db файл), и работать как с таблицей, пользуясь компонентами
Table или Query — у них много соответствующих свойств и методов

----

Если все-же о текстовом файле

void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
struct SSS{
char a[428];
}sss;

AnsiString snum;

// сначала запишем что либо в файл
int ih = FileCreate("c:\\ccc.txt");
for(int i=0; i<10; i++){ // пишем какие-то 10 записей с ID: от 001 до 009
snum.printf("ID:%03d",i);
ListBox2->Items->Add(snum); // проверяем чего пишем
strcpy(sss.a, snum.c_str());
FileWrite(ih, (char*)&sss, 428);
}
FileClose(ih);

//---
ih = FileOpen("c:\\ccc.txt",fmOpenRead);
for(int i=0; i<10; i++){
FileRead(ih, (char*)&sss, 428); // считываем следующие 428 байт
AnsiString s = sss.a;
// находим в них "ID:" и считываем 3 байта после них
AnsiString sn = s.SubString(s.Pos("ID:")+3,3);
ListBox1->Items->Add(sn); // проверяем чего считали из файла
}
FileClose(ih);
}
//-------------------------------------

Если нужно считывать не весь файл от начала до конца,
а какую-то конкретную запись от начала файла,
то воспользуйтесь функцией FileSeek():

// считать 3-и запись те 3-и 428 байт (от начала файла это сдвиг на 2*428)

ih = FileOpen("c:\\ccc.txt",fmOpenRead);
FileSeek(ih,2*428,0); // сдвигаемся от начала на 2*428 = 3 запись
FileRead(ih, (char*)&sss, 428);
AnsiString s = sss.a;
AnsiString sn = s.SubString(s.Pos("ID:")+3,3);
ShowMessage(sn);
FileClose(ih);
 SKh (21-05-2003 08:53:35)
Все понял!Отлично спасибо! только объясните еще одно по подробней.
меня интересует значение "+3,3" в данной строке. Я так понял, что это считывание следующих 3-х байтов после слова "ID:"

s.SubString(s.Pos("ID:")+3,3);

если мне надо теперь считать 15 байтов, то я пишу 15,15?
 Павел (21-05-2003 10:12:07)
Нет, неправильно.

Функция SubString() возвращает подстроку из строки AnsiString.


AnsiString __fastcall SubString(int index, int count) const;

Описание.

SubString вернет новую строку типа AnsiString, являющуюся подстрокой
в данной строке. Подстрока будет содержать count символов, начиная с позиции
index в строке AnsiString.
(те из строки будет вырезано count символов, начиная с позиции index)
index начинается с 1

Если надо считать 15 байтов, то и пишите: s.SubString(s.Pos("ID:")+3,15);

Чтобы было понятней, разберем s.SubString(s.Pos("ID:")+3,15); по частям:

int Pos(AnsiString) — найти подстроку в строке, вернуть позицию начала
подстроки, если строка найдена, иначе 0
AnsiString SubString(index, count) — вернуть подстроку начиная с позиции
index длиной count байт

int n = s.Pos("ID:");
n = n + 3;
AnsiString sn = s.SubString(n, 15);
------------------------------------------------------

Или, пример
Есть строка:


AnsiString s = "This data is ID:12345 and NameIs=Pasha and City:Moscow-city ";

int index = s.Pos("ID:"); // находим подстроку "ID:", получаем в index
номер начала этой подстроки
index = index + 3; // сдвигаемся на 3 байта вправо (на номер)

AnsiString sn = s.SubString(index,5); // вырезаем с указанного index места
подстроку размером 5 байт (номер)
ShowMessage(sn); // "12345"

//----- Теперь также получим значение NameIs
index = s.Pos("NameIs");
index = index + 7;
sn = s.SubString(index,10);
ShowMessage(sn); // "Pasha "

//----- Теперь также получим значение City
index = s.Pos("City");
index = index + 5;
sn = s.SubString(index,15);
ShowMessage(sn); // "Moscow-city "

---


 Павел (21-05-2003 12:42:11)
Кроме того, у вас текстовый файл может состоять и из строк разной длины
Рассмотрим, например, такой пример
Есть текстовый файл subscribe.txt
типа mail*дата время со строками разной длины

mosc@valuehost.ru*2002-12-22 19:41:36
klassiks@mtu-net.ru*2002-12-22 19:42:53
support@rxlib.ru*2002-12-22 19:43:13
moscowin@valuehost.ru*2002-12-22 19:44:27
shop@rol.ru*2002-12-23 16:02:33
gazpr1@sinn.ru*2002-12-24 11:02:25
...
Email-адрес отделен от даты-времени символом *
Нужно выбрать все email-адреса и поместить их в ListBox1
и в другой текстовый файл mail.txt

Тогда чтение строк из файла можем осуществлять через функции C

#include <stdio.h>

char msg[100];
ListBox1->Items->Clear();
AnsiString sDir = GetCurrentDir();
AnsiString sFile = sDir + "\\"+"subscribe.txt";
FILE *fp = fopen(sFile.c_str(), "rt");

while(!feof(fp)){
fgets(msg, 80, fp); // считать следующую строку из файла
AnsiString s = AnsiString(msg);
s = s.Trim(); // удалить начальные/конечные пробелы в строке если есть
AnsiString sMail = s.SubString(1,s.Pos("*")-1); // вырезать адрес в sMail
ListBox1->Items->Add(sMail);
}

fclose(fp);
ListBox1->Items->SaveToFile(sDir + "\\"+"mail.txt");