fseek и fscan дают неверные результаты из файла .DAT в C++

У меня есть файл .dat, который постоянно обновляется. Я хочу получить данные из последней строки в файле. Но я получаю неточные результаты. Вот myfile.DAT:

# Time  forces(pressure, viscous) moment(pressure, viscous)
0.005   (((2 10 4) (3 6 0)) ((12 60 -13) (4.88 0.5 -0.32)))
0.01    (((2 20 2) (4 7 3)) ((0.0024 1 -70) (40 6000 -1200)))

А вот код С++:

#include <iostream>
#include <fstream>
#include <string>

int main ()
{
  FILE * force;
  force = fopen("file.dat", "r");
  float timestep;
  float fxp;
  float fyp;
  float fzp;
  float fxv;
  float fyv;
  float fzv;
  float mxp;
  float myp;
  float mzp;
  float mxv;
  float myv;
  float mzv;

  char c;

  fseek(force,-285,SEEK_END);

  while(c != '\n')
  {
    c = fgetc(force);
  }

  fscanf(force, "%f    ((%f %f %f) (%f %f %f)) ((%f %f %f) (%f %f %f))", &timestep, &fxp, &fyp, &fzp, &fxv, &fyv, &fzv, &mxp, &myp, &mzp, &mxv, &myv, &mzv);

  fclose(force);

  float ftotal = fxp + fxv;

  std::cout << "Here is f_total = " << ftotal << " N" << std::endl;

  return 0;
}

И вот результат:

Here is f_total = 0 N

Очевидно, это неправильно. Должно быть 2 + 4 = 6.


person Community    schedule 20.02.2017    source источник
comment
Какая последняя строка в файле, который постоянно обновляется?   -  person Mike 'Pomax' Kamermans    schedule 21.02.2017
comment
Забавно, что вы #include <fstream> и не используете ни один из std::*fstream классов   -  person WhiZTiM    schedule 21.02.2017
comment
Если файл записывается по мере того, как вы его читаете, последняя строка может быть неполной, потому что часть ее буферизована записывающим устройством.   -  person Barmar    schedule 21.02.2017
comment
@Mike'Pomax'Kamermans Как вы видите Timestep, он обновляется. Timestep продолжается и продолжается. Поэтому я хочу использовать последнюю строку, я имею в виду последний временной шаг.   -  person    schedule 21.02.2017
comment
@ Бармар Хорошо. Но здесь я упростил задачу. И файл .DAT является постоянным. Таким образом, это должно дать мне 2 + 4 = 6. Другими словами, приведенный выше пример прост и состоит из 2 строк.   -  person    schedule 21.02.2017
comment
Проверьте возвращаемое значение fscanf().   -  person Barmar    schedule 21.02.2017
comment
@Barmar Я попробовал std::cout ‹‹ fscanf(), и это дало мне 1. Очень странно.   -  person    schedule 21.02.2017


Ответы (2)


Ваша строка формата fscanf:

"%f    ((%f %f %f) (%f %f %f)) ((%f %f %f) (%f %f %f))"

но должно быть:

"%f    (((%f %f %f) (%f %f %f)) ((%f %f %f) (%f %f %f)))"

Редактировать: это, скорее всего, не лучший способ сделать это (пройти 2 назад, 1 вперед), но проверьте, работает ли это с этим изменением:

fseek(force, -1, SEEK_END);

while (c != '\n')
{
    c = fgetc(force);
    fseek(force, -2, SEEK_CUR);
}
person mpiatek    schedule 20.02.2017
comment
Спасибо. Я попытался, но это дало мне «Вот f_total = 5 N». Должно быть 6. - person ; 21.02.2017
comment
Это дает мне 6, и я создал этот файл .dat с точно таким же содержимым. Скомпилируйте код, который вы разместили здесь, создайте новый файл с опубликованным содержимым и повторите попытку. - person mpiatek; 21.02.2017
comment
Я создал новый код .dat и C++. Результат по-прежнему 5. Даже я изменил значения файла. Всегда дает 5. - person ; 21.02.2017
comment
Я думаю, что у меня проблема с fseek -285. Потому что этот код дает мне результат первой строки, а не последней. - person ; 21.02.2017
comment
@ordinary Каждая строка имеет длину около 60 символов. Итак, -285 вернет 4 строки в файле назад. - person Barmar; 21.02.2017
comment
@mpiatek Большое спасибо. Я пробовал с вашим последним, он дает мне 0. Затем я попробовал ваше последнее редактирование с советом Бармара (cout ‹‹ fscan). Затем он дал мне 1. - person ; 21.02.2017
comment
этот код дает вам 0? Вставьте фактический код, который вы компилируете, куда-нибудь и опубликуйте ссылку, пожалуйста. - person mpiatek; 21.02.2017
comment
@ordinary Вы пробовали код, который я разместил в последнем комментарии? Проблема решена? - person mpiatek; 22.02.2017
comment
Я ценю ваши ценные усилия. Но, к сожалению, ваш последний код, который вы отправили по ссылке, дал мне 0. Еще раз спасибо. - person ; 23.02.2017
comment
@ordinary, не могли бы вы еще раз проверить, совпадает ли последняя запись в вашем файле с той, которую вы разместили здесь? Тогда не могли бы вы загрузить куда-нибудь свой файл .dat? - person mpiatek; 23.02.2017
comment
@ordinary в вашем файле есть \n в качестве последнего символа? Другими словами, есть ли новая строка в конце файла? - person mpiatek; 23.02.2017
comment
На самом деле мой файл продолжается и продолжается. Я имею в виду последнюю строку, которая начинается с 0,01, изменяется на 0,015, 0,02, 0,025, 0,03, 0,035 ... ... Итак, строк много, но для упрощения моего вопроса я разместил в вопросе всего 2 строки. - person ; 23.02.2017
comment
@ordinary мой вопрос: в файле, который вы используете для тестирования (и в реальном файле, созданном чем-то другим), какой последний символ? Это \n или файл заканчивается последней скобкой? - person mpiatek; 23.02.2017
comment
Это просто скобки. - person ; 23.02.2017

1 fscanf возвращает количество просканированных полей, так что для быстрой проверки нужно добавить "int n = fscanf(...." -- затем проверить, что "n" - это то, что, по вашему мнению, должно быть. Это может сэкономить вам много времени. головокружение.

2: Лучше, чем предполагать длину строки с поиском с конца, сканировать \n с начала файла, а затем искать обратно до последнего перед выполнением fscanf - это также позволит вам легко выбрать конкретный номер строки. Следующее будет сканировать весь файл, а затем возвращаться к последней строке (предполагается, что в файле нет \n в качестве последнего символа)

int lineno = 1;
int lastLine = 0;
while(c != EOF)
{
    c = fgetc(force);
    if(c == '\n')
    {
        ++lineno;
        lastLine = ftell(force);
    }
}
printf("%d lines, pos=%d\n", lineno, lastLine);
fseek(force, lastLine, SEEK_SET);
person joeking    schedule 20.02.2017
comment
Спасибо. Я объединил ваш код с проблемой. Теперь я получаю 4 строки, pos=182 Вот f_total = 0 N Кстати, как вы сказали, я думаю, что настоящая проблема здесь в том, чтобы определить -285. Я попробовал этот номер с -65 и без проблем. Это дало мне правильный ответ. Я постараюсь найти решение и сообщить здесь позже. - person ; 21.02.2017