2013-11-28 3 views
2

Я пишу программу c, которая открывает файл txt и хочет прочитать последнюю строку файла txt. Я не владею C, поэтому помните, что я не знаю всех понятий в C. Я застрял в той части, где я использую fscanf, чтобы читать все строки моего txt-файла, но я хочу взять последнее строки txt-файла и получить значения, как описано ниже.C программирование, получение последней строки файла

Вот мой неполный код:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

FILE *sync; 


void check() 
{ 
    int success; //to hold the results if the timestamps match 
    sync = fopen("database.txt","r"); 
    char file[] = "database.txt"; 

    while (fscanf(sync, "%d.%06d", &file) != EOF) 
    { 


    } 

    fclose(sync); 
} 

образец TXT файл:

//////////// ///// ///// //////////////// Time: 1385144574.787665 /////////
//////////// ///// ///// //////////////// Time: 1385144574.787727 /////////
//////////// ///// ///// //////////////// Time: 1385144574.787738 /////////
//////////// ///// ///// //////////////// Time: 1385144574.787746 /////////
//////////// ///// ///// //////////////// Time: 1385144574.787753 /////////

/некоторые слова, символы и цифры я не хочу, только цифры в образце TXT, как показано выше

Я ценю любые примеры и указывая ошибки, которые я сделал, чтобы понять это намного лучше. Так как некоторые люди путают текстовый файл, вот что это на самом деле. Это формат, который будет таким, чтобы я знал длину каждой строки. Однако я не буду знать, сколько строк будет, поскольку оно может быть обновлено.

Socket: 0 PGN: 65308 Data: 381f008300000000 Time: 1385144574.787925 Address: 28 
Socket: 0 PGN: 65398 Data: 0000000100000000 Time: 1385144574.787932 Address: 118 
Socket: 0 PGN: 61444 Data: f07d83351f00ffff Time: 1385144574.787940 Address: 4 
Socket: 0 PGN: 65266 Data: 260000000000ffff Time: 1385144574.787947 Address: 242 
Socket: 0 PGN: 65309 Data: 2600494678fff33c Time: 1385144574.787956 Address: 29 
Socket: 0 PGN: 65398 Data: 0000000100000000 Time: 1385144574.787963 Address: 118 
Socket: 0 PGN: 61444 Data: f07d833d1f00ffff Time: 1385144574.787971 Address: 4 
Socket: 0 PGN: 65398 Data: 0000000100000000 Time: 1385144574.787978 Address: 118 
Socket: 0 PGN: 61443 Data: d1000600ffffffff Time: 1385144574.787985 Address: 3 
Socket: 0 PGN: 65308 Data: 451f008300000000 Time: 1385144574.787993 Address: 28 
Socket: 0 PGN: 65317 Data: e703000000000000 Time: 1385144574.788001 Address: 37 

Опять я после значений времени (например. 1385144574.787925) в последней строке текстового файла. Надеюсь, это поможет.

+0

Чтобы помочь вам «понять это намного лучше», нужно знать, почему вы это сделали в первую очередь. Что вы пытались сделать, передав строку 'file' с' "database.txt" 'в нее в' fscanf'? Какова была цель этого? – AnT

+0

Вы задали вопрос с двумя большими частями: 1, как смотреть только на последнюю строку (ответ Elias - хороший). 2, как извлечь элемент времени из этой строки. Не зная, что именно вы подразумеваете под ***./Некоторые слова, символы и цифры, которые я не хочу ***, нет способа точно знать, как вам помочь. Слова, символы и *** числа *** могут включать любой символ ascii. Если вы хотите исключить все другие входные данные, кроме _Time: 1385144574.787665_ et. al., тогда вам придется проанализировать строку для _exclude_ всех нежелательных данных с помощью 'strtok()' (или 'strtok_r()'). – ryyker

+0

Если вы предоставите пример некоторых экземпляров ввода-фактуры, то вы, скорее всего, получите полное решение. Во время этого комментария, ответчики, возможно, не могли полностью решить эту проблему. – ryyker

ответ

4

Способ использования fscanf неверен, поскольку фактический вектор аргументов должен соответствовать тому, что вы собираете (как вы можете видеть на странице руководства). Вместо использования fscanf вы можете использовать fgets и затем фильтровать то, что вы ищете, в последнем raw с регулярным выражением через sscanf.

Примечание :: Я собрал значение в двойном формате, вы можете выбрать формат, который подходит вам больше всего для вашей проблемы (строка? Int.int? Плавать?), Для того, чтобы сделать это, вы должны проверить для regex используя сканf. Вернитесь, если вы не сможете выполнить эту задачу.

обновления :: из-за некоторые запросы я написал несколько несколько примеров различного сопоставления с образцом. Это должно стать хорошей отправной точкой для устранения ваших проблем.

обновление :: 1. Я видел, что вы добавили шаблон файла БД, поэтому мы можем теперь сказать, что как # 3 и # 4 матча и поставить 3 здесь (быстрее). 2. Я извлекал чек feof как для вашего запроса, но обратите внимание, что чек хорошо, если вы знаете, что вы делаете. В основном вы должны иметь в виду, что индикатор внутреннего положения потока может указывать на конец файла для следующей операции, но, тем не менее, индикатор конца файла не может быть установлен до тех пор, пока операция не попытается прочитать в этой точке. 3. Вы попросили удалить строку символов [1024] = {0,}; Эта команда используется для инициализации массива [1024], который будет содержать строки, которые вы читаете из файла. Это необходимо!Для того, чтобы знать, что это инструкция смотрите here

Код:

void check() 
{ 
    char line[1024]={0,}; // Initialize memory! You have to do this (as for your question) 
    int n2=0; 
    int n3=0; 
    sync = fopen("database.txt", "r"); 
    if(sync) { 
     while(fgets(line, 1024, sync) !=NULL) { 
     // Just search for the latest line, do nothing in the loop 
     } 
     printf("Last line %s\n", line); //<this is just a log... you can remove it 
     fclose(sync); 
     // This will look for Time and it will discard it collecting the number you are looking for in n2 and n3 
     if (sscanf(line, "%*[^T]Time: %d.%d", &n2, &n3)) { 
      printf("%d.%d\n", n2, n3); 
     } 
    } 
} 

Пример 2
если, например, вам нужно собрать значение, используя два целых числа вам нужно будет заменить sscanf из пример выше со следующим кодом:

сказал, что вы должны выяснить как собирать другие форматы.

Пример 3 Более регулярное выражение. В случае, если в файле есть другие числа перед шаблоном дачи, которые вы можете захотеть сопоставить по времени, так что предположим, что раньше не было T. Регулярное выражение для этого может быть:

if (sscanf(line, "%*[^T]Time: %d.%d", &n2, &n3)) { 
    printf("%d.%d\n", n2, n3); 
} 

Регулярное выражение с использованием sscanf может быть не подходит для вашей модели, в этом случае вам необходимо рассмотреть использование gnu regex library или вы можете смешать strstr и sscanf, как я сделал в следующем пример.

Пример 4 Это может быть полезно, если вы не можете найти общий шаблон. В этом случае вы можете вызвать на строку «Время» с помощью strstr перед вызовом sscanf

char *ptr = strstr(line, "Time:"); 
    if(ptr != NULL) { 
    if (sscanf(ptr, "%*[^0-9]%d.%d", &n2, &n3)) { 
     printf("%d.%d\n", n2, n3); 
    } 
    } 

* Примечание * Вам может понадобиться, чтобы найти свой путь, чтобы разобрать файл и те выше, могут быть только предложения, потому что у вас могут быть более конкретные или разные шаблоны в вашем файле, но инструкция, которую я разместил здесь, должна быть достаточной, чтобы дать вам инструменты для выполнения задания в этом случае.

+0

В соответствии с комментариями, OP хочет выполнить соответствие * timestamps *. Это должно быть точно. Ваша попытка использовать «double» будет искажать значения и предотвращать точную математику. – AnT

+0

@AndreyT Я думаю, что если это то, что ему нужно, он должен играть вокруг sscanf и собирать правильную форму, которую он ищет (может быть, строка, возможно, int.int?). Я подозреваю, что в качестве руководства этот фрагмент должен быть достаточным. Вы согласны? – Jekyll

+1

Ну, '% * [0-9]' хорошая вещь для OP, чтобы учиться. Однако похоже, что кто-то уже помог OP использовать подход '% d.% D'. Отбросить его без каких-либо объяснений, вероятно, будет путать ОП. – AnT

4

Поскольку вы находитесь за последней строкой файла, и вы не указали, насколько велик файл, возможно, стоит начать читать файл с e ой, и работать ваш путь назад оттуда:

FILE *fp = fopen("database.txt", "r"); 
fseek(fp, 0, SEEK_END);//sets fp to the very end of your file 

Оттуда вы можете использовать fseek(fp, -x, SEEK_CUR); где х число байтов, которые вы хотите, чтобы вернуться назад, пока вы не получите, где вы хотите ... кроме того, что , Ответ Джекилла должен работать нормально.
Однако, чтобы получить последнюю строку, я, как правило, сделать что-то вроде этого:

FILE *fp = fopen("database.txt", "r"); 
char line[1024] = ""; 
char c; 
int len = 0; 
if (fp == NULL) exit (EXIT_FAILURE); 
fseek(fp, -1, SEEK_END);//next to last char, last is EOF 
c = fgetc(fp); 
while(c == '\n')//define macro EOL 
{ 
    fseek(fp, -2, SEEK_CUR); 
    c = fgetc(fp); 
} 
while(c != '\n') 
{ 
    fseek(fp, -2, SEEK_CUR); 
    ++len; 
    c = fgetc(fp); 
} 
fseek(fp, 1, SEEK_CUR); 
if (fgets(line, len, fp) != NULL) puts(line); 
else printf("Error\n"); 
fclose(fp); 

Смысла моего len вара так, что я могу выделить достаточно памяти, чтобы вместить всю линию. Используя массив 1024 символов должно хватить, но если вы хотите играть в безопасности:

char *line = NULL; 
//read line 
line = calloc(len+1, sizeof(char)); 
if (line == NULL) 
{ 
    fclose(fp); 
    exit(EXIT_FAILURE); 
} 
//add: 
free(line);//this line! 
fclose(fp); 

После того, как вы получили эту строку, вы можете использовать sscanf примеры Джекила, чтобы определить наилучший способ извлечь все, что вы хотите от эта линия.

+0

Файл может содержать более тысячи строк, и он может увеличиться при обновлении. – GhostMember

+0

Ну, в этом случае вам обязательно нужно прочитать файл назад. Учитывая, что вас интересует только последняя строка файла ... –

+0

@EliasVanOotegem Я дал вам +1, потому что я всегда использовал это, и мне это нравится. Кстати, я не предлагал этого, потому что в последний раз, когда я пытался, кто-то жаловался, что «по стандарту» поиск ряда позиций небезопасен (даже если он всегда работает в Linux/Unix). Вы что-то знаете об этом? Я не мог найти эту рекламу нигде. – Jekyll

Смежные вопросы