2013-03-31 4 views
-1

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

В какой-то момент, прочитав файл с 90,855 строками и некоторым другим вторым файлом, скрипт полностью не читает строку файла.

Я подсчитал количество символов, прочитанных до тех пор, пока это не произойдет: 233,467, и поэтому попытался сбросить буфер и спящий режим перед чтением следующей строки файла. Это не работает.

Любые предложения, пожалуйста?

Вот мой код:

foreach $i (@files) { 

    my $buff = 0; 

    print "Analyzing $i\n"; 
    sleep(1); 
    $program = $1 if $i =~ /(\w+)_SITES/; 

    open(FIL, $i) or die "$!: $i\n"; 
    while (<FIL>) { 

     $buff += length($_); 
     if ($buff >= 230000) { #FLUSH THE BUFFER, NOT WORKING!!! 
      $buff = 0; 
      sleep(1); 
      select((select(FIL), $| = 1)[0]); 
     } 

     undef($a); 
     unless ($. == 1) { 
      if ($o == 0) { 
       if (/^\d+\t(\S+)\t(\S+)\t(\d+)\t(\d+)\t(\S+)\t(\S+)\t(.*)/) { 
        $mirna = $1; 
        $target = $2; 
        $start = $3; 
        $end = $4; 
        $site = $5; 
        $comp_p = $6; 
        $a  = $7; 
        $j  = "${mirna}_${target}_${start}_$end"; 
        $site_nu{$j} = "$mirna\t$target\t$start\t$end\t$site\t$comp_p"; # Store each site in a hash 
       } 
       else { #DIES HERE!!! 
        die "$buff characters, in line $.:$_\n" 
       } 
      } 
      else { 
       if (/^\d+\t(\S+)\t(\S+)\t(\d+)\t(\d+)\t(\S+)\t(.*)/) { 
        $mirna  = $1; 
        $target  = $2; 
        $start  = $3; 
        $end   = $4; 
        $site  = $5; 
        $a   = $6; 
        $j   = "${mirna}_${target}_${start}_$end"; 
        $site_nu{$j} = "$mirna\t$target\t$start\t$end\t$site"; # Store each site in a hash 
       } 
      } 

Он умирает на "СКОНЧАЛСЯ ЗДЕСЬ !!" умереть, прочитав 3,413 символов второго файла.

Это происходит потому, что регулярное выражение не работает, так как только половина строки находится в $ _.

+0

Этот сценарий является одним поточным? – Glenn

+0

Переменная '$ |' управляет автоматической очисткой * выходных файлов * после каждого выражения 'print'. Он не влияет на входные файлы, а сброс входного файла не имеет смысла. – Borodin

+0

Если вы пытаетесь прочитать файл с разделяемой вкладкой, вы можете взглянуть на ['Text :: CSV'] (http://search.cpan.org/perldoc?Text%3A%3ACSV). Вы также должны добавить 'use strict; использовать предупреждения, 'к этому скрипту и исправить ошибки/предупреждения. Затем перепишите код, чтобы уменьшить масштаб всех переменных до минимально возможного, используя ключевое слово 'my'. – TLP

ответ

2

Проблема почти наверняка заключается в том, что данные не находятся в вашем файле для чтения.

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

Вы должны проверить состояние успеха вашего close вызова, как этот

close FILEHANDLE or die "Unable to close temporary file: $!"; 

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

  • Вы должны всегдаuse strict и use warnings и объявить все переменные, используя my как можно ближе к их первому месту использования. Если вы не решили объявить все в верхней части своей программы (очень плохая идея), вы этого не сделали

  • Ваш выбор имен переменных является неустойчивым. $i для имени файла? И $o для - erm - что-то? $buff бы хорошо, за исключением, что это размера из воображаемой buffre вместо буфера istelf

  • Вы должны использовать лексические дескрипторы файлы с формой трехпараметрической open: open my $fil, '<', $i or die "$!: $i";

  • Если вы используете $| правильно, он более аккуратный и более читаемый, чтобы использовать FILE->autoflush вместо трюка замены выбранного дескриптора файла и установки $|.Для этого вам нужно use IO::Handle в начале вашего кода, если вы не работаете в Perl 5 версии 14 или более поздней версии, который загружает IO::File (и, следовательно, IO::Handle) по требованию

  • Я думаю, что просто split /\t/ будет лучше, чем регулярное выражение вас используются. Кроме того, похоже, вы бы лучше с хэш-массивов для %site_nu как этот $site_nu{$j} = [$mirna, $target, $start, $end, $site, $comp_p]

  • Ввод новой строки в конце die строки останавливает Perl от отображения информации об источнике и файлы данных и номера строк, которые вероятно, будет полезен, пока вы отлаживаете

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

+0

Спасибо за комментарии, ребята. Да, я использую строгие предупреждения и предупреждения использования, объявляю переменные с моим и успешно закрываю все файлы после завершения печати. Я проверил, и данные действительно находятся в файлах, которые нужно прочитать. Я попробую все другие предложения, и я вернусь к вам. Огромное спасибо. – dannyjmh

+0

Привет всем. В конце концов, я сбросил обработчик выходного файла, который я использовал, прежде чем начинать разбор файлов и решить проблему. Большое вам спасибо за помощь. – dannyjmh

+0

@dannyjmh: Тогда вы не можете закрыть его правильно. Лучше закрыть файл, чем сбросить его. Вы также должны объявлять свои переменные в большом блоке в начале программы, что не очень хорошо. – Borodin