📄 ch18.htm
字号:
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>, "Object-Oriented
Programming in Perl") 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>
$a = "$key:" . $val->{'type'}
. ":" .<BR>
$val->{'symbol'} . ":" .
$val->{'shares'};<BR>
$dummy{$key} = $a;<BR>
# Debug: print "\n Writing $dummy{$key}";
<BR>
}<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>
$a = $dummy{$key};<BR>
($ndx,$sec,$sym,$shr) = split(':',$a);
<BR>
# print "Read back $ndx,$sec,$sym,$shr
\n";<BR>
if ($sec eq 'Fund')<BR>
{<BR>
$i1 = Invest::Fund::new('Invest::Fund',
<BR>
'symbol'
=> "$sym", 'shares' => "$shr");<BR>
}<BR>
else<BR>
{<BR>
$i1 = Invest::Stock::new('Invest::Stock',
<BR>
'symbol'
=> "$sym", 'shares' =>"$shr");<BR>
}<BR>
$this->Invest::AddItem($i1);
<BR>
$this->Invest::showPortfolio;
<BR>
}<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"> 1 #!/usr/bin/perl<BR>
2 <BR>
3 push(@Inc,'pwd');<BR>
4 <BR>
5 use Invest;<BR>
6 # use Invest::Fund;<BR>
7 use Invest::Stock;<BR>
8 <BR>
9 #<BR>
10 # Create a new portfolio object<BR>
11 #<BR>
12 $port = new Invest;<BR>
13 <BR>
14 print "\n -- CREATE PORTFOLIO --";<BR>
15 $s1 = new Invest::Stock('symbol' => 'AMAT', 'shares' =>
'400');<BR>
16 $s2 = new Invest::Stock('symbol' => 'INTC', 'shares' =>
'200');<BR>
17 <BR>
18 print "\n Adding stocks ";<BR>
19 $port->Invest::AddItem($s1);<BR>
20 $port->Invest::AddItem($s2);<BR>
21 <BR>
22 $port->Invest::showPortfolio();<BR>
23 <BR>
24 #<BR>
25 # SAVE THE DATA HERE in the DBM file called
myStocks<BR>
26 #<BR>
27 $port->Invest::savePortfolio("myStocks");</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"> 1 #!/usr/bin/perl<BR>
2 <BR>
3 push(@Inc,'pwd');<BR>
4 <BR>
5 use Invest;<BR>
6 use Invest::Fund;<BR>
7 use Invest::Stock;<BR>
8 <BR>
9 $port = new Invest;<BR>
10 <BR>
11 print "\n -- LIST PORTFOLIO --";<BR>
12 <BR>
13 $port->Invest::restorePortfolio("myStocks");<BR>
14 $port->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>
dbmopen(%earnings,$symbol,0666);<BR>
dbmopen(%prices,$symbol,0666);<BR>
<BR>
@results = analyzeEarnings(\%earnings,\%prices);
<BR>
printResults(\@results);<BR>
<BR>
dbmclose(%prices);<BR>
dbmclose(%earnings);<BR>
}</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 "safer" 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"> 1<BR>
2 package Invest;<BR>
3<BR>
4 push (@Inc,'pwd');<BR>
5 require Exporter;<BR>
6 require Invest::Stock;<BR>
7 require Invest::Fund;<BR>
8 require AnyDBM_File;<BR>
9 @ISA = (Exporter);<BR>
10<BR>
11 =head1 NAME<BR>
12<BR>
13 Invest - Sample module to simulate Bond behaviour<BR>
14<BR>
15 =head1 SYNOPSIS<BR>
16<BR>
17 use Invest;<BR>
18 use Invest::Fund;<BR>
19 use Invest::Stock;<BR>
20<BR>
21 $port = new Invest::new();<BR>
22<BR>
23 $i1 = Invest::Fund('symbol' =>
'twcux'); <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -