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

📄 ch18.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
Because it's possible to use the DBM files from within modules,

let's see if the <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

module (covered in <A HREF="ch5.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch5.htm" >Chapter 5</A>, &quot;Object-Oriented

Programming in Perl&quot;) can be updated to include saving and

restoring portfolio information on disk. You will be appending

some functions to the original <TT><FONT FACE="Courier">Invest.pm</FONT></TT>.

All the new functions will go at the end of the file unless specified

<BR>

otherwise. 

<P>

Some changes need to be made to the <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

module to get it to work with the DBM files. The first change

is to include the following statement before the first executable

line in the <TT><FONT FACE="Courier">Invest.pm</FONT></TT> file:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">require AnyDBM_File;</FONT></TT>

</BLOCKQUOTE>

<P>

The <TT><FONT FACE="Courier">@portfolio</FONT></TT> array is changed

to <TT><FONT FACE="Courier">%portfolio</FONT></TT> because this

array can be mapped directly to disk via a DBM file. The <TT><FONT FACE="Courier">@portfolio</FONT></TT>

array contains references to hashes and not the content of the

item in the referenced hash. Therefore, a new scheme has to be

incorporated in order to parse the values and then store them

to disk. After the values are stored to disk, the reverse operation

has to be applied to read them back. Because this sample portfolio

is not a large database, the important values can be stored using

a colon delimited array. If this example were a very large array,

the items could be stored with the <TT><FONT FACE="Courier">pack()</FONT></TT>

function and thus store only binary values.

<P>

A new function has to be created to save the contents of the portfolio

to disk. Add the following function to the end of the <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

file on or about line 116:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">savePortfolio {<BR>

my ($this, $filename) = @_;<BR>

my %dummy;<BR>

my $a;<BR>

my ($key, $val);<BR>

dbmopen(%dummy,$filename,0666);<BR>

while (($key,$val) = each(%portfolio)) {<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;$a = &quot;$key:&quot; . $val-&gt;{'type'}

. &quot;:&quot; .<BR>

&nbsp;&nbsp;&nbsp;&nbsp;$val-&gt;{'symbol'} . &quot;:&quot; .

$val-&gt;{'shares'};<BR>

&nbsp;&nbsp;&nbsp;&nbsp;$dummy{$key} = $a;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;# Debug: print &quot;\n Writing $dummy{$key}&quot;;

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

dbmclose(%dummy);<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

The <TT><FONT FACE="Courier">%dummy</FONT></TT> hash is used to

map to the disk file. Each item in the <TT><FONT FACE="Courier">portfolio</FONT></TT>

hash is parsed for storage in the <TT><FONT FACE="Courier">%dummy</FONT></TT>

hash. The value of <TT><FONT FACE="Courier">$key</FONT></TT> goes

from <TT><FONT FACE="Courier">0</FONT></TT>, <TT><FONT FACE="Courier">1</FONT></TT>,

<TT><FONT FACE="Courier">2</FONT></TT>, and up. One string is

saved to disk per hash item. Here's the format of the string:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$key:$type:$symbol:$shares</FONT></TT>

</BLOCKQUOTE>

<P>

<TT><FONT FACE="Courier">$type</FONT></TT> can be <TT><FONT FACE="Courier">Stock</FONT></TT>

or <TT><FONT FACE="Courier">Fund</FONT></TT>. <TT><FONT FACE="Courier">$symbol</FONT></TT>

is the stock or fund symbol and <TT><FONT FACE="Courier">$shares</FONT></TT>

is the number of shares of the stock. Keep in mind that this is

only an example-the real data stored would probably have to include

date of purchase, purchase price, and so on. In this event, the

fields could be appended to the string with colons separating

each field. If you want to add purchase price, your field would

look like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$key:$type:$symbol:$shares:$purchased</FONT></TT>

</BLOCKQUOTE>

<P>

To restore the file back from disk, the <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

file will have to read back the same portfolio file and restore

all the values in the portfolio array. The function will also

have to recognize the difference between the types of items it

has to re-create. The restoration is done by this function which

is added to the end of the <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

file at about line 132:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub restorePortfolio {<BR>

my ($this, $filename) = @_;<BR>

my %dummy;<BR>

my ($key, $val);<BR>

my ($ndx,$sec,$sym,$shr);<BR>

my $a;<BR>

local $i1;<BR>

dbmopen(%dummy,$filename,0666);<BR>

while (($key,$val) = each(%dummy)) {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;$a = $dummy{$key};<BR>

&nbsp;&nbsp;&nbsp;&nbsp;($ndx,$sec,$sym,$shr) = split(':',$a);

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;# print &quot;Read back $ndx,$sec,$sym,$shr

\n&quot;;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;if ($sec eq 'Fund')<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i1 = Invest::Fund::new('Invest::Fund',

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'symbol'

=&gt; &quot;$sym&quot;, 'shares' =&gt; &quot;$shr&quot;);<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

&nbsp;&nbsp;&nbsp;&nbsp;else<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i1 = Invest::Stock::new('Invest::Stock',

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'symbol'

=&gt; &quot;$sym&quot;, 'shares' =&gt;&quot;$shr&quot;);<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;Invest::AddItem($i1);

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;Invest::showPortfolio;

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

dbmclose(%dummy);<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

To create the sample portfolio, use the shell script shown in

Listing 18.6. You might want to edit the code shown in Listing

18.6 to print the reported information in a different format than

the one shown here. In this sample script, two stocks are added

and then the contents of the portfolio are printed.

<HR>

<BLOCKQUOTE>

<B>Listing 18.6. Creating a sample portfolio.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 <BR>

&nbsp;3 push(@Inc,'pwd');<BR>

&nbsp;4 <BR>

&nbsp;5 use Invest;<BR>

&nbsp;6 # use Invest::Fund;<BR>

&nbsp;7 use Invest::Stock;<BR>

&nbsp;8 <BR>

&nbsp;9 #<BR>

10 # Create a new portfolio object<BR>

11 #<BR>

12 $port = new Invest;<BR>

13 <BR>

14 print &quot;\n -- CREATE PORTFOLIO --&quot;;<BR>

15 $s1 = new Invest::Stock('symbol' =&gt; 'AMAT', 'shares' =&gt;

'400');<BR>

16 $s2 = new Invest::Stock('symbol' =&gt; 'INTC', 'shares' =&gt;

'200');<BR>

17 <BR>

18 print &quot;\n Adding stocks &quot;;<BR>

19 $port-&gt;Invest::AddItem($s1);<BR>

20 $port-&gt;Invest::AddItem($s2);<BR>

21 <BR>

22 $port-&gt;Invest::showPortfolio();<BR>

23 <BR>

24 #<BR>

25 #&nbsp;&nbsp;&nbsp;SAVE THE DATA HERE in the DBM file called

myStocks<BR>

26 #<BR>

27 $port-&gt;Invest::savePortfolio(&quot;myStocks&quot;);</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

To view the contents of the portfolio, you'll have to write another

simple script. This script is shown is Listing 18.7. The file

to recover data from is called <TT><FONT FACE="Courier">myStocks</FONT></TT>.

You should be able to see this file in your directory.

<HR>

<BLOCKQUOTE>

<B>Listing 18.7. Listing the portfolio.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 <BR>

&nbsp;3 push(@Inc,'pwd');<BR>

&nbsp;4 <BR>

&nbsp;5 use Invest;<BR>

&nbsp;6 use Invest::Fund;<BR>

&nbsp;7 use Invest::Stock;<BR>

&nbsp;8 <BR>

&nbsp;9 $port = new Invest;<BR>

10 <BR>

11 print &quot;\n -- LIST PORTFOLIO --&quot;;<BR>

12 <BR>

13 $port-&gt;Invest::restorePortfolio(&quot;myStocks&quot;);<BR>

14 $port-&gt;Invest::showPortfolio();</FONT></TT>

</BLOCKQUOTE>

<HR>

<H2><A NAME="MultipleDBMFiles"><FONT SIZE=5 COLOR=#FF0000>Multiple

DBM Files</FONT></A></H2>

<P>

There are occasions when you'll want to have more than one file

open for DBM access. You can use a unique stock ticker symbol

as the index into several hashes, each of which is then mapped

to its own DBM file. For example, the following database code

could be used to track stock price information in one DBM file

and earnings information in another DBM file. Both DBM files will

be indexed via the stock symbol name. Results of analyzing data

from both DBM files could be printed using code similar to the

following snippet: 

<BLOCKQUOTE>

<TT><FONT FACE="Courier">foreach $symbol (@listOfsymbols) {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;dbmopen(%earnings,$symbol,0666);<BR>

&nbsp;&nbsp;&nbsp;&nbsp;dbmopen(%prices,$symbol,0666);<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;@results = analyzeEarnings(\%earnings,\%prices);

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;printResults(\@results);<BR>

<BR>

&nbsp;&nbsp;&nbsp;&nbsp;dbmclose(%prices);<BR>

&nbsp;&nbsp;&nbsp;&nbsp;dbmclose(%earnings);<BR>

&nbsp;&nbsp;&nbsp;&nbsp;}</FONT></TT>

</BLOCKQUOTE>

<H2><A NAME="TheCatchwithDBMUtilities"><FONT SIZE=5 COLOR=#FF0000>The

Catch with DBM Utilities</FONT></A></H2>

<P>

So far I have only covered the standard DBM utilities that come

with Perl distribution. For most casual users, these DBM files

will be sufficient for their database needs. Unfortunately, when

things get complicated, as in the case of relational databases,

you might want to reconsider your options with other database

solutions. The price tag for DBM utilities is attractive because

they're free. However, you just might want to pay someone to acquire

a commercial Relational Database Management System (RDBMS).

<P>

Second, there is an inherent danger in using DBM utilities that

I must warn you about. If you make a mistake in working with your

mapped hash and somehow write it to disk with a <TT><FONT FACE="Courier">dbmclose()</FONT></TT>,

guess what? You just wiped out your entire database. This type

of faux pas is not hard to do, especially if you are modifying

data. Obliteration of your DBM database is generally only recoverable

from backup.

<P>

Commercial databases have a &quot;safer&quot; feel because they

provide you with a safety net by keeping alternate backups. You

are still your own worst enemy, but it's a little bit harder to

destroy all data. In any event, <I>always</I> back up your data.

<P>

If you do decide to use a database management system (DBMS) other

than the DBM utilities, all is not lost. You can use RDB (a freeware

relational database) or other Perl front-ends to popular databases.

All of the front packages allow your Perl programs to talk to

different databases via the protocol used by a DBI package.

<P>

Listing 18.8 presents the final version of the <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

file after all the modifications discussed up to now in this chapter

have been made to it. 

<HR>

<BLOCKQUOTE>

<B>Listing 18.8. The final version of </B><TT><B><FONT FACE="Courier">Invest.pm</FONT></B></TT><B>

with DBM support.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;&nbsp;1<BR>

&nbsp;&nbsp;2 package Invest;<BR>

&nbsp;&nbsp;3<BR>

&nbsp;&nbsp;4 push (@Inc,'pwd');<BR>

&nbsp;&nbsp;5 require Exporter;<BR>

&nbsp;&nbsp;6 require Invest::Stock;<BR>

&nbsp;&nbsp;7 require Invest::Fund;<BR>

&nbsp;&nbsp;8 require AnyDBM_File;<BR>

&nbsp;&nbsp;9 @ISA = (Exporter);<BR>

&nbsp;10<BR>

&nbsp;11 =head1 NAME<BR>

&nbsp;12<BR>

&nbsp;13 Invest - Sample module to simulate Bond behaviour<BR>

&nbsp;14<BR>

&nbsp;15 =head1 SYNOPSIS<BR>

&nbsp;16<BR>

&nbsp;17&nbsp;&nbsp;&nbsp;&nbsp; use Invest;<BR>

&nbsp;18&nbsp;&nbsp;&nbsp;&nbsp; use Invest::Fund;<BR>

&nbsp;19&nbsp;&nbsp;&nbsp;&nbsp; use Invest::Stock;<BR>

&nbsp;20<BR>

&nbsp;21&nbsp;&nbsp;&nbsp;&nbsp; $port = new Invest::new();<BR>

&nbsp;22<BR>

&nbsp;23&nbsp;&nbsp;&nbsp;&nbsp; $i1 = Invest::Fund('symbol' =&gt;

'twcux');&nbsp;&nbsp;&nbsp;&nbsp; <BR>

⌨️ 快捷键说明

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