Как мне прочитать содержимое файла в скаляр Perl?
То, что я пытаюсь сделать, это получить содержимое файла с другого сервера. Так как я не настроен на 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
Что, я думаю, означает, что оно не возвращает значение.
Любая помощь высоко ценится.
>>>>>>>>> РЕДАКТИРОВАТЬ <<<<<<<<<<
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 ответов
Это описано в разделе 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
,
Используйте Path::Class::File::slurp, если вы хотите прочитать все содержимое файла за один раз.
Однако, что более важно, используйте анализатор HTML для анализа HTML.
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 и не будут работать надежно в общих случаях.
Также, если вам нужно отредактировать содержимое файлов, взгляните на модуль CPAN Tie::File
Этот модуль избавляет вас от необходимости создания временного файла для редактирования содержимого и записи его обратно в тот же файл.
РЕДАКТИРОВАТЬ:
То, на что вы смотрите - это способ украсть файл. Может быть, вам нужно отменить определение разделителя записей $/
Приведенный ниже код отлично работает для меня:
use strict; my $file = "test.txt"; { local( $/ ); # undefine the record seperator open FILE, "<", $file or die "Cannot open:$!\n"; my $lines =<FILE>; print $lines; }
Также см. Раздел "Традиционное хлебание" в этой статье.
НО, по какой-то причине два регулярных выражения возвращают false. Есть идеи почему?
.
в регулярном выражении по умолчанию соответствует любой символ, кроме новой строки. Предположительно у вас есть переводы строк перед </head>
тег и после <body>
тег. Делать .
соответствовать любому символу, включая символы новой строки, используйте //s
флаг.
Я не уверен, что ты print $0 . $1 ...
код о; вы ничего не захватываете в своих совпадениях для хранения в $1, а $0 - это не переменная, используемая для захвата регулярных выражений, это что-то совсем другое.
Использование File::Slurp::Tiny
, Так же удобно, как File::Slurp
, но без багов.