1、第17章 java项目本教程由yyc,spirit整理 清风小木虫美化- 清风小木虫 精彩无极限 - 第17章 项目本章包含了一系列项目,它们都以本书介绍的内容为基础,并对早期的章节进行了一定程度的扩充。与以前经历过的项目相比,这儿的大多数项目都明显要复杂得多,它们充分演示了新技术以及类库的运用。17.1 文字处理如果您有C或C+的经验,那么最开始可能会对Java控制文本的能力感到怀疑。事实上,我们最害怕的就是速度特别慢,这可能妨碍我们创造能力的发挥。然而,Java对应的工具(特别是String类)具有很强的功能,就象本节的例子展示的那样(而且性能也有一定程度的提升)。正如大家即将看到的那样,
2、建立这些例子的目的都是为了解决本书编制过程中遇到的一些问题。但是,它们的能力并非仅止于此。通过简单的改造,即可让它们在其他场合大显身手。除此以外,它们还揭示出了本书以前没有强调过的一项Java特性。17.1.1 提取代码列表对于本书每一个完整的代码列表(不是代码段),大家无疑会注意到它们都用特殊的注释记号起始与结束(/:和/:)。之所以要包括这种标志信息,是为了能将代码从本书自动提取到兼容的源码文件中。在我的前一本书里,我设计了一个系统,可将测试过的代码文件自动合并到书中。但对于这本书,我发现一种更简便的做法是一旦通过了最初的测试,就把代码粘贴到书中。而且由于很难第一次就编译通过,所以我在书的
3、内部编辑代码。但如何提取并测试代码呢?这个程序就是关键。如果你打算解决一个文字处理的问题,那么它也很有利用价值。该例也演示了String类的许多特性。我首先将整本书都以ASCII文本格式保存成一个独立的文件。CodePackager程序有两种运行模式(在usageString有相应的描述):如果使用-p标志,程序就会检查一个包含了ASCII文本(即本书的内容)的一个输入文件。它会遍历这个文件,按照注释记号提取出代码,并用位于第一行的文件名来决定创建文件使用什么名字。除此以外,在需要将文件置入一个特殊目录的时候,它还会检查package语句(根据由package语句指定的路径选择)。但这样还不够
4、。程序还要对包(package)名进行跟踪,从而监视章内发生的变化。由于每一章使用的所有包都以c02,c03,c04等等起头,用于标记它们所属的是哪一章(除那些以com起头的以外,它们在对不同的章进行跟踪的时候会被忽略)只要每一章的第一个代码列表包含了一个package,所以CodePackager程序能知道每一章发生的变化,并将后续的文件放到新的子目录里。每个文件提取出来时,都会置入一个SourceCodeFile对象,随后再将那个对象置入一个集合(后面还会详尽讲述这个过程)。这些SourceCodeFile对象可以简单地保存在文件中,那正是本项目的第二个用途。如果直接调用CodePacka
5、ger,不添加-p标志,它就会将一个“打包”文件作为输入。那个文件随后会被提取(释放)进入单独的文件。所以-p标志的意思就是提取出来的文件已被“打包”(packed)进入这个单一的文件。但为什么还要如此麻烦地使用打包文件呢?这是由于不同的计算机平台用不同的方式在文件里保存文本信息。其中最大的问题是换行字符的表示方法;当然,还有可能存在另一些问题。然而,Java有一种特殊类型的IO数据流DataOutputStream它可以保证“无论数据来自何种机器,只要使用一个DataInputStream收取这些数据,就可用本机正确的格式保存它们”。也就是说,Java负责控制与不同平台有关的所有细节,而这正
6、是Java最具魅力的一点。所以-p标志能将所有东西都保存到单一的文件里,并采用通用的格式。用户可从Web下载这个文件以及Java程序,然后对这个文件运行CodePackager,同时不指定-p标志,文件便会释放到系统中正确的场所(亦可指定另一个子目录;否则就在当前目录创建子目录)。为确保不会留下与特定平台有关的格式,凡是需要描述一个文件或路径的时候,我们就使用File对象。除此以外,还有一项特别的安全措施:在每个子目录里都放入一个空文件;那个文件的名字指出在那个子目录里应找到多少个文件。下面是完整的代码,后面会对它进行详细的说明:/: CodePackager.java/ Packs and
7、unpacks the code in Thinking / in Java for cross-platform distribution./* Commented so CodePackager sees it and starts a new chapter directory, but so you dont have to worry about the directory where this program lives:package c17;*/import java.util.*;import java.io.*;class Pr static void error(Stri
8、ng e) System.err.println(ERROR: + e); System.exit(1); class IO static BufferedReader disOpen(File f) BufferedReader in = null; try in = new BufferedReader( new FileReader(f); catch(IOException e) Pr.error(could not open + f); return in; static BufferedReader disOpen(String fname) return disOpen(new
9、File(fname); static DataOutputStream dosOpen(File f) DataOutputStream in = null; try in = new DataOutputStream( new BufferedOutputStream( new FileOutputStream(f); catch(IOException e) Pr.error(could not open + f); return in; static DataOutputStream dosOpen(String fname) return dosOpen(new File(fname
10、); static PrintWriter psOpen(File f) PrintWriter in = null; try in = new PrintWriter( new BufferedWriter( new FileWriter(f); catch(IOException e) Pr.error(could not open + f); return in; static PrintWriter psOpen(String fname) return psOpen(new File(fname); static void close(Writer os) try os.close(
11、); catch(IOException e) Pr.error(closing + os); static void close(DataOutputStream os) try os.close(); catch(IOException e) Pr.error(closing + os); static void close(Reader os) try os.close(); catch(IOException e) Pr.error(closing + os); class SourceCodeFile public static final String startMarker =
12、/:, / Start of source file endMarker = /:, / End of source endMarker2 = ; /:, / C+ file end beginContinue = /:Continued, endContinue = /:Continuing, packMarker = #, / Packed file header tag eol = / Line separator on current system System.getProperty(line.separator), filesep = / Systems file path sep
13、arator System.getProperty(file.separator); public static String copyright = ; static try BufferedReader cr = new BufferedReader( new FileReader(Copyright.txt); String crin; while(crin = cr.readLine() != null) copyright += crin + n; cr.close(); catch(Exception e) copyright = ; private String filename
14、, dirname, contents = new String(); private static String chapter = c02; / The file name separator from the old system: public static String oldsep; public String toString() return dirname + filesep + filename; / Constructor for parsing from document file: public SourceCodeFile(String firstLine, Buf
15、feredReader in) dirname = chapter; / Skip past marker: filename = firstLine.substring( startMarker.length().trim(); / Find space that terminates file name: if(filename.indexOf( ) != -1) filename = filename.substring( 0, filename.indexOf( ); System.out.println(found: + filename); contents = firstLine
16、 + eol; if(copyright.length() != 0) contents += copyright + eol; String s; boolean foundEndMarker = false; try while(s = in.readLine() != null) if(s.startsWith(startMarker) Pr.error(No end of file marker for + filename); / For this program, no spaces before / the package keyword are allowed / in the
17、 input source code: else if(s.startsWith(package) / Extract package name: String pdir = s.substring( s.indexOf( ).trim(); pdir = pdir.substring( 0, pdir.indexOf(;).trim(); / Capture the chapter from the package / ignoring the com subdirectories: if(!pdir.startsWith(com) int firstDot = pdir.indexOf(.
18、); if(firstDot != -1) chapter = pdir.substring(0,firstDot); else chapter = pdir; / Convert package name to path name: pdir = pdir.replace( ., filesep.charAt(0); System.out.println(package + pdir); dirname = pdir; contents += s + eol; / Move past continuations: if(s.startsWith(beginContinue) while(s
19、= in.readLine() != null) if(s.startsWith(endContinue) contents += s + eol; break; / Watch for end of code listing: if(s.startsWith(endMarker) | s.startsWith(endMarker2) foundEndMarker = true; break; if(!foundEndMarker) Pr.error( End marker not found before EOF); System.out.println(Chapter: + chapter
20、); catch(IOException e) Pr.error(Error reading line); / For recovering from a packed file: public SourceCodeFile(BufferedReader pFile) try String s = pFile.readLine(); if(s = null) return; if(!s.startsWith(packMarker) Pr.error(Cant find + packMarker + in + s); s = s.substring( packMarker.length().tr
21、im(); 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.readLi
22、ne() != null) / Watch for end of code listing: if(s.startsWith(endMarker) | s.startsWith(endMarker2) contents += s; break; contents += s + eol; catch(IOException e) System.err.println(Error reading line); public boolean hasFile() return filename != null; public String directory() return dirname; pub
23、lic String filename() return filename; public String contents() return contents; / To write to a packed file: public void writePacked(DataOutputStream out) try out.writeBytes( packMarker + dirname + # + filename + eol); out.writeBytes(contents); catch(IOException e) Pr.error(writing + dirname + file
24、sep + filename); / To generate the actual file: public void writeFile(String rootpath) File path = new File(rootpath, dirname); path.mkdirs(); PrintWriter p = IO.psOpen(new File(path, filename); p.print(contents); IO.close(p); class DirMap private Hashtable t = new Hashtable(); private String rootpa
25、th; DirMap() rootpath = System.getProperty(user.dir); DirMap(String alternateDir) rootpath = alternateDir; public void add(SourceCodeFile f) String path = f.directory(); if(!t.containsKey(path) t.put(path, new Vector(); (Vector)t.get(path).addElement(f); public void writePackedFile(String fname) Dat
26、aOutputStream packed = IO.dosOpen(fname); try packed.writeBytes(#Old Separator: + SourceCodeFile.filesep + #n); catch(IOException e) Pr.error(Writing separator to + fname); Enumeration e = t.keys(); while(e.hasMoreElements() String dir = (String)e.nextElement(); System.out.println( Writing directory
27、 + dir); Vector v = (Vector)t.get(dir); for(int i = 0; i v.size(); i+) SourceCodeFile f = (SourceCodeFile)v.elementAt(i); f.writePacked(packed); IO.close(packed); / Write all the files in their directories: public void write() Enumeration e = t.keys(); while(e.hasMoreElements() String dir = (String)
28、e.nextElement(); Vector v = (Vector)t.get(dir); for(int i = 0; i v.size(); i+) SourceCodeFile f = (SourceCodeFile)v.elementAt(i); f.writeFile(rootpath); / Add file indicating file quantity / written to this directory as a check: IO.close(IO.dosOpen( new File(new File(rootpath, dir), Integer.toString
29、(v.size()+.files); public class CodePackager private static final String usageString = usage: java CodePackager packedFileName + nExtracts source code files from packed n + version of Tjava.doc sources into + directories off current directoryn + java CodePackager packedFileName newDirn + Extracts into directories off newDirn + java CodePackager -p source.txt packedFile + n
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1