fscanf дважды читает переменную в середине файла - Windows NT 4.0 dll

У меня возникла проблема с чтением txt-файла в dll-файле Windows NT 4.0; и прежде чем вы спросите, в настоящее время я не заинтересован в переносе этого на новую ОС. Я просто хочу исправить эту проблему и позволить другим после меня беспокоиться о переносе этого сверхустаревшего программного обеспечения.

Проблема возникает, когда я читаю текстовый файл с помощью fscanf, как показано ниже:

infile_ptr = fopen("c:\\LumaGem\\orbit.txt", "r");
byteoffset=0;
while(!feof(infile_ptr) )
    {   
        r=0.0; s1=0.0; s2=0.0; e1=0.0; e2=0.0; e3=0.0; d=0.0; f=0.0;
        fseek(infile_ptr, byteoffset, SEEK_SET);
        fscanf(infile_ptr,"%7lf %7lf %7lf %7lf %7lf %7lf %7lf %7lf", &r, &s1, &s2, &e1, &e2, &e3, &d, &f);

        byteoffset=0; byteoffset = ftell(infile_ptr);
     }
fclose(infile_ptr);  

Текстовый файл, созданный с помощью MATLAB, состоит из 128 строк по 8 столбцов, разделенных 5 пробелами и отформатированных в MATLAB следующим образом:

fprintf(fid,'%7.3f     %7.3f     %7.3f     %7.3f     %7.3f     %7.3f     %7.3f     %7.3f \n', variables);

Этот код был написан не мной и работал несколько лет. Однако недавно нам пришлось переустановить/переустановить ОС и программное обеспечение Windows NT 4.0, и теперь я получаю странную ошибку. Программа нормально читает txt-файл, используя код, представленный вверху, пока не дойдет до строки 123, после чего она дважды читает 8-й столбец, в результате чего все последующие переменные сдвигаются на одну позицию, полностью искажая последнюю. несколько строк программы. Интересно, что эту проблему можно решить, вручную скопировав и вставив первые 123 строки в новый текстовый файл, а затем несколько последних строк одну за другой в тот же новый текстовый файл и используя его в качестве входных данных (копирование выполнено). на машине NT в WordPad). Это устраняет проблему двойного чтения. Я понятия не имею, какие проблемы могут вызвать эту ошибку, но пусть она будет исправлена ​​таким странным/неуклюжим методом. Проблема возникает с новыми и старыми входными данными, поэтому я не думаю, что проблема заключается во входных файлах, поскольку они не изменились.

О, и, кроме того, если я изменю количество пробелов между каждым столбцом в txt-файле, местоположение ошибки сместится. Уменьшение его до 1 пробела приводит к возникновению ошибки в строке 120 или около того, а увеличение количества пробелов (пробовал 7 вместо 5) привело к ошибке до строки 124.

Я не эксперт по программированию (всегда был парнем, который учится по мере необходимости), поэтому помощь в выяснении этого будет очень признательна. Спасибо!


person sdm142    schedule 19.07.2013    source источник
comment
Изучите исходный файл с помощью средства просмотра hex (например, откройте его как двоичный файл в Visual Studio), найдите необычные байты рядом с местом возникновения проблемы. Я бы заподозрил встроенный байт NUL (нулевой) или ^ Z (он же 26, он же 1A). Последний рассматривается как маркер конца файла при чтении в текстовом режиме. Ваш странный танец ftell/fseek может позволить коду обойти его и продолжить чтение.   -  person Igor Tandetnik    schedule 19.07.2013
comment
Отображение строк вашего текстового файла 122–124 может помочь.   -  person chux - Reinstate Monica    schedule 20.07.2013
comment
@IgorTandetnik Я попробую шестнадцатеричный / двоичный комментарий в понедельник, когда вернусь в свою лабораторию. Однако это маловероятно, поскольку более старый входной файл, который работал нормально, прежде чем продемонстрировал ту же проблему. Мог ли быть добавлен необычный байт при переносе с одной машины на другую?   -  person sdm142    schedule 20.07.2013
comment
@CHUX Вот эти 3 строки файла TXT: Вот примеры входных строк для файла TXT: 8.297 0,045 -5,000 340,313 22,624 0,000 5,000,000 8,363 0,045 -5,000 343,125 20,744 0,000 5,000,000 8,430 0,045 -5,000 345,938 19,073 0,000 5,000,000,000,000,000,000 2,000 2,000 0,045 -5,000 345,938 19,073 0,000 5,000,000,000 2,   -  person sdm142    schedule 20.07.2013
comment
Цифры выглядят нормально. Не могли бы вы предоставить шестнадцатеричный дамп линии неисправности вместе с ее 2 или 4 соседями? Кстати, какой тип byteoffset? Я подозреваю, что ваше возвращаемое значение из fcanf рядом со строкой 123 не равно 8, и это разграничит вашу проблему. - Чукс 15 минут назад   -  person chux - Reinstate Monica    schedule 20.07.2013
comment
Шестнадцатеричный дамп входного файла: Отредактировано: Попытка выяснить, как скопировать и вставить шестнадцатеричный дамп; хочет просто вставить исходные входные значения... byteoffset это long. Я посмотрю значение, возвращаемое fscanf для каждой строки, но не будет ли строка всегда читать 8, если она возвращает 8 значений? Проблема не в отсутствии значения, а в двойном чтении значения.   -  person sdm142    schedule 22.07.2013
comment
Строка 122: '20 20 20 38 2e 34 33 30 20 20 20 20 20 20 20 30 2e 30 34 35 20 20 20 20 20 20 2d 35 2e 30 30 30 20 20 20 20 20 3 20 31 304 20 20 20 20 31 39 2д 30 37 33 20 20 20 20 20 20 20 30 2д 30 30 30 20 20 20 20 20 20 20 35 2д 30 30 30 20 20 20 20 20 0 3' 20 20 30 02 123: 20 20 20 38 2e 33 36 33 20 20 20 20 20 20 20 30 2e 30 34 35 20 20 20 20 20 20 2d 35 2e 30 30 30 20 20 20 2 2 0 7 3 20 31 36 20 20 20 32 30 2е 37 34 34 20 20 20 20 20 20 20 30 2е 30 30 30 20 20 20 20 20 20 20 35 2е 30 30 30 20 20 20 20 20 20 20 3' 30 2е   -  person sdm142    schedule 22.07.2013
comment
Строка 124: '20 20 20 38 2e 32 39 37 20 20 20 20 20 20 20 30 2e 30 34 35 20 20 20 20 20 20 2d 35 2e 30 30 30 20 20 20 2 0 20 3 8 20 31 39 20 20 20 20 32 32 2д 36 32 34 20 20 20 20 20 20 20 30 2д 30 30 30 20 20 20 20 20 20 20 35 2д 30 30 30 20 20 20 20 20 3'3 20 20 30 32   -  person sdm142    schedule 22.07.2013
comment
@ sdm142 Спасибо. Далее следует слишком много идей: Примечания: шестнадцатеричный дамп 1-го столбца (8.430:8.363:8.297) и текстовый дамп (2 дня назад 8.297:8.363:8.430) меняются в обратном порядке. Вы сообщаете об изменении только столбцов 1,5,6. Я вижу 1,4,5 изменения. В столбце 4 отмечены значения от 14 до 345. Вы уверены, что столбец не превышает 999,999? Вы пробовали %lf%lf%lf%lf%lf%lf%lf%lf вместо %7lf...? Ваша последняя строка прочитана не полностью?   -  person chux - Reinstate Monica    schedule 22.07.2013
comment
Возможно, вам потребуется предоставить ссылку на исходный текстовый файл. У меня заканчиваются идеи, кроме того, что манипулирование указателем файла ведет себя неправильно. Конечно, проблема может заключаться в неопубликованном коде. Смотрите новый опубликованный ответ ниже. Удачи!   -  person chux - Reinstate Monica    schedule 22.07.2013
comment
Извините, я имел в виду, что столбцы 1, 4, 5 меняются, как вы указываете. Наибольшее значение в любом из этих входных файлов — 357,188; все значения меньше 360, потому что это файл траектории для некоторых двигателей. -5.000 — единственное отрицательное значение, и оно фиксированное. Вот входные файлы. Обычный — это тот, который имеет ошибку в конце строки 123, ручной — это скопированная версия, которую я сделал в Wordpad на Windows NT 4.0, и она работает нормально. people.duke.edu/~sdm36/PROJSINE_Manual.txt people.duke.edu/~sdm36/PROJSINE_Normal.txt   -  person sdm142    schedule 22.07.2013


Ответы (2)


Упрощение кандидатов

Не удалось найти источник проблемы, но рекомендовал его для упрощения отладки. Это позаботится об окончании строк PC, чрезмерных манипуляциях с указателем файла, ненужном ограничении %7lf и обеспечит лучшую проверку ошибок.

FILE *infile_ptr = fopen("c:\\LumaGem\\orbit.txt", "rt");  // PC text file
char buf[1000];
while (fgets(buf, sizeof(buf), infile_ptr)) {  // separate I/O from scanning
  int count = sscanf(buf,"%lf%lf%lf%lf%lf%lf%lf%lf", &r, &s1, &s2, &e1, &e2, &e3, &d, &f);  
  if (count != 8) { // check for correct scan count
    ; //handle error;
  }
}
if (ferror(infile_ptr)) {
  ; //handle error;
}
fclose(infile_ptr);

[Изменить] ОП опубликовал исходный текстовый файл.

Также добавьте эту строку в цикл, чтобы позаботиться о конечных строках, состоящих только из пробелов.

  if (count <= 0) continue;

[править] Заключение.

Использование fseek() и ftell(), обычно используемых с двоичными файлами, здесь не нужно, ИМХО, является ошибкой Windows при чтении текстового файла UNIX (\n), открытого в Windows в двоичном режиме "r", и использовании fscanf(), который лучше всего работает при чтении текстовых файлов, открытых "rt". Не обнаружено ничего, что указывало бы на строку 123 или ее соседей как на проблемную область.

person chux - Reinstate Monica    schedule 22.07.2013
comment
fprintf() использует \n, который fscanf() обычно не отличает от пробела. При использовании fgets(), в котором используется '\n', проблемы локализуются в проблемной строке. - person chux - Reinstate Monica; 22.07.2013
comment
Реализация этого работает для чтения файла, но теперь я сталкиваюсь с другими проблемами; Я начинаю думать, что это может быть связано с памятью. Я включил ссылку на исходный код для этой DLL (однако без заголовков и т. д.). Я уверен, что это небрежно (опять же, я не программировал большую часть этого, но я адаптировал некоторые из них для работы с нашей перестройкой), но я был бы признателен, если бы вы (или кто-либо другой) могли посмотреть на это и заметить любую ошибку. очевидные ошибки, особенно с функцией int ReadEuler(int, index). С удовольствием отвечу на любые вопросы о предназначении. people.duke.edu/~sdm36/DLL_NewXPS_v1_StackEdit.cc - person sdm142; 22.07.2013
comment
Чтобы добавить, этот компьютер имеет 1 ГБ оперативной памяти, если это имеет какое-либо значение в отношении памяти и т. д. - person sdm142; 22.07.2013
comment
fclose( CommandList ); в вашем полном коде после обнаружения ошибки следует заменить на break; в 2 местах. Кстати: почему rdeg = 9.7773f*pow(r,6) против rdeg = 9.7773 *pow(r,6)? Второй должен быть быстрее (или так же быстро) и точнее. Кстати: ваш второй текстовый файл использует \r\n, тогда как первый файл использует \r. - person chux - Reinstate Monica; 23.07.2013
comment
Выходные данные CommandList не являются частью исходного кода; Я просто поместил их туда для отладки и определения того, что компьютер читал/хранил/отправлял по сравнению с тем, что он должен был делать. Формат rdeg был создан первоначальным программистом; понятия не имею, почему это в этом конкретном формате, поэтому я обновлю. Полезно знать о различиях файлов txt. Но даже с реализованным кодом из этого ответа у меня теперь возникают новые проблемы (я думаю, с преобразованием сохраненных переменных в строки). Завтра еще посмотрю. Еще раз спасибо за такую ​​помощь! - person sdm142; 23.07.2013
comment
Новые проблемы звучат как прогресс. ТТФН - person chux - Reinstate Monica; 23.07.2013

Проблема с директивой fscanf().
Рекомендовать %lf вместо %7lf.

Ваш fprintf() с "%7.3f" выводит числа с плавающей запятой, используя для этого минимум 7 символов, при необходимости добавляя ' '.

Ваше последующее использование "%7lf" в fscanf() говорит о сканировании максимум 7 символов. Поэтому, когда вы печатаете f/scanf 999.999, все в порядке, но с большими числами, такими как 1000.007, ваше сканирование принимает «1000.00» и оставляет «7» для следующего "%7lf".

 int main(void) {
  char buf[1000];
  double f1, f2;
  int r;
  sprintf(buf, "%7.3f %7.3f", 1.23, 4.56);
  r = sscanf(buf, "%7lf %7lf", &f1, &f2);
  printf("'%s'\n%d %g %g\n", buf, r, f1, f2);

  sprintf(buf, "%7.3f %7.3f", 999.999, 4.56);
  r = sscanf(buf, "%7lf %7lf", &f1, &f2);
  printf("'%s'\n%d %.10g %.10g\n", buf, r, f1, f2);

  sprintf(buf, "%7.3f %7.3f", 1000.007, 4.56);
  r = sscanf(buf, "%7lf %7lf", &f1, &f2);
  printf("'%s'\n%d %.10g %.10g\n", buf, r, f1, f2);

  return 0;
}

Output:  
'  1.230   4.560'  
2 1.23 4.56  
'999.999   4.560'  
2 999.999 4.56  
'1000.007   4.560'  
2 1000 7  

Кстати: для fscanf() подходит "%lf%lf%lf ...". Добавление пробелов между %lf не меняет функциональности.

person chux - Reinstate Monica    schedule 20.07.2013
comment
Я не думаю, что% 7lf является проблемой, поскольку значения столбца всегда находятся в диапазоне от 0 до 999,999. - person sdm142; 20.07.2013
comment
Я сделал снимок - кстати, ваши примерные значения включают -5,000, что находится за пределами диапазона 0 и 999,999. Если вы используете отрицательные числа, предельный диапазон %7lf составляет от -99,999 до 999,999. - person chux - Reinstate Monica; 20.07.2013
comment
Конечно, я ценю любые идеи/помощь. И эти отрицательные значения не меняются. Изменяются только столбцы 1, 5 и 6; остальные постоянны для всех входов. - person sdm142; 20.07.2013