Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1800312
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: Java

2012-03-26 00:16:18

先看一下java.io.File类。它其实应该命名为FileInfo会好一些。看看它能做什么:
它能用来创建一个文件


  1. File file = new File("MyFile");
  2. if (!file.exists()) {
  3.     try {
  4.         file.createNewFile();
  5.     } catch (IOException e) {
  6.         e.printStackTrace();
  7.     }
  8. }

查看一个文件的属性
  1. boolean canRead = file.canRead();
  2. long lastModified = file.lastModified();
  3. String absolutePath = file.getAbsolutePath();
  4. long freeSpace = file.getFreeSpace();

改变一个文件的属性
  1. file.setExecutable(false);
  2. file.setWritable(true);
  3. file.setLastModified(System.currentTimeMillis());

移动/重命名一个文件
  1. File otherFile = new File("MyOtherFile");
  2. file.renameTo(otherFile);
  3. try {
  4.     Thread.sleep(5000);
  5. } catch (InterruptedException e) {
  6.     e.printStackTrace();
  7. }
  8. boolean exists = file.exists(); // false;

创建一个文件夹
  1. File folder = new File("MyFolder");
  2. if (!folder.exists())
  3.     folder.mkdir();

列出一个文件夹下的所有文件和文件夹
  1. String fileNamesInFolder[] = folder.list();
  2. File filesInFolder[] = folder.listFiles();

当然你也可以列出一个文件夹下你感兴趣的文件和文件夹
  1. String interestedfileNames[] = folder.list(new FilenameFilter() {
  2.     public boolean accept(File dir, String name) {
  3.         return name.endsWith(".txt");
  4.     }
  5. });

用File的静态方法得到系统所有的根目录
  1. File roots[] = File.listRoots();
  2. System.out.println(Arrays.toString(roots));

得到一个文件或文件夹的父文件夹(只对绝对路径有效):
  1. System.out.println(file.getParent()); // null!!
  2. File absFile = file.getAbsoluteFile();
  3. System.out.println(absFile.getParent()); // works!!

最后是删除一个文件或文件夹
  1. boolean deleted = file.delete();
  2. deleted = folder.delete();


输入输出(I/O)的对象并不仅仅是文件,可以是任何形式的设备,比如屏幕或是网络。下面介绍四个I/O最最基本的类,它们是InputStreamOutputStreamReaderWriter

InputStream是所有“输入流”的基类,它是一个纯虚类并定义了一个读取字节的纯虚方法:“public int read() throws IOException”,你可以这样定义InputStream的子类:


  1. class MyInputStream extends InputStream {
  2.     @Override
  3.     public int read() throws IOException {
  4.         if (itor >= data.length)
  5.             return -1;
  6.         return data[itor++];
  7.     }
  8.     
  9.     private int itor = 0;
  10.     private byte data[] = { 2, 5, 9, 8, 3, 4 };
  11. }

在定义好这个纯虚read方法只读取一个字节,但返回一个int值。这个int值如果为-1说明读取已经完毕,但如果这个值作为有效值的话,它的前三个字节会被忽略。read方法定义好后,InputStream的read(byte[] b)read(byte[] b, int off, int len)方法会调用read()方法来实现更复杂的功能。

OutputStream是所有“输出流”的基类,它也是一个纯虚类,定义了两个写入字节的纯虚方法:“public void write(int b) throws IOException”。定义子类:


  1. class MyOutputStream extends OutputStream {
  2.     @Override
  3.     public void write(int b) throws IOException {
  4.         data.add((byte)b);
  5.     }
  6.     
  7.     private ArrayList<Byte> data = new ArrayList<Byte>();
  8. }

Write方法写入传入int值的最后一个字节。同样的,OutputStream的write(byte[] b)write(byte[] b, int off, int len)方法会调用write()方法来完成更复杂的功能。

Reader是所有“字符读取器”的纯虚基类,它有两个纯虚方法:“public void close() throws IOException”、“public int read(char[] cbuf, int off, int len) throws IOException”。定义子类:


  1. class MyReader extends Reader {
  2.     @Override
  3.     public void close() throws IOException {
  4.         closed = true;
  5.     }

  6.     @Override
  7.     public int read(char[] cbuf, int off, int len) throws IOException {
  8.         if (closed)
  9.             throw new IOException();
  10.         if (index >= data.length())
  11.             return -1;
  12.         int count = 0;
  13.         for (int i = 0; i < len && index < data.length(); ++i) {
  14.             cbuf[i+off] = data.charAt(index++);
  15.             ++count;
  16.         }
  17.         return count;
  18.     }
  19.     
  20.     private boolean closed = false;
  21.     private String data = "This is the data. You are happy~";
  22.     private int index = 0;
  23. }

Reader是InputStream的补充,它提供了读取字符的功能,而不仅仅是字节。在定义好read(char[] cbuf, int off, int len)方法后,Reader的“read()”、“read(char[] cbuf)”和“read(CharBuffer target)”方法就可以利用定义好的方法来提供更简单的读取字符的方法。

Writer是所有“写入字符器”的纯虚基类,它定义了三个纯虚方法:“public void close() throws IOException”、“public void flush() throws IOException”和“public void write(char[] cbuf, int off, int len) throws IOException”。定义子类:


  1. class MyWriter extends Writer {
  2.     @Override
  3.     public void close() throws IOException {
  4.         closed = true;
  5.     }

  6.     @Override
  7.     public void flush() throws IOException {
  8.         if (closed)
  9.             throw new IOException();
  10.         System.out.println(data);
  11.     }

  12.     @Override
  13.     public void write(char[] cbuf, int off, int len) throws IOException {
  14.         if (closed)
  15.             throw new IOException();
  16.         for (int i = 0; i < len; ++i)
  17.             data += cbuf[i+off];
  18.     }
  19.     
  20.     private boolean closed = false;
  21.     private String data = new String();
  22. }

定义好这个纯虚方法后,Writer类的“append(char c)”、“append(CharSequence csq)”、“append(CharSequence csq, int start, int end)”、“write(char[] cbuf)”、“writer.write(int c)”、“write(String str)”和“write(String str, int off, int len)”方法也都可以用了。


现在回到一个比较基本的问题,怎么从读写一个文件的数据?java提供了两个类:FileInputStreamFileOutputStream。我们可以用它们基类里定义的方法:InputStream.read(byte[] bytes)OutputStream.write(byte[] bytes)。提起精神来,下面的代码有点长,虽然不复杂:


  1. void testFileIOStream() throws IOException {
  2.     long ldata = -328910192;
  3.     int idata = 2305910;
  4.     short sdata = 4652;
  5.     char cdata = 'A';
  6.     double ddata = 98323.8253221;
  7.     float fdata = 2382.784f;
  8.         
  9.     // Write to file
  10.     FileOutputStream fos = new FileOutputStream("MyFile");
  11.     fos.write(DataConvertor.longToBytes(ldata));
  12.     fos.write(DataConvertor.intToBytes(idata));
  13.     fos.write(DataConvertor.shortToBytes(sdata));
  14.     fos.write(DataConvertor.charToBytes(cdata));
  15.     fos.write(DataConvertor.doubleToBytes(ddata));
  16.     fos.write(DataConvertor.floatToBytes(fdata));
  17.     fos.flush();
  18.     fos.close();
  19.         
  20.     byte[] lBytes = new byte[Long.SIZE/8];
  21.     byte[] iBytes = new byte[Integer.SIZE/8];
  22.     byte[] sBytes = new byte[Short.SIZE/8];
  23.     byte[] cBytes = new byte[Character.SIZE/8];
  24.     byte[] dBytes = new byte[Double.SIZE/8];
  25.     byte[] fBytes = new byte[Float.SIZE/8];
  26.         
  27.     // Read from file
  28.     FileInputStream fis = new FileInputStream("MyFile");
  29.     fis.read(lBytes);
  30.     fis.read(iBytes);
  31.     fis.read(sBytes);
  32.     fis.read(cBytes);
  33.     fis.read(dBytes);
  34.     fis.read(fBytes);
  35.     fis.close();
  36.         
  37.     // Print Values
  38.     System.out.println("Long data: " + DataConvertor.bytesToLong(lBytes));
  39.     System.out.println("Int data: " + DataConvertor.bytesToInt(iBytes));
  40.     System.out.println("Short data: " + DataConvertor.bytesToShort(sBytes));
  41.     System.out.println("Char data: " + DataConvertor.bytesToChar(cBytes));
  42.     System.out.println("Double data: " + DataConvertor.bytesToDouble(dBytes));
  43.     System.out.println("Float data: " + DataConvertor.bytesToFloat(fBytes));
  44. }

看到上面的代码里有个DataConvertor的类,它可以把基本类型和字节数组进行转换。它可不是java里自带的,我们得自己实现它:
  1. class DataConvertor {
  2.     public static byte[] longToBytes(long l) {
  3.         return numberToBytes(l, Long.SIZE/8);
  4.     }
  5.     
  6.     public static long bytesToLong(byte[] bytes) {
  7.         return bytesToNumber(bytes, Long.SIZE/8).longValue();
  8.     }

  9.     public static byte[] intToBytes(int n) {
  10.         return numberToBytes(n, Integer.SIZE/8);
  11.     }
  12.     
  13.     public static int bytesToInt(byte[] bytes) {
  14.         return bytesToNumber(bytes, Integer.SIZE/8).intValue();
  15.     }
  16.     
  17.     public static byte[] shortToBytes(short s) {
  18.         return numberToBytes(s, Short.SIZE/8);
  19.     }
  20.     
  21.     public static short bytesToShort(byte[] bytes) {
  22.         return bytesToNumber(bytes, Short.SIZE/8).shortValue();
  23.     }
  24.     
  25.     public static byte[] doubleToBytes(double d) {
  26.         return longToBytes(Double.doubleToLongBits(d));
  27.     }
  28.     
  29.     public static double bytesToDouble(byte[] bytes) {
  30.         return Double.longBitsToDouble(bytesToLong(bytes));
  31.     }
  32.     
  33.     public static byte[] floatToBytes(float f) {
  34.         return intToBytes(Float.floatToRawIntBits(f));
  35.     }
  36.     
  37.     public static float bytesToFloat(byte[] bytes) {
  38.         return Float.intBitsToFloat(bytesToInt(bytes));
  39.     }
  40.     
  41.     public static byte[] charToBytes(char c) {
  42.         return numberToBytes((int)c, Character.SIZE/8);
  43.     }
  44.     
  45.     public static char bytesToChar(byte[] bytes) {
  46.         return (char)(bytesToNumber(bytes, Character.SIZE/8).intValue());
  47.     }
  48.     
  49.     private static byte[] numberToBytes(Number n, final int size) {
  50.         byte[] bytes = new byte[size];
  51.         long l = n.longValue();
  52.         for (int i = 0; i < size; i++)
  53.             bytes[i] = (byte)((l >> 8*i) & 0xff);
  54.         return bytes;
  55.     }
  56.     
  57.     private static Number bytesToNumber(byte[] bytes, final int size) {
  58.         long l = 0;
  59.         for (int i = 0; i < size; i++)
  60.             l |= ((long)(bytes[i] & 0xff) << (8*i));
  61.         return l;
  62.     }
  63. }

是不是有点复杂?如果我们每次写文件总要和这么底层的字节打交道的话,那样总是显得比较繁琐。java提供了另一组I/O流:DataInputStreamDataOutputStream,它可以外嵌在其它的I/O流对象外,比如FileInputStream。用这两个类重写上面的读写文件的功能:
  1. void testDataIOStream() throws IOException {        
  2.     DataOutputStream dos = new DataOutputStream(new FileOutputStream("MyFile"));
  3.     dos.writeLong(ldata);
  4.     dos.writeInt(idata);
  5.     dos.writeShort(sdata);
  6.     dos.writeChar(cdata);
  7.     dos.writeDouble(ddata);
  8.     dos.writeFloat(fdata);
  9.     dos.flush();
  10.     dos.close();
  11.         
  12.     DataInputStream dis = new DataInputStream(new FileInputStream("MyFile"));
  13.     long l = dis.readLong();
  14.     int n = dis.readInt();
  15.     short s = dis.readShort();
  16.     char c = dis.readChar();
  17.     double d = dis.readDouble();
  18.     float f = dis.readFloat();
  19.     dis.close();
  20. }

java的I/O类库用的是装饰者模式,比如DataInputStream可以是任何一个InputStream的装饰者。通过这种模式,你可以组合出各种功能的I/O对象。


如果需要向文件存取字符串,而不是字节,就可以使用FileReaderFileWriter了:


  1. testFileRW() throws IOException {
  2.     FileWriter fw = new FileWriter("MyFile");
  3.     fw.write("Hello, ");
  4.     fw.write("hava a good day\n");
  5.     fw.append("Here's another line!");
  6.     fw.flush();
  7.     fw.close();
  8.         
  9.     FileReader fr = new FileReader("MyFile");
  10.     CharBuffer cb = CharBuffer.allocate(1000);
  11.     int n = fr.read(cb);
  12.     fr.close();
  13.         
  14.     System.out.println(cb.array());
  15. }

我们同样可以给Reader和Writer添加装饰者,比如BufferedReaderBufferedWriter。它们提供一个缓冲区来防止每次都执行实际读写操作,同时还提供读写行的能力:
  1. void testBufferRW() throws IOException {
  2.     BufferedWriter bw = new BufferedWriter(new FileWriter("MyFile"));
  3.     bw.write("Write into buffer");
  4.     bw.newLine(); // BufferedWriter only!!
  5.     bw.write("Another line");
  6.     bw.flush();
  7.     bw.close();
  8.         
  9.     BufferedReader br = new BufferedReader(new FileReader("MyFile"));
  10.     String line;
  11.     do {
  12.         line = br.readLine(); // BufferedReader only!!
  13.         System.out.println(line);
  14.     } while (line != null);
  15. }


除了文件,我们也可以对其它类型的目标进行读写,比如内存。我们可以用CharArrayWriter/CharArrayReader读写内存(或者ByteArrayInputStream/ByteArrayOutputStream读写字节)。下面给了一个在内存中读写字符串例子,同时也介绍一个PrintWriter和StringReader:


  1. void testCharArrayRW() throws IOException {
  2.     // write to memory instead of file
  3.     CharArrayWriter baw = new CharArrayWriter();
  4.     PrintWriter pw = new PrintWriter(baw);
  5.     pw.print((int)3);
  6.     pw.print((boolean)true);
  7.     pw.println("OK");
  8.     pw.flush();
  9.     pw.close();
  10.         
  11.     // read from memory using CharArrayReader
  12.     CharArrayReader car = new CharArrayReader(baw.toCharArray());
  13.     BufferedReader br = new BufferedReader(car);
  14.     String line;
  15.     while ((line = br.readLine()) != null)
  16.         System.out.println(line);
  17.     br.close();
  18.         
  19.     // read from memory using StringReader
  20.     StringReader sr = new StringReader(baw.toString());
  21.     br = new BufferedReader(sr);
  22.     sr.skip(2);
  23.     while ((line = br.readLine()) != null)
  24.         System.out.println(line);
  25.     sr.close();
  26. }


InputStreamReaderOutputStreamWriter可以把InputStream和OutputStream转成Reader和Writer:


  1. void testIOStreamRW() throws IOException {
  2.     OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("MyFile"));
  3.     osw.write("Just for fun");
  4.     osw.flush();
  5.     osw.close();
  6.         
  7.     InputStreamReader isr = new InputStreamReader(new FileInputStream("MyFile"));
  8.     int c;
  9.     while ((c = isr.read()) >= 0)
  10.         System.out.print((char)c);
  11.     isr.close();
  12. }


系统的标准I/O包括System.inSystem.outSystem.err。System.out和System.err是两个PrintStream对象,System.in是一个InputStream对象。可以使用System的setIn(InputStream)setOut(PrintStream)setErr(PrintStream)方法来重定向这些标准I/O的目标。

I/O库里有一个类RandomAccessFile,它不是Reader/Writer或InputStream/OutputStream的子类,而是直接继承自Object类并实现了DataInputDataOuput这两个接口。(DataInputStream和DataOutputStream也分别实现了这两个接口)。同时它还可以定位到文件的随机位置进行读写:


  1. void testRandomAccessFile() throws IOException {
  2.     RandomAccessFile raf = new RandomAccessFile("MyFile", "rw");
  3.     for (int i = 1; i <= 10; ++i)
  4.         raf.writeInt(i);
  5.         
  6.     // return to the beginning
  7.     raf.seek(0);
  8.     for (int i = 0; i < 10; ++i)
  9.         System.out.print(raf.readInt() + " "); // 1 2 3 4 5 6 7 8 9 10
  10.         
  11.     // modify the 5th int
  12.     raf.seek(Integer.SIZE/8 * 4);
  13.     raf.writeInt(555);
  14.         
  15.     raf.seek(0);
  16.     for (int i = 0; i < 10; ++i)
  17.         System.out.print(raf.readInt() + " "); // 1 2 3 4 555 6 7 8 9 10
  18. }


java里还提供压缩文件的读写。最常用的两种压缩算法是Zip和GZiP。先看看GZip的简单例子:


  1. testGZipIOStream() throws FileNotFoundException, IOException {
  2.     GZIPOutputStream gzos = new GZIPOutputStream(new FileOutputStream("MyZip.gz"));
  3.     DataOutputStream dos = new DataOutputStream(gzos);
  4.     dos.writeInt(38);
  5.     dos.flush();
  6.     dos.close();
  7.         
  8.     GZIPInputStream gzis = new GZIPInputStream(new FileInputStream("MyZip.gz"));
  9.     DataInputStream dis = new DataInputStream(gzis);
  10.     int n = dis.readInt();
  11.     dis.close();
  12.         
  13.     System.out.println(n);
  14. }

上面的代码会生成一个MyZip.gz文件,它里面带一个名为“MyZip”的Entry。用解压缩软件就可以看到。

java对Zip文件的支持比较好,可以添加多个Entry,甚至是子文件夹。下例把一个文件压缩到一个zip文件里,同时创建了一个子文件夹下的Entry:


  1. void testZipIOStream() throws IOException {
  2.     // create a file to compress into a zip file
  3.     FileWriter fw = new FileWriter("MyFile");
  4.     fw.write("Just for fun");
  5.     fw.flush();
  6.     fw.close();
  7.     
  8.     ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("MyZip.zip"));
  9.     zos.setComment("Here's some comment");
  10.     zos.putNextEntry(new ZipEntry("MyFile"));
  11.     // compress MyFile into the zip file
  12.     FileReader fr = new FileReader("MyFile");
  13.     int b;
  14.     while ((b=fr.read()) >= 0)
  15.         zos.write(b);
  16.     // another entry in a sub folder.
  17.     zos.putNextEntry(new ZipEntry("Parent/SubFile"));
  18.     zos.write('A');
  19.     zos.flush();
  20.     zos.close();
  21.         
  22.     ZipInputStream zis = new ZipInputStream(new FileInputStream("MyZip.zip"));
  23.     // read MyFile
  24.     ZipEntry ze = zis.getNextEntry();
  25.     System.out.println(ze.getName()); // MyFile
  26.     InputStreamReader isr = new InputStreamReader(zis);
  27.     int c;
  28.     while ((c=isr.read()) >= 0)
  29.         System.out.print((char)c); // Output: Just for fun
  30.     System.out.println();
  31.     // read SubFile
  32.     ze = zis.getNextEntry();
  33.     System.out.println(ze.getName()); // Parent/SubFile
  34.     System.out.println((char)isr.read()); // 'A'
  35.     isr.close();
  36. }


JDK1.4引入了一个新的I/O类库:java.nio.*(nio = new io)。它通过通道(java.nio.channels.Channel)缓冲器(java.nio.ByteBuffer)来提高I/O的效率。FileInputStream、FileOutputStream和RandomAccessFile都提供了一个getChannel的方法来使用通道传输数据。下面给一个简单的例子:


  1. void testChannel() throws IOException {
  2.     FileChannel fc = new FileOutputStream("MyFile").getChannel();
  3.     fc.write(ByteBuffer.wrap("string data".getBytes()));
  4.     fc.close();
  5.     fc = new RandomAccessFile("MyFile", "rw").getChannel();
  6.     // locate to the end
  7.     fc.position(fc.size());
  8.     fc.write(ByteBuffer.wrap("\nAppend to the end".getBytes()));
  9.     fc.close();
  10.         
  11.     fc = new FileInputStream("MyFile").getChannel();
  12.     ByteBuffer bb = ByteBuffer.allocate(1024);
  13.     fc.read(bb);
  14.     bb.flip(); // prepare to read the buffer
  15.     while (bb.hasRemaining())
  16.         System.out.print((char)bb.get());
  17. }

ByteBuffer就是唯一可以直接和Channel交互的缓冲器。它有一点不方便的地方就是,当读取这个缓冲器的数据前,必须调用ByteBuffer.flip()方法,而在向这个缓冲器写数据前,要调用ByteBuffer.clear()方法。(clear方法并不清空已有的数据,待会再作详细说明)。这种不便利性也是为了提高存取速度而作的牺牲。

ByteBuffer只能通过静态方法ByteBuffer.wrapByteBuffer.allocate创建,它在被创建后大小(Capacity)就是固定的。它用一个position的整型值来指示当前读写的位置,同时用一个limit的整型成员来表示当前数据的大小(字节数)。
当向ByteBuffer里写数据时,应该先调用clear方法,它会把postion设为0同时把limit设为和Capacity一样。之后每调用put方法写数据时,position就向后移n个字节。当position超过limit时,就抛出异常。
读数据前,应该先调用flip方法,它会把limit值设为已写数据的尾部,并把position设为0。读时可以用hasRemaining方法来判断是否还有可读数据。remaining等于limit与position的差值。
你还可以用markreset方法来标记和重置缓冲区的某个特定的位置。

在上面的代码里,我们使用ByteBuffer直接读写字符串。我们也可以使用CharBuffer


  1. testCharBuffer() throws UnsupportedEncodingException {
  2.     ByteBuffer bb = ByteBuffer.wrap("some text".getBytes());
  3.     System.out.println(bb.asCharBuffer()); // Output: ????
  4.         
  5.     bb = ByteBuffer.allocate(1024);
  6.     bb.put("some text".getBytes("UTF-16BE"));
  7.     bb.flip(); // after "put" call this to read
  8.     bb.rewind(); // return to the beginning
  9.     System.out.println(bb.asCharBuffer()); // Output: some text
  10.         
  11.     bb.clear(); // only reset the position, won't erase the content
  12.     CharBuffer cb = bb.asCharBuffer();
  13.     cb.put("other");
  14.     cb.flip();
  15.     System.out.println(cb); // Output: other
  16. }

CharBuffer是ByteBuffer的一个视图缓冲器,即它底层和ByteBuffer共用一块缓冲区,但维护独自的position和limit等成员。此外还有IntBuffer、DoubleBuffer等视图缓冲器。注意到上面的代码里,在用裸缓冲器写字符串我们必须把对它进行UTF-16BE的编码,否则CharBuffer不能识别。


你可以用Channel的TransferToTransferFrom方法在两个通道间传递数据:


  1. void testTransferChannel() throws IOException {
  2.     FileChannel in = new FileInputStream("MyFile").getChannel();
  3.     FileChannel out = new FileOutputStream("Other").getChannel();
  4.     in.transferTo(0, in.size(), out);
  5. }


有了通道,我们就可以使用MappedByteBuffer把一个文件(整个或部份地)映射到内存中进行读写:
  1. void testMappedBuffer() throws FileNotFoundException, IOException {
  2.     int start = 2;
  3.     int length = 12;
  4.     MappedByteBuffer mbb = new RandomAccessFile("MyFile", "rw").getChannel().
  5.                 map(FileChannel.MapMode.READ_WRITE, start, length);
  6.     while (mbb.hasRemaining())
  7.         System.out.print((char)mbb.get());
  8. }

内存映射的读写比直接使用I/O stream要快速很多,同时还能解决大文件不能全部装入内存的问题。

我们可以对文件或其中的某一部份进行加锁
  1. void testFileLock() throws IOException {
  2.     FileOutputStream fos = new FileOutputStream("MyFile");
  3.     FileLock fl = fos.getChannel().tryLock();
  4.     if (fl != null) {
  5.         System.out.println("Got lock!");
  6.         fl.release();
  7.     }
  8.         
  9.     int start = 2;
  10.     int length = 12;
  11.     boolean shared = false;
  12.     FileLock fl_part = fos.getChannel().tryLock(start, length, shared);
  13.     if (fl_part != null) {
  14.         System.out.println("Got part lock!!");
  15.         fl.release();
  16.     }
  17.         
  18.     fos.close();
  19. }


java对序列化的支持作的非常好,只要让需要序列化的类实现Serializable接口,而这个接口没有任何方法。之后使用ObjectOutputStreamObjectInputStream就可以读写对象了:


  1. class MyClass implements Serializable {
  2.     public void print() {
  3.         System.out.println("MyClass - " + i);
  4.     }
  5.     private int i;
  6.     {
  7.         i = new Random().nextInt(199);
  8.     }
  9. }

  10. void testSerialization() throws FileNotFoundException, IOException, ClassNotFoundException {
  11.     MyClass mc = new MyClass();
  12.     mc.print();
  13.         
  14.     ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("MyFile"));
  15.     oos.writeObject(mc);
  16.     oos.close();
  17.         
  18.     ObjectInputStream ois = new ObjectInputStream(new FileInputStream("MyFile"));
  19.     MyClass mc2 = (MyClass)ois.readObject();
  20.     ois.close();
  21.     mc2.print();
  22. }


如果你不想使用java自带的序列化方式(直接把二进制数据写入内存),可以实现Externalizable接口。它有两个方法:writeExternalreadExternal。想要使用Externalizable接口的类必须提供一个public的不带参数的构造器。看一个例子:


  1. class MyExternalizable implements Externalizable {

  2.     @Override
  3.     public void readExternal(ObjectInput in) throws IOException,
  4.             ClassNotFoundException {
  5.         i = in.readInt();
  6.     }

  7.     @Override
  8.     public void writeExternal(ObjectOutput out) throws IOException {
  9.         out.writeInt(i);
  10.     }
  11.         
  12.     // A public constructor without arguments is a must!!
  13.     public MyExternalizable() {}
  14.         
  15.     public void print() {
  16.         System.out.println(i);
  17.     }
  18.         
  19.     private int i;
  20.     {
  21.         i = new Random().nextInt(198);
  22.     }
  23. }

接下来就可以和Serializable一样进行序列化了。如果你还是想用Serializable,但只想序列化对象里的其中一部份成员,可以用transient关键字:
  1. class MySerializable implements Serializable {
  2.     private int i;
  3.     private transient int j;
  4. }

如果你想实现Serializable,同时又想定义自己序列化的方法,也是可以的。只要实现readObjectwriteObject方法。这不是覆盖,而是通过反射被调用:
  1. class MySerializable implements Serializable {
  2.     private int i;
  3.     private transient int j;
  4.     
  5.     private void writeObject(ObjectOutputStream out) throws IOException {
  6.         out.defaultWriteObject(); // use default behavior
  7.         out.writeInt(j);
  8.     }
  9.     
  10.     private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
  11.         in.defaultReadObject();
  12.         j = in.readInt();
  13.     }
  14. }


我们还可以用java.util.prefs.Preferences注册表读写数据:


  1. void testPreferences() throws BackingStoreException {
  2.     Preferences p = Preferences.userNodeForPackage(IOTest4.class);
  3.     p.putInt("MyKey", 8); // write to registry
  4.         
  5.     int n = p.getInt("MyKey", 0); // read from registry
  6.     System.out.println(n);
  7.         
  8.     p.removeNode();
  9. }

阅读(1241) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~