पर्ल में, मैं एक स्ट्रिंग में पूरी फाइल कैसे पढ़ सकता हूं?


118

मैं एक बड़ी लंबी स्ट्रिंग के रूप में एक .html फ़ाइल खोलने की कोशिश कर रहा हूँ। यह मेरे पास है:

open(FILE, 'index.html') or die "Can't read file 'filename' [$!]\n";  
$document = <FILE>; 
close (FILE);  
print $document;

जिसके परिणामस्वरूप:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN

हालाँकि, मैं चाहता हूँ कि परिणाम जैसा दिखे:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

इस तरह मैं पूरे दस्तावेज़ को अधिक आसानी से खोज सकता हूं।


8
वास्तव में यह जांचना चाहिए कि "केंट इंस्टॉल" की परिभाषा क्या है, यह एक आम समस्या है और इसका आमतौर पर एक तर्क है जिसे बनाने की आवश्यकता नहीं है। stackoverflow.com/questions/755168/perl-myths/…
केंट फ्रेड्रिक

1
मैं वास्तव में पूरे स्क्रिप्ट पर कुछ भी संशोधित करने में असमर्थ हूं कि यह स्क्रिप्ट चल रही है, स्क्रिप्ट के अलावा यह स्व।
गोडामड्यौर्यन

तो आपको सर्वर पर कहीं भी, किसी भी फाइल को जोड़ने की अनुमति नहीं है?
ब्रैड गिल्बर्ट

अपनी स्क्रिप्ट में फैटपैक मॉड्यूल? इसके अलावा, ऐसा लगता है कि आप नियमित भावों के साथ HTML पार्स करने की सोच रहे हैं, नहीं।
एमकेवी २

जवाबों:


81

जोड़ें:

 local $/;

फ़ाइल हैंडल से पढ़ने से पहले। देखें कि मैं एक बार में एक पूरी फ़ाइल में कैसे पढ़ सकता हूँ? , या

$ perldoc -q "संपूर्ण फ़ाइल"

देखें filehandles से संबंधित चर में perldoc perlvarऔर perldoc -f local

संयोग से, यदि आप सर्वर पर अपनी स्क्रिप्ट रख सकते हैं, तो आपके पास सभी मॉड्यूल हो सकते हैं जो आप चाहते हैं। देखें कि मैं अपने स्वयं के मॉड्यूल / पुस्तकालय निर्देशिका कैसे रखता हूं?

इसके अलावा, Path :: Class :: File आपको स्लेप और स्प्यू करने की अनुमति देता है ।

पथ :: टिनी और भी अधिक सुविधाजनक तरीके देता है slurp,slurp_rawslurp_utf8 जैसे कि , साथ ही साथ अपने spewसमकक्षों को भी।


33
आपको शायद यह बताना चाहिए कि $ / का स्थानीयकरण क्या प्रभाव डालता है और साथ ही इसका उद्देश्य क्या है।
डैनी

12
यदि आप स्थानीयकरण के बारे में कुछ भी समझाने नहीं जा रहे हैं $/, तो आपको संभवतः आगे की जानकारी के लिए लिंक जोड़ना चाहिए।
ब्रैड गिल्बर्ट

7
क्या कर रहा है के कदम स्पष्टीकरण द्वारा एक अच्छा कदम: {स्थानीय $ /; <$ fh>} यहां प्रदान किया गया है: perlmonks.org/?node_id=287647
dawez

शायद सिर्फ यह कहें कि आपको क्यों इस्तेमाल करना चाहिए localऔर क्या नहीं my
गेरमिया

@Geremia डांटने की चर्चा इस जवाब के दायरे से बाहर है।
सिनान Marnür

99

मैं इसे इस तरह से करूंगा:

my $file = "index.html";
my $document = do {
    local $/ = undef;
    open my $fh, "<", $file
        or die "could not open $file: $!";
    <$fh>;
};

खुले के तीन-तर्क संस्करण के उपयोग पर ध्यान दें। यह पुराने दो (या एक-) तर्क संस्करणों की तुलना में अधिक सुरक्षित है। लेक्सिकल फाइलहैंडल के उपयोग पर भी ध्यान दें। लेक्सिकल फाइलहैंडल कई कारणों से पुराने नंगे तलवार वाले वेरिएंट की तुलना में अच्छे हैं। हम यहां उनमें से एक का लाभ ले रहे हैं: वे दायरे से बाहर जाने पर बंद हो जाते हैं।


9
यह शायद ऐसा करने के लिए सबसे अच्छा गैर-cpan'd तरीका है क्योंकि यह दोनों 3 तर्क खुले का उपयोग करता है और साथ ही INPUT_RECORD_SEPARATOR ($ /) चर को छोटी से छोटी आवश्यक संदर्भ के लिए स्थानीय रखता है।
डैनी

77

ओपी ने कहा कि वह सर्वर पर कुछ भी संशोधित नहीं कर सकते। "हाँ, यहां तक ​​कि आप CPAN का उपयोग कर सकते हैं" लिंक आपको दिखाता है कि ज्यादातर मामलों में, उस सीमा के आसपास कैसे काम किया जाए।
ट्रेंटन

Can't locate File/Slurp.pm in @INC (@INC contains: /usr/lib/perl5/5.8/msys:(
दिमित्री

2
@ डमिट्री - तो मॉड्यूल स्थापित करें। इस जवाब से लिंक किए गए मेटापैन पेज पर एक इंस्टॉलेशन निर्देश लिंक है।
क्वेंटिन

53

सभी पद थोड़े गैर-मुहावरेदार हैं। मुहावरा है:

open my $fh, '<', $filename or die "error opening $filename: $!";
my $data = do { local $/; <$fh> };

अधिकतर, $ / to सेट करने की कोई आवश्यकता नहीं है undef


3
local $foo = undefसिर्फ पर्ल बेस्ट प्रैक्टिस (PBP) सुझाई गई विधि है। अगर हम कोड के स्निपिट पोस्ट कर रहे हैं तो मुझे लगता है कि यह स्पष्ट करने के लिए हमारी पूरी कोशिश होगी कि यह एक अच्छी बात हो।
डैनी

2
लोगों को दिखा रहा है कि गैर-मुहावरेदार कोड कैसे लिखना एक अच्छी बात है? यदि मैं कोड में "स्थानीय $ / = अपराजित" देखता था तो मैं काम कर रहा था, मेरी पहली कार्रवाई लेखक को सार्वजनिक रूप से irc पर अपमानित करने के लिए होगी। (और मैं "शैली" मुद्दों के बारे में आम तौर पर पसंद नहीं कर रहा हूँ।)
जुवेवे

1
ठीक है, मैं काट लूंगा: "स्थानीय $ / = अपरिभाषित" के बारे में वास्तव में क्या नकली है? यदि आपका एकमात्र उत्तर "यह गैर-मुहावरेदार है," तो (ए) मैं इतना निश्चित नहीं हूं और (बी) तो क्या? मुझे इतना यकीन नहीं है, क्योंकि यह एक ऐसा करने के तरीके के रूप में भयानक रूप से सामान्य है। और इसलिए क्या क्योंकि यह पूरी तरह से स्पष्ट और यथोचित संक्षिप्त है। आपको लगता है कि शैली के मुद्दों के बारे में अधिक picky हो सकता है।
टेलीमेकस

1
कुंजी यह है कि "स्थानीय $ /" एक प्रसिद्ध मुहावरे का हिस्सा है। यदि आप कुछ यादृच्छिक कोड लिख रहे हैं और "स्थानीय $ फू :: बार = अपरिभाषित" लिख रहे हैं, तो यह ठीक है। लेकिन इस बहुत ही विशेष मामले में, आप सभी के रूप में एक ही भाषा बोल सकते हैं, भले ही यह "कम स्पष्ट" हो (जो इससे सहमत नहीं है, "स्थानीय" का व्यवहार इस संबंध में अच्छी तरह से परिभाषित है)।
:

11
क्षमा करें, असहमत। जब आप एक जादू चर के वास्तविक व्यवहार को बदलना चाहते हैं तो यह स्पष्ट होना बहुत आम है; यह आशय की घोषणा है। यहां तक ​​कि प्रलेखन 'स्थानीय $ / = undef ' का उपयोग करता है (देखें perldoc.perl.org/perlsub.html#Temporary-Values-via-local () )
लियोनार्डो हरेरा

19

से perlfaq5: मैं कैसे एक पूरे फ़ाइल में सभी एक ही बार में पढ़ सकते हैं? :


आप इसे एक स्टेप में करने के लिए File :: Slurp मॉड्यूल का उपयोग कर सकते हैं।

use File::Slurp;

$all_of_it = read_file($filename); # entire file in scalar
@all_lines = read_file($filename); # one line per element

किसी फ़ाइल में सभी पंक्तियों को संसाधित करने के लिए प्रथागत पर्ल दृष्टिकोण एक समय में एक पंक्ति करने के लिए है:

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

यह पूरी फ़ाइल को मेमोरी में लाइनों की एक सरणी के रूप में पढ़ने और फिर एक समय में एक तत्व को संसाधित करने की तुलना में बहुत अधिक कुशल है, जो अक्सर होता है - यदि लगभग हमेशा नहीं - गलत दृष्टिकोण। जब भी आप किसी को ऐसा करते देखते हैं:

@lines = <INPUT>;

आपको लंबे और कठिन के बारे में सोचना चाहिए कि आपको एक ही बार में सब कुछ क्यों लोड करना चाहिए यह सिर्फ एक मापनीय समाधान नहीं है। आपको मानक टाई :: फ़ाइल मॉड्यूल, या DB_File मॉड्यूल के $ DB_RECNO बाइंडिंग का उपयोग करने में और अधिक मज़ा मिल सकता है, जो आपको किसी फ़ाइल के लिए एक सरणी बाँधने की अनुमति देता है ताकि किसी तत्व तक पहुँचने के लिए सरणी वास्तव में फ़ाइल में संबंधित लाइन तक पहुंच सके। ।

आप संपूर्ण फ़ाइलहैंड सामग्री को स्केलर में पढ़ सकते हैं।

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

यह अस्थायी रूप से आपके रिकॉर्ड विभाजक को हटा देता है, और स्वचालित रूप से ब्लॉक से बाहर निकलने पर फ़ाइल को बंद कर देगा। यदि फ़ाइल पहले से खुली है, तो इसका उपयोग करें:

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

साधारण फाइलों के लिए आप रीड फंक्शन का उपयोग कर सकते हैं।

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

तीसरा तर्क INPUT फ़ाइलहैंडल पर डेटा के बाइट आकार का परीक्षण करता है और पढ़ता है कि कई बाइट्स बफर वर्जन में हैं।


8

एक सरल तरीका है:

while (<FILE>) { $document .= $_ }

दूसरा तरीका इनपुट रिकॉर्ड सेपरेटर "$ /" को बदलना है। वैश्विक रिकॉर्ड विभाजक को बदलने से बचने के लिए आप इसे स्थानीय रूप से एक नंगे ब्लॉक में कर सकते हैं।

{
    open(F, "filename");
    local $/ = undef;
    $d = <F>;
}

1
आपके द्वारा दिए गए दोनों उदाहरणों के साथ समस्याओं की एक महत्वपूर्ण संख्या है। मुख्य समस्या यह है कि वे प्राचीन पर्ल में लिखे गए हैं, मैं आधुनिक पर्ल
ब्रैड गिल्बर्ट

@ ब्रैड, टिप्पणी वर्षों पहले की गई थी, बिंदु अभी भी खड़ा है। बेहतर है{local $/; open(my $f, '<', 'filename'); $d = <$f>;}
जोएल बर्जर

@ जोल केवल थोड़ा बेहतर है। आपने openया कथित रूप से कहे जाने वाले आउटपुट की जाँच नहीं की closemy $d = do{ local $/; open(my $f, '<', 'filename') or die $!; my $tmp = <$f>; close $f or die $!; $tmp}। (यह अभी भी समस्या है कि यह इनपुट एन्कोडिंग को निर्दिष्ट नहीं करता है।)
ब्रैड गिल्बर्ट

use autodieमैं दिखाने के लिए मुख्य सुधार lexical filehandle और 3 arg खुला था। वहाँ कुछ कारण आप doइस आईएनजी हैं ? ब्लॉक से पहले घोषित चर में फ़ाइल को डंप क्यों न करें?
जोएल बर्जर

7

या तो सेट $/करें undef(jrockway का उत्तर देखें) या फ़ाइल की सभी पंक्तियों को संक्षिप्त करें:

$content = join('', <$fh>);

इसे समर्थन करने वाले किसी भी पर्ल संस्करण पर फ़ाइलहैंडल के लिए स्केलर्स का उपयोग करने की अनुशंसा की जाती है।


4

दूसरा संभावित तरीका:

open my $fh, '<', "filename";
read $fh, my $string, -s $fh;
close $fh;

3

आप हीरा ऑपरेटर से केवल पहली पंक्ति प्राप्त <FILE>कर रहे हैं क्योंकि आप इसे स्केलर संदर्भ में मूल्यांकन कर रहे हैं:

$document = <FILE>; 

सूची / सरणी संदर्भ में, हीरा ऑपरेटर फ़ाइल की सभी पंक्तियों को लौटा देगा।

@lines = <FILE>;
print @lines;

1
केवल नामकरण पर एक नोट: अंतरिक्ष यान ऑपरेटर है <=>और <>हीरा ऑपरेटर है।
टूलिक

ओह, धन्यवाद, मैंने पहले "डायमंड ऑपरेटर" नहीं सुना था और सोचा था कि वे दोनों एक ही नाम साझा करेंगे। मैं इसे ऊपर सही कर दूंगा।
नाथन

2

मैं इसे सबसे सरल तरीके से करूंगा, इसलिए कोई भी समझ सकता है कि क्या होता है, भले ही होशियार तरीके हों:

my $text = "";
while (my $line = <FILE>) {
    $text .= $line;
}

वे सभी स्ट्रिंग कॉन्टेक्शंस काफी महंगे होने वाले हैं। मैं ऐसा करने से बचूंगा। डेटा को एक साथ वापस लाने के लिए केवल आंसू क्यों?
औररू

2
open f, "test.txt"
$file = join '', <f>

<f>- हमारी फ़ाइल (यदि $/डिफ़ॉल्ट मान है "\n") से लाइनों की एक सरणी लौटाता है और फिर join ''इस सरणी को इसमें चिपका देगा।


2

यह कैसे पर एक सुझाव के अधिक है नहीं यह करने के लिए। मैं सिर्फ एक बुरा समय एक बड़ा पर्ल अनुप्रयोग में एक बग खोजने के लिए किया है। अधिकांश मॉड्यूल की अपनी कॉन्फ़िगरेशन फ़ाइलें थीं। संपूर्ण रूप में कॉन्फ़िगरेशन फ़ाइलों को पढ़ने के लिए, मुझे इंटरनेट पर कहीं-कहीं पर्ल की यह एकल पंक्ति मिली:

# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};

यह रेखा विभाजक को पहले बताए अनुसार पुन: असाइन करता है। लेकिन यह एसटीडीआईएन को भी आश्वस्त करता है।

इसका कम से कम एक साइड इफ़ेक्ट था जो मुझे ढूंढने में घंटों का समय लगता था: यह निहित फ़ाइल हैंडल को ठीक से बंद नहीं करता है (क्योंकि यह बिल्कुल भी कॉल नहीं करता है close)।

उदाहरण के लिए, ऐसा करना:

use strict;
use warnings;

my $filename = 'some-file.txt';

my $content = do{local(@ARGV,$/)=$filename;<>};
my $content2 = do{local(@ARGV,$/)=$filename;<>};
my $content3 = do{local(@ARGV,$/)=$filename;<>};

print "After reading a file 3 times redirecting to STDIN: $.\n";

open (FILE, "<", $filename) or die $!;

print "After opening a file using dedicated file handle: $.\n";

while (<FILE>) {
    print "read line: $.\n";
}

print "before close: $.\n";
close FILE;
print "after close: $.\n";

का परिणाम:

After reading a file 3 times redirecting to STDIN: 3
After opening a file using dedicated file handle: 3
read line: 1
read line: 2
(...)
read line: 46
before close: 46
after close: 0

अजीब बात यह है, कि $.हर फाइल के लिए एक-एक करके लाइन काउंटर बढ़ाया जाता है। यह रीसेट नहीं है, और इसमें लाइनों की संख्या नहीं है। और कम से कम एक पंक्ति पढ़ने तक दूसरी फ़ाइल खोलने पर इसे शून्य पर रीसेट नहीं किया जाता है। मेरे मामले में, मैं कुछ इस तरह कर रहा था:

while($. < $skipLines) {<FILE>};

इस समस्या के कारण, स्थिति झूठी थी क्योंकि लाइन काउंटर ठीक से रीसेट नहीं किया गया था। मुझे नहीं पता कि यह बग है या बस गलत कोड ... इसके अलावा close;ओडर कॉल करने से भी close STDIN;मदद नहीं मिलती है।

मैंने इस अपठनीय कोड को खुले, स्ट्रिंग संयोजन और बंद का उपयोग करके बदल दिया। हालांकि, ब्रैड गिल्बर्ट द्वारा पोस्ट किया गया समाधान भी काम करता है क्योंकि यह इसके बजाय एक स्पष्ट फ़ाइल हैंडल का उपयोग करता है।

शुरुआत में तीन पंक्तियों को प्रतिस्थापित किया जा सकता है:

my $content = do{local $/; open(my $f1, '<', $filename) or die $!; my $tmp1 = <$f1>; close $f1 or die $!; $tmp1};
my $content2 = do{local $/; open(my $f2, '<', $filename) or die $!; my $tmp2 = <$f2>; close $f2 or die $!; $tmp2};
my $content3 = do{local $/; open(my $f3, '<', $filename) or die $!; my $tmp3 = <$f3>; close $f3 or die $!; $tmp3};

जो फ़ाइल हैंडल को ठीक से बंद कर देता है।


2

उपयोग

 $/ = undef;

पहले $document = <FILE>;$/है इनपुट रिकॉर्ड विभाजक , जो डिफ़ॉल्ट रूप से एक नई पंक्ति है। इसे फिर से परिभाषित करके undef, आप कह रहे हैं कि कोई क्षेत्र विभाजक नहीं है। इसे "स्लरप" मोड कहा जाता है।

अन्य समाधान जैसे undef $/और local $/(लेकिन नहीं my $/) $ redeclare / और इस प्रकार एक ही प्रभाव पैदा करते हैं।



0

मुझे नहीं पता कि यह अच्छा अभ्यास है, लेकिन मैं इसका उपयोग करता था:

($a=<F>);

-1

ये सभी अच्छे उत्तर हैं। लेकिन अगर आप आलसी महसूस कर रहे हैं, और फ़ाइल इतनी बड़ी नहीं है, और सुरक्षा कोई समस्या नहीं है (आपको पता है कि आपके पास दागी फ़ाइल नाम नहीं है), तो आप बाहर खोल सकते हैं:

$x=`cat /tmp/foo`;    # note backticks, qw"cat ..." also works

-2

आप लिनक्स में बिल्ली का उपयोग कर सकते हैं:

@file1=\`cat /etc/file.txt\`;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.