Проблемы с чтением файла (построчно)

#perl #file #while-loop

#perl #файл #цикл while

Вопрос:

Я пытаюсь автоматизировать программу анализа данных с помощью gnuplot, по сути, я запускаю программу подгонки кривой в gnuplot, а затем читаю файл журнала, чтобы извлечь нужные значения для дальнейшего анализа.

Вот раздел кода:

 #Open curvefit log file to gather the needed coefficients
open (FILE_CURVE, 'fit.log') or die;
while (<FILE_CURVE>)
{   
    push(@log, $_);
    print "Im heren";
}
close (FILE_CURVE);
  

Моя проблема в том, что он не входит в цикл while, поскольку я не вижу print "Im heren"; строку кода.

Также в начале программы я удаляю файл журнала, чтобы он не убежал. Программа curve fit воссоздает его.

Вот как выглядит файл журнала. Примечание: в начале файла есть две пустые строки.

 *******************************************************************************
Tue May 17 11:28:59 2011


FIT:    data read from 'temp_norm.txt' using 1:2
        #datapoints = 2000
        residuals are weighted equally (unit weight)

function used for fitting: g(x)
fitted parameters initialized with current variable values



 Iteration 0
 WSSR        : 566.797           delta(WSSR)/WSSR   : 0
 delta(WSSR) : 0                 limit for stopping : 1e-05
 lambda   : 1.49986

initial set of free parameter values

cc              = 100
dd              = 9.3

After 31 iterations the fit converged.
final sum of squares of residuals : 24.1325
rel. change during last iteration : 0

degrees of freedom    (FIT_NDF)                        : 1998
rms of residuals      (FIT_STDFIT) = sqrt(WSSR/ndf)    : 0.109901
variance of residuals (reduced chisquare) = WSSR/ndf   : 0.0120783

Final set of parameters            Asymptotic Standard Error
=======================            ==========================

cc              = 108.497           /- 3.189        (2.939%)
dd              = 8.8375            /- 0.0001571    (0.001777%)


correlation matrix of the fit parameters:

               cc     dd     
cc              1.000 
dd              0.246  1.000 
  

Комментарии:

1. Правильно ли я вас понял, если я думаю, что вы говорите о том, что вы запускаете что-то вроде сценария оболочки для первого выполнения gnuplot и непосредственно после сценария perl для проверки журнала? Итак, ваша проблема в том, что скрипт perl обращается к вашему файлу журнала слишком рано, когда файл пуст?

2. Если это так, вы можете запустить gnuplot из скрипта perl, тем самым получив контроль над завершением процесса.

3. Оказывается, проблема заключалась в том, что gnuplot недостаточно быстро создавал файл fit.log, поэтому мне пришлось подождать (5);, чтобы дать gnuplot некоторое время.

Ответ №1:

Здесь есть пара проблем:

1. Настоятельно рекомендуется использовать форму open с тремя аргументами и использовать локальный var, а не FILEHANDLE, что приведет к загрязнению вашего глобального пространства имен, поэтому вместо

 open (FILE_CURVE, 'fit.log') or die;
  

использование

 open(my $fh, '<', 'fit.log') or die; 
while(<$fh>){
}
close($fh);
  

2. Удаление файла с открытым дескриптором файла «на самом деле» не приводит к его удалению, и если вы читаете из дескриптора файла в «удаленном» файле, вы просто будете читать из старого файла. Файлы действительно удаляются, когда удаляются все ссылки на них, включая открытые дескрипторы файлов, что может занять некоторое время. Одна из стратегий, которую вы могли бы рассмотреть, это:

 sleep 1 while ! -f $path_to_logfile; # sleep until the file exists
  

3. Для того, что вы хотите, есть библиотека.

Проверьте File::Tail и Filesys::Notify::Simple

—РЕДАКТИРОВАТЬ—

Основываясь на ваших комментариях, я бы предположил, что происходит что-то подобное:

Предполагается, что два агента:

 a producer (gnuplot) that writes to the log file 

a consumer (your script) that reads from the log file
  
  1. производитель запускает

    1.1 запись в файл журнала

  2. пользователь запускает

    2.1 удаляет файл журнала

    2.2 открывает файл журнала для чтения

    2.3 не находит строк для чтения

    2.4 завершается

Если это так, то, удаляя файл на версии 2.1, в который производитель все еще записывает сообщения журнала, вы создаете ситуацию, когда производитель выполняет запись в «зависший» файл, который был удален из файловой системы, но для которого все еще открыт дескриптор.

Затем, когда вы открываете журнал в версии 2.2, файл воссоздается как пустой файл, что означает, что ваш цикл while не найдет никаких строк и ваша печать не произойдет.

Я бы рекомендовал либо:

  1. запустите программу-потребитель перед запуском программы-производителя и попросите ее подождать, пока не появится файл журнала, чтобы попытаться открыть его (используя команду sleep выше), или

  2. сначала запустите программу-производитель, но не удаляйте файл журнала в системе-получателе.

Комментарии:

1. Общее эмпирическое правило: обычно для этого есть библиотека Perl. 😉

2. Итак, я использовал ваш метод open, и я получаю сообщение не удается открыть, но файл есть…

Ответ №2:

На первый взгляд кажется, что ваш синтаксис для этого цикла правильный. Вы уверены, что к файлу действительно осуществляется доступ? Попробуйте добавить сообщение для die «файл не удается открыть: $!», как $! распечатает все сообщения об ошибках, связанные с открытием файла.

Кроме того, если вы этого еще не сделали, воспользуйтесь прагматиками strict и warnings.