您的位置:首页 > 编程语言 > Java开发

Think in Java(12)-IO

2005-04-13 07:36 826 查看
[align=center]A directory list[/align]//c12:DirList.java
//Displays directory listing using regular expressions, regular Expressions by DirFilter class.
//Implements the Interface FilenameFilter.
public interface FilenameFilter{
    public boolean accept(File dir, String name);
} File.list() can "call back" accept() to datermine which file names should be included in the list.
list() return String[] accept() uses a regular expression watcher object to see if the regular expression regex matches the name of the file.
boolean b=Pattern.matches(regex, sequense chars) equals
{
 Pattern p=Pattern.compile(regex);
 Matcher m=p.matcher(sequense char);
 boolean b=m.matchers();
} 匿名内部类的参数必须是final.
  [align=center]Input and Output[/align]InputStream    |    |---ByteArrayInputStream        Allows a buffer in memory to be used as an InputStream    |    |---StringBufferInputStream     Converts a String to InputStream    |    |---FileInputStream             Reading Information from a file    |    |---PipedInputStream            Produces the data that being written to the associated PipedOutputStream    |    |---SequenceInputStream         Coverts two or more InputStream object into a single InputStream    |    |___FilterInputStream           Abstract class OutputStream    |    |---ByteArrayOutputStream    Creates a buffer in memory call the data the you send the stream is placed in this buffer    |    |---FileOutputStream         For sending information to the file    |    |--PipedOutputStream         any information you write to this automatically ends up as input fro the associated PipedInputStream    |    |--FilterOutputStream        Abstract class that is an interface for characters that provide useful functionality to the other output   [align=center]Reader and Writer[/align][align=center] [/align]There are times when you must use classes form the 'byte' hierarchy in combination with classes in the 'character' hierarchy.  To accomplish this there are 'adapter' class: InputStreamReader and OutputStreamWriter. //c12:IoStreamDemo.java//Reading input by line(reading character files)BufferedReader bufferedReader=new BufferedReader(new FileReader(File file));    bufferedReader.readLine(); //Reading standard input(reading from byte stream to character stream)BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));    bufferedReader.readLine(); //Input from memory(reading character)StringReader stringReader=new StringBuffer(String str);    int c;    while((c=stringReader.read())!=-1)        System.out.print((char)c); //Formated menory input(reading bytes)DataInputStream dataInputStream=new DataInputStream(new ByteArrayInputStream(str.getBytes());    (char)dataInputStream.readByte(); //File outputPrintWriter printWriter=new PrintWriter(new BufferedWriter(new FileWriter(File file)));    printWriter.println(string);    printWriter.close(); //Storing and recovering data//storingDataOutputStream dataOutputStream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(File file)));    dataOutputStream.writeUTF(String str);    //UTF-8 representation of a Unicode character. String encoded in Java: ASCII in a single byte;non ASCII in two or three byte.//recoverDataInputStream dataInputStream=new DataInputStream(new BufferedInputStream(new FileInputStream(File file)));    dataInputStream.readUTF(); //Reading/Writing random access fileRandomAccessFile randomAccessFile=new RandomAccessFile(File file);//reading    randomAccessFile.readFloat(); etc.//writing    randomAccessFile.writeFloat(float v);//seek       randomAccessFile.seek(long position);  File reading & writing Utilities//static method for reading and writing text files as a single string, and treating a file as ArrayList//c12:TextFile.java  [align=center]Standard I/O[/align]One program's standard output can become the standard input for another program.System.in must be wrapped before you can read from it.//Change System.out to a PrintWriterPrintWriter printWriter=new PrintWriter(System.out, true);    printWriter.println(String str);//second parameter "true" in order to enable automatic flushing. Redirecting standard I/OSystem.setIn(InputStream)System.setOut(PrintStream)System.setErr(PrintStream)//c12:Redirecting.javaBufferedInputStream bufferedInputStream=new BufferedInputStream(new FileInputStream(File file));    System.setIn(bufferedInputStream);BufferedReader bufferdReader=new BufferedReader(new InputStreamReader(System.in));    bufferedReader.readLine();   [align=center]New I/O[/align]Three of the classes have been modified so that they produce a FileChannel:FileInputStream,FileOutputStream,RandomAccessFile.//FileInputStream,FileOutputStream,RandomAccessFile get FileChannelFileChannel fileChannel=new FileInputStream(File file).getChannel();    fileChannel.write(ByteBuffer[] src);FileChannel fileChannel=new FileOutputStream(File file).getChannel();FileChannel fileChannel=new RandomAccessFile(File,"rw").getChannel();for read-only access(FileInputStream), you must explicitly allocate a ByteBuffer, using the static allocate() method. //c12:ChannelCopy.javafileChannel.read(ByteBuffer buffer);buffer.flip();    //Flips this buffer. The limit is set to the current position and then the position is set to zero.out.write(buffer);buffer.clear(); //c12:TransferTo.javaFileChannel in=
4000
new FileInputStream(File file).getChannel();FileChannel out=new FileOutputStream(File file).getChannel();in.transferTo(0,in.size(),out);//orout.transferFrom(in,0,in.size());  Converting dataThe ByteBuffer contains plain bytes, java.nio.charset.Charset provides tools for encoding into many different type of character sets//c12:BufferToText.javaString encoding=System.getProperty("file.encoding");Charset charset=Charset.forName(encoding);ByteBuffer byteBuffer=charset.encode(String);CharBuffer charBuffer=charset.decode(byteBuffer); Although a ByteBuffer only holds bytes, it contains methods to produce each of different types of primitive values from the bytes it contains.//c12:GetData.javaByteBuffer bb=ByteBuffer.allocate(BSIZE);bb.asCharBuffer().put(String str);char c;while((c=bb.getChar())!=0){   ......  } View Buffers//c12:IntBufferDemo.java//Here's a example that manipulates int in a ByteBuffer via a IntBufferByteBuffer bb=ByteBuffer.allocate(BSIZE);IntBuffer ib=bb.asIntBuffer();ib.put(new int[]{ 11, 42, 47, 99, 143, 811, 1016});ib.put(3,1811);    //ib's position is 7ib.rewind();       //ib's position is 0while(ib.hasRemaining()){  ...... } Note that these absolute location accesses are available for primitive types by talking directly to a ByteBuffer, as well. //c12:ViewBuffers.java//interprets the same sequence of bytes as short,int float,long and double by producing different view buffers on the same ByteBuffer ByteBuffer bb=ByteBuffer.wrap(new byte[]{0,0,0,0,0,0,0,'a'});//Byte Buffer    while(bb.hasRemaining())        System.out.println(bb.position()+"->"+bb.get());//Char Buffer    CharBuffer cb=((ByteBuffer)bb.rewind()).asCharBuffer();    while(cb.hasRemaining())        System.out.println(cb.position()+"->"+cb.get());    ......//FloatBuffer,IntBuffer,LongBuffer,ShortBuffer,DoubleBuffer, etc.

EndiansDifferent machines may use different byte-ordering approaches to store data."Big endian" places the most significant byte in the lowest memory address, and "Little endian" places the most significant byte in the highest memory address.A ByteBuffer stores data in big endian form, and data sent over a network always uses big endian order. You can change the endian-ness of a ByteBuffer using order() with an argument of ByteOrder.BIG_ENDIAN or ByteOrder.LITTLE_ENDIAN. //c12:Endians.javaByteBuffer bb=ByteBuffer.wrap(new byte[12]);bb.asCharBuffer().put("abcdef");bb.rewind();bb.order(ByteOrder.BIG_ENDIAN);bb.rewind();bb.order(ByteOrder.LITTLE_ENDIAN); Data manipulation with buffersIf  you wish to write a byte array to a file, then you wrap the byte array using the ByteBuffer.wrap() method, open a channel on the FileOutputStream using the getChannel() method, and then write data into FileChannel form this ByteBuffer.

Note that ByteBuffer is the only way to move data in and out of channels, and that you can only create a standalone primitive-typed buffer, or get one from a ByteBuffer using an "as" method. That is, you cannot convert a primitive-typed buffer to a ByteBuffer. However, since you are able to move primitive data into and out of a ByteBuffer via a view buffer. Buffer detailsA Buffer consists of data and four indexes of access and manipulate this data efficiently:mark,position,limit and capacity.capacity()--returns the buffer's capacityclear()-----clears the buffer,sets the position to zero, and limit to capacity. You call this method to overwrite an existing buffer.flip()------sets limit to position and position to zero. This method is used to prepare the buffer for a read after data has been written into it.limit()-----returns the value of limitlimit(int lim)---sets the value of limitmark()------sets mark at positionposition----returns the value of positionposition(int pos)---sets the value of positionremaining()--returns(limit-position)hasRemaining()---returns true if there are any elements between position and limit Example uses a very simple algorithm to scramble and unscramble characters in a CharBuffer//c12:UsingBuffers.javaprivate static void symmetricScramble(CharBuffer buffer){    while(buffer.hasRemaining()){        buffer.mark();        char c1=buffer.get();        if(buffer.hasRemaining(){            char c2=buffer.get();            buffer.reset();            buffer.put(c2).put(c1);        }    }} Memory-mapped filesWith a memory-mapped file, you can pretend that entire file is in memory and that you can access it by simple treating it as a very large array.//c12:LargeMappedFiles.java//Creating a very large file using mapping.static int length=0x8FFFFFF;    //128MBMappedByteBuffer out=new RandomAccessFile("test.dat","rw").getChannel().map(FileChannel.MapMode.READ_WRITE,0,length);for(int i=0; i<length; i++)    out.put((byte)'x');Note that you must specify the starting point and the length of the region that you want to map in the file; this means that you have the option to map smaller regions of a large file.MappedByteBuffer is inherited from ByteBuffer, that has put(), get(),asCharBuffer() methods, etc.This way a very large file(up to 2GB)can easily be modified. PerformanceAlthough the performance of "old" stream I/O has been improved by implementing it with nio, mapped file asscess tends to be dramatically faster.//c12:MappedIO.java   File lockingFile locking, introduced in JDK1.4, allows you to synchronize access to a file as a shared resource.//c12:FileLocking.javaFileOutputStream fos=new FileOutputStream(File file);FileLock fl=fos.getChannel().tryLock();    //Locked fileif(fl!=null){    Thread.sleep(100);    fl.release();    //Releaseed Lock}fos.close(); You get a FileLock on the entire file by calling either tryLock() or lock() on a FileChannel. (SocketChannel, DatagramChannel, and ServerSocketChannel do not need locking since they are inherently single-process entities; you don't generally share a network socket between two processes.)tryLock()is non-blocking. It tries to grab the lock, but if it cannot, it simply returns from the method call.lock() blocks until the lock is acquired, or the thread that invoked lock() is interrupted, or the channel on which the lock() method is called is closed.A lock is released using FileLock.release().It is also possible to lock a part of the file by using        tryLock(long position, long size, boolean shared) or lock(long position, long size, boolean shared)The zero-argument locking methods lock the entire file, even if it grows.  Locking portions of a mapped file//c12:LockingMappedFiles.javaThe LockAndModify thread class sets up the buffer region and creates a slice() to be modified, and in run(), the lock is acquired on the file channel.  Compression
Compression classFunction
CheckedInputStreamGetCheckSum() produces checksum for any InputStream(not just decompression).
CheckedOutputStreamGetCheckSum() produces checksum for any OutputStream(not just decompression).
DeflaterOutputStreamBase class for compression classes.
ZipOutputStreamA DeflaterOutputStream that compresses data into the ZIP file format.
GZIPOutputStreamA DeflaterOutputStream that compresses data into the GZIP file format.
InflaterInputStreamAn InflaterInputStream that decompresses data that has been storedin the Zip file format.
ZipInputStreamAn InflaterInputStream that decompresses data that has been storedin the Zip file format.
GZIPInputStreamAn InflaterInputStream that decompresses data that has been storedin the GZIP file format.
 These classes are derived form InputStream and OutputStream. This is because the compression library works with bytes, not characters. However, you might sometimes be forced to mix the two types of streams.(Remember InputStreamReader and OutputStreamWriter) Simple compression with GZIP//c12:GZIPcompress.java//Args:GZIPcompress.java//clean:test.gzBufferedReader in=new BufferedReader(new FileReader(File file));BufferedOutputStream out=new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(File file)));int c;while((c=in.read())!=-1)    out.write(c);in.close();out.close();//Read from GZIPInputStreamBufferedReader reader=new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(File file))));String s;while((s=reader.readLine())!=null)    System.out.println(s);reader.close(); Multifile storage with Zip//c12:ZipCompress.javaFileOutputStream f = new FileOutputStream("test.zip");
  CheckedOutputStream csum =new CheckedOutputStream(f, new Adler32());
    ZipOutputStream zos = new ZipOutputStream(csum);
     BufferedOutputStream out =new BufferedOutputStream(zos);
    zos.setComment("A test of Java Zipping");
    for(int i = 0; i < args.length; i++) {
      System.out.println("Writing file " + args);
      BufferedReader in =
        new BufferedReader(new FileReader(args[i]));
      zos.putNextEntry(new ZipEntry(args[i]));
      int c;
      while((c = in.read()) != -1)
        out.write(c);
      in.close();
    }
    out.close();
    // Checksum valid only after the file has been closed!
    System.out.println("Checksum: " + csum.getChecksum().getValue());    FileInputStream fi = new FileInputStream("test.zip");
    CheckedInputStream csumi =new CheckedInputStream(fi, new Adler32());
    ZipInputStream in2 = new ZipInputStream(csumi);
    BufferedInputStream bis = new BufferedInputStream(in2);
    ZipEntry ze;
    while((ze = in2.getNextEntry()) != null) {
      System.out.println("Reading file " + ze);
      int x;
      while((x = bis.read()) != -1)
        System.out.write(x);
    }
    System.out.println("Checksum: " + csumi.getChecksum().getValue());
    bis.close();
    // Alternative way to open and read zip files:
    ZipFile zf = new ZipFile("test.zip");
    Enumeration e = zf.entries();
    while(e.hasMoreElements()) {
      ZipEntry ze2 = (ZipEntry)e.nextElement();
      System.out.println("File: " + ze2);
      // ... and extract the data as before
    }
Java ARchives (JARs) Each of these files was uncompressed. By combining all of the files for a particular applet into a single JAR file, only one server request is necessary and the transfer is faster because of compression. And each entry in a JAR file can be digitally signed for security(See Chapter 14 for an Example of signing).A JAR file consists of a single file containing a collection of zipped files along with a "manifest" that describes them.(You can create your own manifest file; otherwise, the jar program will do it for you.) jar [options] destination [manifest] inputfile(s)
c
Creates a new or empty archive.
t
Lists the table of contents.
x
Extracts all files.
x file
Extracts the named file.
f
Says: “I’m going to give you the name of the file.” If you don’t use this, jar assumes that its input will come from standard input, or, if it is creating a file, its output will go to standard output.
m
Says that the first argument will be the name of the user-created manifest file.
v
Generates verbose output describing what jar is doing.
0
Only store the files; doesn’t compress the files (use to create a JAR file that you can put in your classpath).
M
Don’t automatically create a manifest file.
 Examples:    jar cf myJarFile.jar *.classThis creates a JAR file called myJarFile.jar that contains all of the class files in the current directory, along with an automatically generated manifest file.    jar cmf myJarFile.jar myManifestfile.mf *.classLike the previous example, but adding a user-created manifest file called myManifestFile.mf.    jar tf myJarFile.jarProduces a table of contents of the files in myJarFile.jar    jar tvf myJarFile.jarAdds the "verbose" flag to give more detailed information about the files in myJarFile.jar. If you create a JAR file using the zero option, that file can be placed in your CLASSPATH:    CLASSPATH="lib1.jar;lib2.jar;"Then Java can search lib1.jar and lib2.jar for class files.  [align=center]Object serialization[/align] Java's object serialization allows you to take any object that implements the Serializable interface and turn it into a sequence of bytes that can later be fully restored to regenerate the original object. This is even true across a netowrk, which means that the serialization mechanism automatically compensates for deifferences in operating systems. That is, you can create an object on a Windows machine, serialize it, and send it across the network to a Unix machine, where it will be correctly reconstructed. You don't have to worry about the data representations on the different machines, the byte ordering, or any other details.Remember that persistence means that an object's lifetime is not determined by whether a program is executing; the object lives in between invocations of the program.Object serialization is called "lightweight" is that you can't simply define an object using some kind of "prersistent" keyword and let the system take care of the details(although this might happen in the future). Instead, you must explicitly serialize and deserialize the objects in your program. If you need a more serious persistence mechanism, consider Java Data Object(JDO) or a tool like Hibernate(http://hibernate.sourceforge.net). For details, see Thinking in Enterprise Java, downloadable form www.BruceEckel.comObject serialization was added to the language to support two major features:Java's Remote Method Invocation(RMI); JavaBeans. RMI allows objects that live on other machines to behave as if they live on your machine. When sending messages to remote objects, object serialization is necessary to transport the arguments and return values. RMI is discussed in Thinking in Enterprise Java. JavaBeans described in Chapter 14, when a Bean is used, its state information is generally configured at design time. This state information must be stored and later recovered when the program is started; object serialization performs this task. Serializing an object is quite simple as long as the object implements the Serializable interface(this is a tagging interface and has no methods). When serialization was added to the language, many standard library classes were changed to make them serializable, including all of the wrappers for the primitive types, all of the container classes, and many others. Even Class object can be serialized. //c12:Worm.javaTo make things interesting, the array of Data objects inside Worm are initialized with random numbers.(This way you don't suspect the compiler of keeping some kind of meta-information.) Each Worm segment is labeled with a char that's automatically generated in the process of recursively(递归) generating the linked list of Worms. When you create a Worm, you tell the constructor how long you want it to be. To make the next reference, it calls the Worm constructor with a length of one less, etc. The final next reference is left as null, indicating the end of the Worm. Object serialization is byte-oriented, and thus uses the InputStream and OutputStream hierarchies.  Finding the classAn object to be recovered from its serialized state, suppose you serialize an object and send it as a file or through a network to another machine, then you could on the other machine reconstruct the object using only the contents of the file.//c12:Alien.java//A serializable class//c12:FreezeAlien.java//Create a serialized output file.//c12:ThawAlien.java//Try to recover a serialized file without the class of object that's stored in that file.  Controlling serialization You can control the process of serialization by implementing the Externalizable interface instead of the Serializable interface. The Externalizable interface extends the Serializable interface and adds two methods, writeExteranl()(The object implements the writeExternal method to save its contents by calling the methods of DataOutput for its primitive values or calling the writeObject method of ObjectOutput for objects, strings, and arrays.) and readExternal()(The object implements the readExternal method to restore its contents by calling the methods of DataInput for primitive types and readObject for objects, strings and arrays.), that are automatically called for your object during serialization and deserialization so that you can perform your special operations. //c12:Blips.java//Simple use of Externalizable & a pitfall.//Clean: Blips.outWhen b1 is recovered, the Blip1 default constructor(public) is called, This is different form recovering a Serializable object, in which the object is constructed entirely form its stored bits, with no constructor calls. With an Externalizable object, all the normal default construction behavior occurs(including the initializations at the point of field definition), and then readExternal() is called. You need to be aware of this-in particular, the fact that all the default construction always takes place-to produce the correct behavior in your Externalizable objects. //c12:Blip3.java//Fully store and retrieve an Externalizable object The fields s and i are initialized only in the second constructor, but not in the default constructor. This means that if you don't initialize s and i in readExternal(), s will be null and i will be zero(since the storage for the object gets wiped to zero in the first step of object creation). If you comment ou the two lines of code following the phrases "You must do this" and run the program, you'll see that when the object is recovered, s is null and i is zero. If you are inheriting from an Externalizable object, you'll typically call the base-class versions of writeExternal() and readExternal() to provide proper storage and retrieval of the base-class components.  The transient keyword One way to prevent sensitive parts of your object from being serialized is to implement your class as Externalizable, as shown previously. Then nothing is automatically serialized, and you can explicity serialize only the necessary parts inside writeExternal().If you're working with a Serializable object, however, all serialization happens automatically. To control this, you can turn off serialization on a field-by-field basis using the transient keyword.For example, consider a Login object that keeps information about a particular login session. Support that, once you verify the login, you want to store the data, but without the password. The easiest way to do this is by implementing Serializable and marking the password field as transient. //c12:Logon.javaprivate transient String password; Since Externalizable objects do not store any of their fields by default, the transient keyword is for use with Serializable objects only.  An alternative to Externalizable If you're not keen on implementing the Externalizable interface, there's another approach. You can implement the Serializable interface and add(notice "add" and not "override" or "implement") methods called writeObject() and readObject() that will automatically be called when the object is serialized and deserialized, respectively. That is, if you provide these two methods, they will be used instead of the default serialization. private void writeObject(ObjectOutputStream stream) throws IOException;private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException; There's one other twist. Inside your writeObject(), you can choose to perform the default writeObject() action by calling defaultWriteObject(). Likewise, inside readObject() you can call defaultReadObject(). Here is a simple example that demonstrates how you can control the storage and retrieval of a Serializable object://c12:SerialCtl.javaprivate String a;private transient String b; private void writeObject(ObjectOutputStream stream) throws IOException{    stream.defaultWriteObject();    stream.writeObject(b);}private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException{    stream.defaultReadObject();    b=(String)stream.readObject();}In this example, non-transient field is saved by the defaultWriteObject() method and the transient field is saved and restored explicity.If you are going to use the default mechanism to write the non-transient parts of you object, you must call defaultWriteObject() as the first operation in writeObject(), and defaultReadObject() as the first operation in readObject().  Versioning It’s possible that you might want to change the version of a serializable class (objects of the original class might be stored in a database, for example). This is supported, but you’ll probably do it only in special cases, and it requires an extra depth of understanding that we will not attempt to achieve here. The JDK documents downloadable from [i]java.sun.com
cover this topic quite thoroughly.Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications ...

 Using persistence deep copy: means that you're duplicating the entire web of objects, rather than just the basic object and its references.What happens if you serialize two objects that both have a reference to a third object?When you restore those two objects from their serialized state, do you get only one occurrence of the third object?What if you serialize your two objects to separate files and deserialize them in defferent parts of your code? //c12:MyWorld.java//shows the problem Results:animals: [Bosco the dog[c12.Animal@26e431], c12.House@14f8dab
, Ralph the hamster[c12.Animal@1ddebc3], c12.House@14f8dab
, Fronk the cat[c12.Animal@a18aa2], c12.House@14f8dab
]
animals1: [Bosco the dog[c12.Animal@10ef90c], c12.House@a32b
, Ralph the hamster[c12.Animal@1d8957f], c12.House@a32b
, Fronk the cat[c12.Animal@3ee284], c12.House@a32b
]
animals2: [Bosco the dog[c12.Animal@10ef90c], c12.House@a32b
, Ralph the hamster[c12.Animal@1d8957f], c12.House@a32b
, Fronk the cat[c12.Animal@3ee284], c12.House@a32b
]
animals3: [Bosco the dog[c12.Animal@8965fb], c12.House@867e89
, Ralph the hamster[c12.Animal@1dd7056], c12.House@867e89
, Fronk the cat[c12.Animal@fa3ac1], c12.House@867e89
] Notice that in animals1 and animals2, the same addresses appear, including the references to the House object that both share. On the other hand, when animals3 is recovered, the system has no way of knowing that the objects in this other stream are aliases of the objects in the first stream, so it makes a completely different web of objects.As long as you're serializing everything to a single stream, you'll be able to recover the same web of objects that you wrote, with no accidental duplication of objects. Of course, you can change the state of your objects in between the time you write the first and the last,, but that's your responsibility; the objects will be written in whatever state they are in (and with whatever connections they have to other objects) at the time you serialize them. The safest thing to do if you want to save the state of a system is to serialize as an "atomic" operation. If you serialize some things, do some other work, and serialize some more, etc., then you will not be storing the system safely. Instead, put all the objects that comprise the state of your system in a single container and simply write that container out in one operation. Then you can restore it with a single method call as well. Serializable Class should be easy to store the static fields by simply serializing the Class object.//c12:CADState.java//Saving and restoring the state of a pretend CAD system.//clean: CADState.outclass Line extends Shape {
  private static int color = RED;
  public static void serializeStaticState(ObjectOutputStream os) throws IOException { os.writeInt(color); }
  public static void deserializeStaticState(ObjectInputStream os) throws IOException { color = os.readInt(); }
  public Line(int xVal, int yVal, int dim) {
    super(xVal, yVal, dim);
  }
  public void setColor(int newColor) { color = newColor; }
  public int getColor() { return color; }
}
 The Shape class implements Serializable, so anything that is inherited from Shape is automatically Serielizable as well. Each Shape contains data, and each derived Shape class contains a static field that determines the color of all of those types of Shapes.(Placing a static field in the base class would result in only one field) Methods in the base class can be overridden to set the color for the various types(static methods are not dynamically bound, so these are normal methods). The randomFactory() method creates a different Shape each time you call it, using random values for the Shape data.Circle and square are straightforward extensions of Shape.In main(), one ArrayList is used to hold the Class objects and the other to hold the shapes. If you don't provide a command-line argument, the shapeTypes ArrayList is created and the Class objects are added, and then the shapes ArrayList is created and Shape objects are added. Next, all the static color values are set to GREEN, and everything is serialized to the file CADState.out.If you provide a command-line argument(presumably CADState.out), that file is oppened and used to restore the state of program. In both situations, the resulting ArrayList of Shapes is printed.$ java CADState
[class Circlecolor[3] xPos[71] yPos[82] dim[44]
, class Squarecolor[3] xPos[98] yPos[21] dim[49]
, class Linecolor[3] xPos[16] yPos[80] dim[37]
, class Circlecolor[3] xPos[51] yPos[74] dim[7]
, class Squarecolor[3] xPos[7] yPos[78] dim[98]
, class Linecolor[3] xPos[38] yPos[79] dim[93]
, class Circlecolor[3] xPos[84] yPos[12] dim[62]
, class Squarecolor[3] xPos[16] yPos[51] dim[94]
, class Linecolor[3] xPos[51] yPos[0] dim[73]
, class Circlecolor[3] xPos[47] yPos[6] dim[49]
]

$ java CADState CADState.out
[class Circlecolor[1] xPos[71] yPos[82] dim[44]
, class Squarecolor[0] xPos[98] yPos[21] dim[49]
, class Linecolor[3] xPos[16] yPos[80] dim[37]
, class Circlecolor[1] xPos[51] yPos[74] dim[7]
, class Squarecolor[0] xPos[7] yPos[78] dim[98]
, class Linecolor[3] xPos[38] yPos[79] dim[93]
, class Circlecolor[1] xPos[84] yPos[12] dim[62]
, class Squarecolor[0] xPos[16] yPos[51] dim[94]
, class Linecolor[3] xPos[51] yPos[0] dim[73]
, class Circlecolor[1] xPos[47] yPos[6] dim[49]
]You can see that the values of xPos, yPos, and dim were all stored and recovered successfully, but there's something wrong with the retrieval of the static information. It's all "3" going in, but it doesn't come out that way. Circles have a value of 1 (RED, which is the definition), and Squares have a value of 0(remember, they are initialized in the constructor). It's as if the statics didn't get serialized at all! That's right-even though class Class is Serializable, it doesn't do what you expect. So if you want to seialize statics, you must do it yourself.This is what the serializeStaticState() and deserializeStaticState() static methods in Line are for.Thus to make CADState.java run correctly, you must:Add a serializeStaticState() and deserializeStaticState() to the shapes.
Remove the ArrayList shapeTypes and all code related to it.
Add calls to the new serialize and deserialize static methods in the shapes.
 [align=center]Preferences[/align]JDK1.4 introduced the Preferences API, which is much closer to persistence than object serialization because it automatically stores and retrieves your information. However, its use is restricted to small and limited data sets-you can only hold primitives and Strings, and the length of each stored String can't be longer than 8K (not tiny, but you don't want to build anything serious with it, either). As the name suggests, the preferences API IS designed to store and retrieve user preferences and program-configuration settings.//c12:PreferencesDemo.java Here, userNodeForPackage() is used, but you could also choose systemNodeForPackage(); the choice is somewhat arbitrary, but the idea is that "user" is for individual user preferences, and "system" is for general installation configuration. Since main() is static, PreferencesDemo.class is used to identify the node, but inside a non-static method, you'll usually use getClass(). You don't need to use the current class as the node identifier, but that's the usual pratice.Once you create the node, it's available for either loading or reading data. This example loads the node with various types of items and then gets the keys(). These come back as a String[], which you might not expect if you're used to keys() in collections library. Here, they're converted to a List that is used to produce an Iterator for printing keys and values. Notice the second argument to get(). This is the default value that is produced if there isn't any entry for that key value. While iterating through a set of keys, you always know there's an entry, so using null as the default is safe, but normally you'll be fetching a named key, as in:    prefs.getInt("companions", 0);In the normal case, you'll want to provide a reasonable default value. In fact, a typical idiom(习惯用法) is seen in the lines:    int usageCount=prefs.getInt("UsageCount", 0);    usageCount++;    prefs.putInt("UsageCount", usageCount);This way, the first time you run the program, the UsageCount will be zero, but on subsequent invocations it will be nonzero.When you run PreferencesDemo.java you'll see that the UsageCount does indeed increment every time you run the program, but where is the data stored? There's no local file that appears after the program is run the first time. The Preferences API uses appropriate system resources to accomplish its task, and these will vary depending on the OS. In Windows, the registry is used. But the whole point is that the information is magically stored for you so that you don't have to worry about how it works form one system to another.  [align=center]Regular expressions[/align][align=center] [/align]Technically, Rugular expressions are string manipulation tools.Regular expressions are powerful and flexible text-processing tools. They allow you to specify, programmatically, complex patterns of text that can be discovered in an input string. Once you discover these patterns, you can then react to them any way you want. Although the syntax of regular expressions can be initmidating at first, they provide a compact and dynamic language that can be employed to solve all sorts of string processing, matching and selection, editing, and verification problems in a completely general way. Creating regular expressionsYou can begin learning regular expressions with a useful subset of the possible constructs. A complete list of constructs for building regular expressions can be found in the javadocs for the Pattern class for package java.util.regex.
Characters
B
The specific character B
/xhh
Character with hex value 0xhh
/uhhhh
The Unicode character with hex representation 0xhhhh
/t
Tab
/n
Newline
/r
Carriage return
/f
Form feed
/e
Escape
 The power of regular expressions begins to appear when defining character classes. Here are some typical ways to create character classes, and some predefined classes:
Character Classes
.
Represents any character
[abc]
Any of the characters a, b, or c (same as a|b|c)
[^abc]
Any character except a, b, and c (negation)
[a-zA-Z]
Any character a through z or A through Z (range)
[abc[hij]]
Any of a,b,c,h,i,j (same as a|b|c|h|i|j) (union)
[a-z&&[hij]]
Either h, i, or j (intersection)
/s
A whitespace character (space, tab, newline, formfeed, carriage return)
/S
A non-whitespace character ([^/s])
/d
A numeric digit [0-9]
/D
A non-digit [^0-9]
/w
A word character [a-zA-Z_0-9]
/W
A non-word character [^/w]
In Java, "//" means "I'm inserting a regular expression backslash, so the following character has special meaning." For example, if you want to indicate one or more word characters, your regular expression string will be '//w+'. If you want to insert a literal backslash, you say '////'. However, things like newlines and tabs just use a single backslash:"/n/t". 
Logical Operators
XY
X followed by Y
X|Y
X or Y
(X)
A capturing group. You can refer to the ithcaptured group later in the expression with /i
 
Boundary Matchers
^
Beginning of a line
$
End of a line
/b
Word boundary
/B
Non-word boundary
/G
End of the previous match
 As an example, each of the following represent valid regular expressions, and all will successfully match the character sequence "Rudolph":    Rudolph    [rR]udolph    [rR][aeiou][a-z]ol.*    R.* QuantifiersA quantifier describes the way that a pattern absorbs input text:Greedy:Quantifiers are greedy unless otherwise altered. A greedy expression finds as many possible matchers for the pattern as possible. A typical cause of problems is to assume that your pattern will only match the first possible group of characters, when it's actually greedy and will keep going.
Reluctant:Specified with a question mark, this quantifier matches the minimum necessary number of characters to satisfy the pattern. Also called lazy,minimal matching, non-greedy, or ungreedy.
Possessive:Currently only available in Java, and it is more advanced, so you probably won't use it right away. As a regular expression is applied to a string, it generates many states so that it can backtrack if the match fails. Possessive quantifiers do not keey those intermediate states, and thus prevent backtracking. They can be used to prevent a regular expression from running away and also to make it execute more efficiently.
Greedy

Reluctant

Possessive

Matches

X?

X??

X?+

X, one or none

X*

X*?

X*+

X, zero or more

X+

X+?

X++

X, one or more

X{n}

X{n}?

X{n}+

X, exactly n times

X{n,}

X{n,}?

X{n,}+

X, at least n times

X{n,m}

X{n,m}?

X{n,m}+

X, at least n but not more than m times

 For example:    abc+    Might seem like it would match the sequence 'abc' one or more times, and if you apple it to the input string 'abcabcabc', you will in fact get three matches. However, the expression actually says "match 'ab' followed by one or more occurrences of 'c'". To match the entire string 'abc' one or more times, you must say:    (abc)+ CharSequence The String, StringBuffer, and CharBuffer classes have been modified to implement this new CharSequence interface. Many regular expression operations take CharSequence arguments.  Pattern and Matcher //c12:TestRegularExpression.java//Allow you to easly try out regular expressions.//args: abcabcabcdefabc "abc+" "(abc)+" "(abc){2,}"Regular expressions are implemented in Java throuth the Pattern and Matcher classes in the package java.util.regex. A Pattern object represents a compiled version of a regular expression. The static compile() method compiles a regular expression string into a Pattern object. As seen in the preceding example, you can use the matcher() method and the input string to produce a Matcher object from the compiled Pattern object.    Pattern p= Pattern.compile("a*b");    Matcher m=p.matcher("aaaaab");    boolean b=m.matches();or    boolean b=Pattern.matches("a*b", "aaaaab");for quickly discerning if regex can be found in input, and a split() method that produces an array of String that has been broken around matches of the regex.A Matcher object is generated by calling Pattern.matcher() with the input string as an argument. The Matcher object is then used to access the results, using methods to evaluate the success or failure of different types of matches:boolean matches(); boolean lookingAt(); boolean find(); boolean find(int start) find()Matcher.find() can be used to discover multiple pattern matches in the CharSequence to whick it is applied. //c12:FindDemo.javaThe pattern '//w+' indicates "one or more word characters", so it will simple split up the input into words. find() is like an iterator., moving forward through the input string. However, the second version of find() can be given an integer argument that tells it the character position for the beginning of the search-this version resets the search position to the value of the argument. GroupsGroups are regular expressions set off by parentheses that can be called up later with their group number. Group zero indicates the whole expression match, group one is the first parenthesized group, etc. Thus inA(B(C))D - there are three groups: Group 0 is ABCD, Group 1 is BC, Group 2 is C The Matcher object has methods to give you information about groups:public int groupCount() returns the number of groups in this matchers pattern. Group zero is not included in this count.public String group() returns group zero(the entire match) from the previous match operation(find(), for example).public String group(int i) returns the given group number during the previous match operation. If the match was successful, but the group specified failed to match any part of the input string, then null is returned.public int start(int group) returns the start index of the group found in the previous match operation.public int end(int group) returns the index of the last character, plus one, of the group found in the previous match operation. //c12:Groups.javaThe regular expressions("(?m)(//S+)//s+((//S+)//s+(//S+))$") pattern has four parentheses so that it has five groups.(/S+) means consisting of any number of non-whitespace characters;(/s+) means consisting of any number of witespace characters;'$' means the end of a line;(?m) explicitly tell the regular expression to pay attention to newlines within the input.  start() and end() Following a successful matching operation, start() returns the start index of the previous match, and end() returns the index of the last character matched, plus one. Invoking either start() or end() following an unsuccessful matching operation produces an ILLegalStateException. The following program also demonstrates matches() and lookingAt()://c12:StartEnd.java Notice that find() will locate the regular expression anywhere in the input, but lookingAt() and matches() only succeed if the regular expression starts matching at the very(真正的) beginning of the input. While matches() only succeeds if the entire input matches the regular expression, lookingAt() succeeds if only the first part of the input matches.  Pattern flags An alternative compile() method accepts flags that affect the behavior of regular expression matching:    Pattern Pattern.compile(String regex, int flag) 
Compile Flag

Effect

Pattern.CANON_EQ

Two characters will be considered to match if, and only if, their full canonical decompositions match. The expression “a/u030A”, for example, will match the string “?” when this flag is specified. By default, matching does not take canonical equivalence into account.

Pattern.CASE_INSENSITIVE
(?i)

By default, case-insensitive matching assumes that only characters in the US-ASCII character set are being matched. This flag allows your pattern to match without regard to case (upper or lower). Unicode-aware case-insensitive matching can be enabled by specifying the UNICODE_CASE flag in conjunction with this flag.

Pattern.COMMENTS
(?x)

In this mode, whitespace is ignored, and embedded comments starting with # are ignored until the end of a line. Unix lines mode can also be enabled via the embedded flag expression.

Pattern.DOTALL
(?s)

In dotall mode, the expression ‘.’ matches any character, including a line terminator. By default, the ‘.’ expression does not match line terminators.

Pattern.MULTILINE
(?m)

In multiline mode, the expressions ‘^’ and ‘$’ match the beginning and ending of a line, respectively. ‘^’ also matches the beginning of the input string, and ‘$’ also matches the end of the input string. By default, these expressions only match at the beginning and the end of the entire input string.

Pattern.UNICODE_CASE
(?u)

When this flag is specified, case-insensitive matching, when enabled by the CASE_INSENSITIVE flag, is done in a manner consistent with the Unicode Standard. By default, case-insensitive matching assumes that only characters in the US-ASCII character set are being matched.

Pattern.UNIX_LINES
(?d)

In this mode, only the ‘/n’ line terminator is recognized in the behavior of ‘.’, ‘^’, and ‘$’.

 Particularly useful among these flags are Pattern.CASE_INSENSITIVE, Pattern.MULTILINE, and Pattern.COMMENTS(which is helpful for clarity and/or documentation). Note that the behavior of most of the flags can also be obtained by inserting the parenthesized characters, shown in the table beneath the flags, into you regular expression preceding the place where you want the mode to take effect.You can combine the effect of these and other flags through an "OR"("|") operation://c12:ReFlags.java    Pattern p=Pattern.compile("^java", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); This creates a pattern that will match lines starting with "java","Java","JAVA", etc.. Note that the group() method only produces the matched portion.  split() Splitting divieds an input string into an array of String objects, delimited by the regular expression.    String[] split(CharSequence charseq)    String[] split(CharSequence charseq, int limit) //c12:SplitDemo.java    String input =
      "This!!unusual use!!of exclamation!!points";
    System.out.println(Arrays.asList(
      Pattern.compile("!!").split(input)));
    // Only do the first three:
    System.out.println(Arrays.asList(
      Pattern.compile("!!").split(input, 3)));
    System.out.println(Arrays.asList(
      "Aha! String has a split() built in!".split(" "))); Results:
      "[This, unusual use, of exclamation, points]",
      "[This, unusual use, of exclamation!!points]",
      "[Aha!, String, has, a, split(), built, in!]"

Notice that regular expressions are so valuable that some operations have also been added to the String class, including split(), matches(), replaceFirst(), and replaceAll(). These behave llike their Pattern and Matcher counterparts.  Replace operations Regular expressions become especially useful when you begin replacing text. replaceFirst(String replacement) replaces the first matching part of the input string with replacement.replaceAll(String replacement) replaces every matching part of the input string with replacement.appendReplacement(StringBuffer sbuf, String replacement) performs step-by-step replacements into sbuf, rather than replacing only the first one or all of them, as in replaceFirst( ) and replaceAll( ), respectively. This is a very important method, because it allows you to call methods and perform other processing in order to produce replacement (replaceFirst( ) and replaceAll( ) are only able to put in fixed strings). With this method, you can programmatically pick apart the groups and create powerful replacements.appendTail(StringBuffer sbuf, String replacement) is invoked after one or more invocations of the appendReplacement( ) method in order to copy the remainder of the input string.   reset() An existing Matcher object can be applied to a new character sequence Using the reset() method://c12:Resetting.javaMatcher m=Pattern.compile("[frb][aiu][gx]").matcher("fix the rug with bags");m.reset("fix the rig with rags"); result:      "fix"
      "rug"
      "bag"
      "fix"
      "rig"
      "rag"
reset() without any arguments sets the Matcher to the beginning of the current sequence.  [align=center]Regular expressions and Java I/O[/align]Most of the examples so far have shown regular expressions applied to static strings. The following example shows one way to apply regular expressions to search for matches in a file.//c12:JGrep.java//args: JGrep.java //b[Ssct]//w+the test arguments open the JGrep.java file to read as input, and search for words starting with [Ssct].  Is StringTokenizer needed? The new capabilities provided with regular expressions might prompt you to wonder whether the original StringTokenizer class is still necessary. Before JDK1.4, the way to split a string into parts was to "tokenize" it with StringTokenizer. But now it's much easier and more succinct to the same thin with regular expressions: //c12:ReplacingStringTokenizer.javaString input="But I'm not dead yet! I feel happy!";StringTokenize stoke=new StringTokenize(input);while(stoke.hasMreElements())    System.out.println(stoke.nextToken());  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息