⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch14_08.htm

📁 By Tom Christiansen and Nathan Torkington ISBN 1-56592-243-3 First Edition, published August 1998
💻 HTM
字号:
<HTML><HEAD><TITLE>Recipe 14.7. Treating a Text File as a Database Array (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:42:52Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch14_01.htm"TITLE="14. Database Access"><LINKREL="prev"HREF="ch14_07.htm"TITLE="14.6. Sorting Large DBM Files"><LINKREL="next"HREF="ch14_09.htm"TITLE="14.8. Storing Complex Data in a DBM File"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch14_07.htm"TITLE="14.6. Sorting Large DBM Files"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 14.6. Sorting Large DBM Files"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch14_01.htm"TITLE="14. Database Access"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch14_09.htm"TITLE="14.8. Storing Complex Data in a DBM File"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 14.8. Storing Complex Data in a DBM File"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch14-10143">14.7. Treating a Text File as a Database Array</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch14-pgfId-728">Problem<ACLASS="indexterm"NAME="ch14-idx-1000004980-0"></A><ACLASS="indexterm"NAME="ch14-idx-1000004980-1"></A><ACLASS="indexterm"NAME="ch14-idx-1000004980-2"></A><ACLASS="indexterm"NAME="ch14-idx-1000004980-3"></A></A></H3><PCLASS="para">You'd like to treat a text file as an array of lines with read-write privileges. You might want to do that so you could easily update the Nth line.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch14-pgfId-734">Solution</A></H3><PCLASS="para">The DB_File module lets you <CODECLASS="literal">tie</CODE> a text file to an array.</P><PRECLASS="programlisting">use DB_File;tie(@array, &quot;DB_File&quot;, &quot;/tmp/textfile&quot;, O_RDWR|O_CREAT, 0666, $DB_RECNO)    or die &quot;Cannot open file 'text': $!\en&quot; ;$array[4] = &quot;a new line&quot;;untie @array;</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch14-pgfId-754">Description</A></H3><PCLASS="para">Updating a textfile in place is surprisingly tricky, as noted in <ACLASS="xref"HREF="ch07_01.htm"TITLE="File Access">Chapter 7, <CITECLASS="chapter">File Access</CITE></A>. The RECNO binding provides a nice way to address the file as though it were a simple array of lines &nbsp;-  the way everyone always seems to think they can.</P><PCLASS="para">Working with files this way can be odd. For one thing, the zeroth element of the tied array is the first line of the file. More importantly, tied arrays aren't as fully featured as tied hashes are. This will be fixed in a future version of Perl &nbsp;-  patches are already available, in fact.</P><PCLASS="para">As you can see from the example above, the tied array interface is limited. To make the interface more useful, methods supplied with DB_File simulate the standard array operations that are not currently implemented in Perl's tied array interface. Save the return value from <CODECLASS="literal">tie</CODE> function or retrieve it later from the tied hash using the <CODECLASS="literal">tied</CODE> function. Use this object to access the following methods:</P><DLCLASS="variablelist"><DTCLASS="term"><CODECLASS="literal">$X-&gt;push(LIST)</CODE> </DT><DDCLASS="listitem"><PCLASS="para">Pushes elements of <CODECLASS="literal">LIST</CODE> to the end of the array.</P></DD><DTCLASS="term"><CODECLASS="literal">$value</CODE> <CODECLASS="literal">= $X-&gt;pop </CODE></DT><DDCLASS="listitem"><PCLASS="para">Removes and returns the last element of the array.</P></DD><DTCLASS="term"><CODECLASS="literal">$X-&gt;shift </CODE></DT><DDCLASS="listitem"><PCLASS="para">Removes and returns the first element of the array.</P></DD><DTCLASS="term"><CODECLASS="literal">$X-&gt;unshift(LIST) </CODE></DT><DDCLASS="listitem"><PCLASS="para">Pushes elements of <CODECLASS="literal">LIST</CODE> to the start of the array.</P></DD><DTCLASS="term"><CODECLASS="literal">$X-&gt;length </CODE></DT><DDCLASS="listitem"><PCLASS="para">Returns the number of elements in the array.</P></DD></DL><PCLASS="para"><ACLASS="xref"HREF="ch14_08.htm#ch14-19290"TITLE="recno_demo">Example 14.5</A> is a more complete example using methods described above. It also accesses the direct API interface as described in the DB_File module documentation. (Much of this recipe is derived from the DB_File module documentation, courtesy of Paul Marquess, author of the Perl port of Berkeley DB. This material is used with his permission.)</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch14-19290">Example 14.5: recno_demo</A></H4><PRECLASS="programlisting">#!/usr/bin/perl -w# <ACLASS="indexterm"NAME="ch14-idx-1000004981-0"></A>recno_demo - show how to use the raw API on recno bindingsuse strict;use vars qw(@lines $dbobj $file $i);use DB_File;$file = &quot;/tmp/textfile&quot;;unlink $file;               # just in case$dbobj = tie(@lines, &quot;DB_File&quot;, $file, O_RDWR|O_CREAT, 0666, $DB_RECNO)    or die &quot;Cannot open file $file: $!\n&quot;;# first create a text file to play with$lines[0] = &quot;zero&quot;;$lines[1] = &quot;one&quot;;$lines[2] = &quot;two&quot;;$lines[3] = &quot;three&quot;;$lines[4] = &quot;four&quot;;# Print the records in order.## The length method is needed here because evaluating a tied# array in a scalar context does not return the number of# elements in the array.print &quot;\nORIGINAL\n&quot;;foreach $i (0 .. $dbobj-&gt;length - 1) {    print &quot;$i: $lines[$i]\n&quot;;}# use the push &amp; pop methods$a = $dbobj-&gt;pop;$dbobj-&gt;push(&quot;last&quot;);print &quot;\nThe last record was [$a]\n&quot;;# and the shift &amp; unshift methods$a = $dbobj-&gt;shift;$dbobj-&gt;unshift(&quot;first&quot;);print &quot;The first record was [$a]\n&quot;;# Use the API to add a new record after record 2.$i = 2;$dbobj-&gt;put($i, &quot;Newbie&quot;, R_IAFTER);    # and a new record before record 1.$i = 1;$dbobj-&gt;put($i, &quot;New One&quot;, R_IBEFORE);# delete record 3$dbobj-&gt;del(3);# now print the records in reverse orderprint &quot;\nREVERSE\n&quot;;for ($i = $dbobj-&gt;length - 1; $i &gt;= 0; -- $i) {    print &quot;$i: $lines[$i]\n&quot;;}# same again, but use the API functions insteadprint &quot;\nREVERSE again\n&quot;;my ($s, $k, $v)  = (0, 0, 0);for ($s = $dbobj-&gt;seq($k, $v, R_LAST);     $s == 0;     $s = $dbobj-&gt;seq($k, $v, R_PREV)){    print &quot;$k: $v\n&quot;}undef $dbobj;untie @lines;</PRE></DIV><PCLASS="para">This is what it outputs:</P><PRECLASS="programlisting"><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>ORIGINAL</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>0: zero</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>1: one</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>2: two</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>3: three</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>4: four</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>The last record was [four]</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>The first record was [zero]</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>REVERSE</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>5: last</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>4: three</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>3: Newbie</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>2: one</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>1: New One</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>0: first</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>REVERSE again</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>5: last</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>4: three</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>3: Newbie</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>2: one</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>1: New One</I></CODE></B></CODE><CODECLASS="userinput"><B><CODECLASS="replaceable"><I>0: first</I></CODE></B></CODE></PRE><PCLASS="para">Note that rather than iterating through the array, <CODECLASS="literal">@lines</CODE>, like this:</P><PRECLASS="programlisting">    foreach $item (@lines) { }</PRE><PCLASS="para">you must use either this:</P><PRECLASS="programlisting">    foreach $i (0 .. $dbobj-&gt;length - 1) { }</PRE><PCLASS="para">or this:</P><PRECLASS="programlisting">    for ($done_yet = $dbobj-&gt;get($k, $v, R_FIRST);         not $done_yet;         $done_yet = $dbobj-&gt;get($k, $v, R_NEXT) )    {        # process key or value    }</PRE><PCLASS="para">Also, when we used the <CODECLASS="literal">put</CODE> method, we specified the record index using a variable, <CODECLASS="literal">$i</CODE>, rather than passing the literal value itself. This is because <CODECLASS="literal">put</CODE> returns the record number of the inserted line in that parameter, altering its contents.<ACLASS="indexterm"NAME="ch14-idx-1000004983-0"></A><ACLASS="indexterm"NAME="ch14-idx-1000004983-1"></A><ACLASS="indexterm"NAME="ch14-idx-1000004983-2"></A><ACLASS="indexterm"NAME="ch14-idx-1000004983-3"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch14-pgfId-1004">See Also</A></H3><PCLASS="para">The documentation for the standard DB_File module, also in <ACLASS="olink"HREF="../prog/ch07_01.htm">Chapter 7</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A>, in its discussion of <CODECLASS="literal">$DB_RECNO</CODE> bindings.</P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch14_07.htm"TITLE="14.6. Sorting Large DBM Files"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 14.6. Sorting Large DBM Files"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch14_09.htm"TITLE="14.8. Storing Complex Data in a DBM File"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 14.8. Storing Complex Data in a DBM File"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">14.6. Sorting Large DBM Files</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">14.8. Storing Complex Data in a DBM File</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright &copy; 2002</a> O'Reilly &amp; Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -