第17章 java项目.docx
《第17章 java项目.docx》由会员分享,可在线阅读,更多相关《第17章 java项目.docx(55页珍藏版)》请在冰豆网上搜索。
第17章java项目
本教程由yyc,spirit整理清风小木虫美化
-----------------------清风小木虫精彩无极限--------------------------
第17章项目
本章包含了一系列项目,它们都以本书介绍的内容为基础,并对早期的章节进行了一定程度的扩充。
与以前经历过的项目相比,这儿的大多数项目都明显要复杂得多,它们充分演示了新技术以及类库的运用。
17.1文字处理
如果您有C或C++的经验,那么最开始可能会对Java控制文本的能力感到怀疑。
事实上,我们最害怕的就是速度特别慢,这可能妨碍我们创造能力的发挥。
然而,Java对应的工具(特别是String类)具有很强的功能,就象本节的例子展示的那样(而且性能也有一定程度的提升)。
正如大家即将看到的那样,建立这些例子的目的都是为了解决本书编制过程中遇到的一些问题。
但是,它们的能力并非仅止于此。
通过简单的改造,即可让它们在其他场合大显身手。
除此以外,它们还揭示出了本书以前没有强调过的一项Java特性。
17.1.1提取代码列表
对于本书每一个完整的代码列表(不是代码段),大家无疑会注意到它们都用特殊的注释记号起始与结束('//:
'和'///:
~')。
之所以要包括这种标志信息,是为了能将代码从本书自动提取到兼容的源码文件中。
在我的前一本书里,我设计了一个系统,可将测试过的代码文件自动合并到书中。
但对于这本书,我发现一种更简便的做法是一旦通过了最初的测试,就把代码粘贴到书中。
而且由于很难第一次就编译通过,所以我在书的内部编辑代码。
但如何提取并测试代码呢?
这个程序就是关键。
如果你打算解决一个文字处理的问题,那么它也很有利用价值。
该例也演示了String类的许多特性。
我首先将整本书都以ASCII文本格式保存成一个独立的文件。
CodePackager程序有两种运行模式(在usageString有相应的描述):
如果使用-p标志,程序就会检查一个包含了ASCII文本(即本书的内容)的一个输入文件。
它会遍历这个文件,按照注释记号提取出代码,并用位于第一行的文件名来决定创建文件使用什么名字。
除此以外,在需要将文件置入一个特殊目录的时候,它还会检查package语句(根据由package语句指定的路径选择)。
但这样还不够。
程序还要对包(package)名进行跟踪,从而监视章内发生的变化。
由于每一章使用的所有包都以c02,c03,c04等等起头,用于标记它们所属的是哪一章(除那些以com起头的以外,它们在对不同的章进行跟踪的时候会被忽略)——只要每一章的第一个代码列表包含了一个package,所以CodePackager程序能知道每一章发生的变化,并将后续的文件放到新的子目录里。
每个文件提取出来时,都会置入一个SourceCodeFile对象,随后再将那个对象置入一个集合(后面还会详尽讲述这个过程)。
这些SourceCodeFile对象可以简单地保存在文件中,那正是本项目的第二个用途。
如果直接调用CodePackager,不添加-p标志,它就会将一个“打包”文件作为输入。
那个文件随后会被提取(释放)进入单独的文件。
所以-p标志的意思就是提取出来的文件已被“打包”(packed)进入这个单一的文件。
但为什么还要如此麻烦地使用打包文件呢?
这是由于不同的计算机平台用不同的方式在文件里保存文本信息。
其中最大的问题是换行字符的表示方法;当然,还有可能存在另一些问题。
然而,Java有一种特殊类型的IO数据流——DataOutputStream——它可以保证“无论数据来自何种机器,只要使用一个DataInputStream收取这些数据,就可用本机正确的格式保存它们”。
也就是说,Java负责控制与不同平台有关的所有细节,而这正是Java最具魅力的一点。
所以-p标志能将所有东西都保存到单一的文件里,并采用通用的格式。
用户可从Web下载这个文件以及Java程序,然后对这个文件运行CodePackager,同时不指定-p标志,文件便会释放到系统中正确的场所(亦可指定另一个子目录;否则就在当前目录创建子目录)。
为确保不会留下与特定平台有关的格式,凡是需要描述一个文件或路径的时候,我们就使用File对象。
除此以外,还有一项特别的安全措施:
在每个子目录里都放入一个空文件;那个文件的名字指出在那个子目录里应找到多少个文件。
下面是完整的代码,后面会对它进行详细的说明:
//:
CodePackager.java
//"Packs"and"unpacks"thecodein"Thinking
//inJava"forcross-platformdistribution.
/*CommentedsoCodePackagerseesitandstarts
anewchapterdirectory,butsoyoudon't
havetoworryaboutthedirectorywherethis
programlives:
packagec17;
*/
importjava.util.*;
importjava.io.*;
classPr{
staticvoiderror(Stringe){
System.err.println("ERROR:
"+e);
System.exit
(1);
}
}
classIO{
staticBufferedReaderdisOpen(Filef){
BufferedReaderin=null;
try{
in=newBufferedReader(
newFileReader(f));
}catch(IOExceptione){
Pr.error("couldnotopen"+f);
}
returnin;
}
staticBufferedReaderdisOpen(Stringfname){
returndisOpen(newFile(fname));
}
staticDataOutputStreamdosOpen(Filef){
DataOutputStreamin=null;
try{
in=newDataOutputStream(
newBufferedOutputStream(
newFileOutputStream(f)));
}catch(IOExceptione){
Pr.error("couldnotopen"+f);
}
returnin;
}
staticDataOutputStreamdosOpen(Stringfname){
returndosOpen(newFile(fname));
}
staticPrintWriterpsOpen(Filef){
PrintWriterin=null;
try{
in=newPrintWriter(
newBufferedWriter(
newFileWriter(f)));
}catch(IOExceptione){
Pr.error("couldnotopen"+f);
}
returnin;
}
staticPrintWriterpsOpen(Stringfname){
returnpsOpen(newFile(fname));
}
staticvoidclose(Writeros){
try{
os.close();
}catch(IOExceptione){
Pr.error("closing"+os);
}
}
staticvoidclose(DataOutputStreamos){
try{
os.close();
}catch(IOExceptione){
Pr.error("closing"+os);
}
}
staticvoidclose(Readeros){
try{
os.close();
}catch(IOExceptione){
Pr.error("closing"+os);
}
}
}
classSourceCodeFile{
publicstaticfinalString
startMarker="//:
",//Startofsourcefile
endMarker="}///:
~",//Endofsource
endMarker2="};///:
~",//C++fileend
beginContinue="}///:
Continued",
endContinue="///:
Continuing",
packMarker="###",//Packedfileheadertag
eol=//Lineseparatoroncurrentsystem
System.getProperty("line.separator"),
filesep=//System'sfilepathseparator
System.getProperty("file.separator");
publicstaticStringcopyright="";
static{
try{
BufferedReadercr=
newBufferedReader(
newFileReader("Copyright.txt"));
Stringcrin;
while((crin=cr.readLine())!
=null)
copyright+=crin+"\n";
cr.close();
}catch(Exceptione){
copyright="";
}
}
privateStringfilename,dirname,
contents=newString();
privatestaticStringchapter="c02";
//Thefilenameseparatorfromtheoldsystem:
publicstaticStringoldsep;
publicStringtoString(){
returndirname+filesep+filename;
}
//Constructorforparsingfromdocumentfile:
publicSourceCodeFile(StringfirstLine,
BufferedReaderin){
dirname=chapter;
//Skippastmarker:
filename=firstLine.substring(
startMarker.length()).trim();
//Findspacethatterminatesfilename:
if(filename.indexOf('')!
=-1)
filename=filename.substring(
0,filename.indexOf(''));
System.out.println("found:
"+filename);
contents=firstLine+eol;
if(copyright.length()!
=0)
contents+=copyright+eol;
Strings;
booleanfoundEndMarker=false;
try{
while((s=in.readLine())!
=null){
if(s.startsWith(startMarker))
Pr.error("Noendoffilemarkerfor"+
filename);
//Forthisprogram,nospacesbefore
//the"package"keywordareallowed
//intheinputsourcecode:
elseif(s.startsWith("package")){
//Extractpackagename:
Stringpdir=s.substring(
s.indexOf('')).trim();
pdir=pdir.substring(
0,pdir.indexOf(';')).trim();
//Capturethechapterfromthepackage
//ignoringthe'com'subdirectories:
if(!
pdir.startsWith("com")){
intfirstDot=pdir.indexOf('.');
if(firstDot!
=-1)
chapter=
pdir.substring(0,firstDot);
else
chapter=pdir;
}
//Convertpackagenametopathname:
pdir=pdir.replace(
'.',filesep.charAt(0));
System.out.println("package"+pdir);
dirname=pdir;
}
contents+=s+eol;
//Movepastcontinuations:
if(s.startsWith(beginContinue))
while((s=in.readLine())!
=null)
if(s.startsWith(endContinue)){
contents+=s+eol;
break;
}
//Watchforendofcodelisting:
if(s.startsWith(endMarker)||
s.startsWith(endMarker2)){
foundEndMarker=true;
break;
}
}
if(!
foundEndMarker)
Pr.error(
"EndmarkernotfoundbeforeEOF");
System.out.println("Chapter:
"+chapter);
}catch(IOExceptione){
Pr.error("Errorreadingline");
}
}
//Forrecoveringfromapackedfile:
publicSourceCodeFile(BufferedReaderpFile){
try{
Strings=pFile.readLine();
if(s==null)return;
if(!
s.startsWith(packMarker))
Pr.error("Can'tfind"+packMarker
+"in"+s);
s=s.substring(
packMarker.length()).trim();
dirname=s.substring(0,s.indexOf('#'));
filename=s.substring(s.indexOf('#')+1);
dirname=dirname.replace(
oldsep.charAt(0),filesep.charAt(0));
filename=filename.replace(
oldsep.charAt(0),filesep.charAt(0));
System.out.println("listing:
"+dirname
+filesep+filename);
while((s=pFile.readLine())!
=null){
//Watchforendofcodelisting:
if(s.startsWith(endMarker)||
s.startsWith(endMarker2)){
contents+=s;
break;
}
contents+=s+eol;
}
}catch(IOExceptione){
System.err.println("Errorreadingline");
}
}
publicbooleanhasFile(){
returnfilename!
=null;
}
publicStringdirectory(){returndirname;}
publicStringfilename(){returnfilename;}
publicStringcontents(){returncontents;}
//Towritetoapackedfile:
publicvoidwritePacked(DataOutputStreamout){
try{
out.writeBytes(
packMarker+dirname+"#"
+filename+eol);
out.writeBytes(contents);
}catch(IOExceptione){
Pr.error("writing"+dirname+
filesep+filename);
}
}
//Togeneratetheactualfile:
publicvoidwriteFile(Stringrootpath){
Filepath=newFile(rootpath,dirname);
path.mkdirs();
PrintWriterp=
IO.psOpen(newFile(path,filename));
p.print(contents);
IO.close(p);
}
}
classDirMap{
privateHashtablet=newHashtable();
privateStringrootpath;
DirMap(){
rootpath=System.getProperty("user.dir");
}
DirMap(StringalternateDir){
rootpath=alternateDir;
}
publicvoidadd(SourceCodeFilef){
Stringpath=f.directory();
if(!
t.containsKey(path))
t.put(path,newVector());
((Vector)t.get(path)).addElement(f);
}
publicvoidwritePackedFile(Stringfname){
DataOutputStreampacked=IO.dosOpen(fname);
try{
packed.writeBytes("###OldSeparator:
"+
SourceCodeFile.filesep+"###\n");
}catch(IOExceptione){
Pr.error("Writingseparatorto"+fname);
}
Enumeratione=t.keys();
while(e.hasMoreElements()){
Stringdir=(String)e.nextElement();
System.out.println(
"Writingdirectory"+dir);
Vectorv=(Vector)t.get(dir);
for(inti=0;iSourceCodeFilef=
(SourceCodeFile)v.elementAt(i);
f.writePacked(packed);
}
}
IO.close(packed);
}
//Writeallthefilesintheirdirectories:
publicvoidwrite(){
Enumeratione=t.keys();
while(e.hasMoreElements()){
Stringdir=(String)e.nextElement();
Vectorv=(Vector)t.get(dir);
for(inti=0;iSourceCodeFilef=
(SourceCodeFile)v.elementAt(i);
f.writeFile(rootpath);
}
//Addfileindicatingfilequantity
//writtentothisdirectoryasacheck:
IO.close(IO.dosOpen(
newFile(newFile(rootpath,dir),
Integer.toString(v.size())+".files")));
}
}
}
publicclassCodePackager{
privatestaticfinalStringusageString=
"usage:
javaCodePackagerpackedFileName"+
"\nExtractssourcecodefilesfrompacked\n"+
"versionofTjava.docsourcesinto"+
"directoriesoffcurrentdirectory\n"+
"javaCodePackagerpackedFileNamenewDir\n"+
"ExtractsintodirectoriesoffnewDir\n"+
"javaCodePackager-psource.txtpackedFile"+
"\n