Как мне прочитать содержимое файла в скаляр Perl? - PullRequest
0 голосов
/ 06 февраля 2010

что я пытаюсь сделать, это получить содержимое файла с другого сервера. Так как я не настроен на Perl и не знаю его модов и функций, я пошел по этому пути:

 my $fileContents;
 if( $md5Con =~ m/\.php$/g ) {
     my $ftp = Net::FTP->new($DB_ftpserver, Debug => 0) or die "Cannot connect to some.host.name: $@";
     $ftp->login($DB_ftpuser, $DB_ftppass) or die "Cannot login ", $ftp->message;
     $ftp->get("/" . $root . $webpage, "c:/perlscripts/" . md5_hex($md5Con) . "-code.php") or die $ftp->message;
     open FILE, ">>c:/perlscripts/" . md5_hex($md5Con) . "-code.php" or die $!;
     $fileContents = <FILE>;
     close(FILE);
     unlink("c:/perlscripts/" . md5_hex($md5Con) . "-code.php");
     $ftp->quit;
 }

То, что я думал, что id делает, это получает файл с сервера, помещает его на мой локальный компьютер, редактирует содержимое, загружает куда угодно и затем удаляет временный файл.

Но я не могу понять, как получить содержимое файла;

open FILE, ">>c:/perlscripts/" . md5_hex($md5Con) . "-code.php" or die $!;
$fileContents = <FILE>;
close(FILE);

продолжаю получать ошибку;

Использование неинициализированного значения $ fileContents

Что, я думаю, означает, что оно не возвращает значение.

Любая помощь высоко ценится.

>>>>>>>>>> РЕДАКТИРОВАТЬ <<<<<<<<<< </strong>

my $fileContents;
if( $md5Con =~ m/\.php$/g ) {
    my $ftp = Net::FTP->new($DB_ftpserver, Debug => 0) or die "Cannot connect to some.host.name: $@";
    $ftp->login($DB_ftpuser, $DB_ftppass) or die "Cannot login ", $ftp->message;
    $ftp->get("/" . $root . $webpage, "c:/perlscripts/" . md5_hex($md5Con) . "-code.php") or die $ftp->message;
    my $file = "c:/perlscripts/" . md5_hex($md5Con) . "-code.php";
    {
        local( $/ ); # undefine the record seperator
        open FILE, "<", $file or die "Cannot open:$!\n";
        my $fileContents = <FILE>;
        #print $fileContents;
        my $bodyContents;
        my $headContents;

        if( $fileContents =~ m/<\s*body[^>]*>.*$/gi ) {
            print $0 . $1 . "\n";
            $bodyContents = $dbh->quote($1);    
        }
        if( $fileContents =~ m/^.*<\/head>/gi ) {
            print $0 . $1 . "\n";
            $headContents = $dbh->quote($1);    
        }

        $bodyTable = $dbh->quote($bodyTable);
        $headerTable = $dbh->quote($headerTable);
        $dbh->do($createBodyTable) or die " error: Couldn't create body table: " . DBI->errstr;
        $dbh->do($createHeadTable) or die " error: Couldn't create header table: " . DBI->errstr;
        $dbh->do("INSERT INTO $headerTable ( headData, headDataOutput ) VALUES ( $headContents, $headContents )") or die " error: Couldn't connect to database: " . DBI->errstr;
        $dbh->do("INSERT INTO $bodyTable ( bodyData, bodyDataOutput ) VALUES ( $bodyContents, $bodyContents )") or die " error: Couldn't connect to database: " . DBI->errstr;
        $dbh->do("INSERT INTO page_names (linkFromRoot, linkTrue, page_name, table_name, navigation, location) VALUES ( $linkFromRoot, $linkTrue, $page_name, $table_name, $navigation, $location )") or die " error: Couldn't connect to database: " . DBI->errstr;

        unlink("c:/perlscripts/" . md5_hex($md5Con) . "-code.php");
    }
    $ftp->quit;
}

вышеизложенное с использованием print БУДЕТ распечатать весь файл. НО, по какой-то причине два регулярных выражения возвращают false. Есть идеи почему?

if( $fileContents =~ m/<\s*body[^>]*>.*$/gi ) {
            print $0 . $1 . "\n";
            $bodyContents = $dbh->quote($1);    
        }
        if( $fileContents =~ m/^.*<\/head>/gi ) {
            print $0 . $1 . "\n";
            $headContents = $dbh->quote($1);    
        }

Ответы [ 7 ]

10 голосов
/ 06 февраля 2010

Это , описанное в разделе 5 FAQ по Perl , входящему в стандартную поставку.

Как я могу прочитать весь файл сразу?

Вы можете использовать модуль Path::Class::File::slurp, чтобы сделать это за один шаг.

use Path::Class;
$all_of_it = file($filename)->slurp; # entire file in scalar
@all_lines = file($filename)->slurp; # one line per element

Обычный подход Perl для обработки всех строк в файле состоит в том, чтобы делать это по одной строке за раз:

open (INPUT, $file) || die "can't open $file: $!";
while (<INPUT>) {
    chomp;
    # do something with $_
}
close(INPUT)        || die "can't close $file: $!";

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

@lines = <INPUT>;

Вы должны долго и усердно думать о том, зачем вам нужно загружать все сразу. Это просто не масштабируемое решение. Вам также может быть интереснее использовать стандартный модуль Tie::File или привязки DB_File модуля $DB_RECNO, которые позволяют привязать массив к файлу так, что при доступе к элементу массив фактически обращается к соответствующей строке в файле.

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

{
local(*INPUT, $/);
open (INPUT, $file) || die "can't open $file: $!";
$var = <INPUT>;
}

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

$var = do { local $/; <INPUT> };

Для обычных файлов вы также можете использовать функцию read.

read( INPUT, $var, -s INPUT );

Третий аргумент проверяет размер байта данных в файловом дескрипторе INPUT и считывает столько байтов в буфер $var.

8 голосов
/ 06 февраля 2010

Используйте Path :: Class :: File :: slurp , если вы хотите прочитать все содержимое файла за один раз.

Однако, что более важно, используйте HTML-анализатор для анализа HTML.

3 голосов
/ 06 февраля 2010
open FILE, "c:/perlscripts" . md5_hex($md5Con) . "-code.php" or die $!;
while (<FILE>) {
    # each line is in $_
}
close(FILE);

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

Замечу, что вы также используете регулярные выражения для разбора HTML. Обычно я бы рекомендовал использовать для этого парсер (например, см. HTML :: Parser ). Регулярные выражения не подходят для HTML из-за отсутствия регулярности в HTML и не будут работать надежно в общих случаях.

2 голосов
/ 06 февраля 2010

Кроме того, если вам нужно редактировать содержимое файлов, взгляните на модуль CPAN Tie :: File
Этот модуль избавляет вас от необходимости создания временного файла.для редактирования содержимого и записи его обратно в один и тот же файл.

РЕДАКТИРОВАТЬ :
То, на что вы смотрите, - это способ сохранить файл.Возможно, вам придется отменить определение разделителя записей $/

У меня отлично работает приведенный ниже код: </p> <pre><code>use strict; my $file = "test.txt"; { local( $/ ); # undefine the record seperator open FILE, "<", $file or die "Cannot open:$!\n"; my $lines =<FILE>; print $lines; }

Также см. Раздел «Традиционное слэпинг»1016 * товар .

1 голос
/ 07 февраля 2010

НО, по какой-то причине два регулярных выражения возвращают false.Любая идея, почему?

. в регулярном выражении по умолчанию соответствует любому символу кроме символа новой строки .Предположительно, у вас есть новые строки перед тегом </head> и после тега <body>.Чтобы . соответствовал любому символу, включая символы новой строки, используйте флаг //s.

Я не уверен, что означает ваш код print $0 . $1 ...;вы не захватываете что-либо в своих совпадениях для хранения в $ 1, а $ 0 - это не переменная, используемая для захвата регулярных выражений, это что-то совсем другое.

0 голосов
/ 16 августа 2014

Использование File::Slurp::Tiny.Так же удобно, как File::Slurp, но без ошибок .

0 голосов
/ 06 февраля 2010

, если вы хотите получить содержимое файла,

 @lines = <FILE>;
...