我正在编写一个打开txt文件的c程序,想要读取txt文件的最后一行。 我不是那么精通C所以请记住,我可能不知道C中的所有概念。我被困在我使用fscanf读取我的txt文件的所有行的部分,但我想采取最后一行txt文件并获取如下所述的值。
这是我不完整的代码:
#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
我再次在txt文件的最后一行的时间值(例如1385144574.787925)之后。 希望这会有所帮助。
答案 0 :(得分:6)
由于你是在文件的最后一行之后,而你没有提到文件的大小,所以从最后开始阅读文件可能是值得的,并从那里开始向后工作:
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);
,其中x是您想要返回的字节数,直到您到达您想要的位置...除此之外,Jekyll的答案应该可以正常工作。 />
但是,要获得最后一行,我倾向于做这样的事情:
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
var背后的原因是我可以分配足够的内存来容纳整行。使用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);
获得该行后,您可以使用Jekyll的sscanf
示例来确定从该行中提取所需内容的最佳方法。
答案 1 :(得分:4)
您使用fscanf的方式是错误的,因为参数的实际向量需要与您收集的内容相匹配(如您在联机帮助页中所示)。您可以考虑使用fgets然后使用正则表达式通过sscanf过滤最新原始内容,而不是使用fscanf。
注意 ::我以双格式收集了值,您可以选择最适合您的格式(字符串?int.int?float? ),为此,您应该使用scanf 检查 正则表达式。如果你不能完成这项任务,请回来。
更新 ::由于某些请求,我写了一些不同模式匹配的示例。这些应该是解决问题的良好起点。
<强> 更新 强> :: 1.我已经看到你添加了你的db文件的模式,所以我们现在可以说#3和#4匹配并将3放在这里(更快)。 2.我已根据您的请求删除 feof 检查,但请注意 如果您知道自己在做什么,检查就没那么 强> 。基本上你必须记住,流的内部位置指示器可能指向下一个操作的文件结尾,但是,在操作尝试读取之前,可能不会设置文件结束指示符。那一点 。 3.您要求删除char行[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:
unsigned int n2, n3;
if (sscanf(line, "%*[^0-9]%d.%d", &n2, &n3) ) {
printf( "%d.%d\n", n2, n3);
}
说这个你应该弄清楚如何收集其他格式。
示例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在字符串“Time”上触发 char *ptr = strstr( line, "Time:" );
if( ptr != NULL ) {
if (sscanf(ptr, "%*[^0-9]%d.%d", &n2, &n3) ) {
printf( "%d.%d\n", n2, n3);
}
}
*注意* 您可能需要找到解析文件的方法,而上述内容只能作为建议,因为您的文件中可能有更多特定或不同的模式,但我在此处发布的说明应该足以为您提供完成工作的工具。情况下