第18章 Java I/O系统

18.1 File类
1、File(文件)类这个名字有一定的误导性。认为它指代的是文件,实际上却并非如此。它既能代表一个特定文件的名称,又能代表一个目录下的一组文件的名称。如果它指的是一个文件集,就可以对此集合调用list()方法,这个方法会返回一个字符数组。如果想取得不同的目录列表,只需要再创建一个不同的File对象就可以了。
18.1.1目录列表器
1、想查看一个目录列表,可以用两种方法来使用File对象。如果调用不带参数的list()方法,便可以获得此File对象包含的全部列表。然而,如果想获得一个受限列表,想得到所有扩展名为.java的文件,就要用到“目录过滤器”。


import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * Created by Panda on 2018/5/18.
 */
class DirFilter implements FilenameFilter{
    private Pattern pattern;

    public DirFilter( String regex) {
         pattern=Pattern.compile(regex);
    }

    @Override
    public boolean accept(File dir, String name) {
        return pattern.matcher(name).matches();
    }
}
public class DirList {
    public static void main(String[] args) {
        File path = new File(".");
        String[] list;
        //list()方法会为此目录对象下的每个文件名调用accept(),来判断该文件是否包含在内
        if(args.length==0){
            list=path.list();
        }else{
            list=path.list(new DirFilter(args[0]));
        }
        Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
        for (String dirItem:list) {
            System.out.println(dirItem);
        }
    }
}

18.1.2目录实用工具
1、通过使用local()方法产生由本地目录中的文件构成的File对象数组,或者通过使用walk()方法产生给定目录下的由整个目录树中所有文件构成的List(File对象比文件名更有用,因为File对象包含更多的信息)
2、

package com18;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by Panda on 2018/5/18.
 */
public final class Directoty {

    //local()
    public static File[] local(File file,final  String regex){
        return file.listFiles(new FilenameFilter()  {
            private Pattern pattern=Pattern.compile(regex);
            @Override
            public boolean accept(File pathname,String name) {
                return pattern.matcher(new File(name).getName()).matches();
            }
        });
    }


    public static File[] local(String path,final String regex){
        return local(new File(path),regex);
    }




    //walk()
    public static class TreeInfo implements Iterable<File>{
        public List<File> files = new ArrayList<>();
        public List<File> dirs = new ArrayList<>();
        @Override
        public Iterator<File> iterator() {
            return  files.iterator();
        }

        void addAll(TreeInfo other){
            files.addAll(other.files);
            dirs.addAll(other.dirs);
        }

        @Override
        public String toString() {
            return "TreeInfo{" +
                    "files=" + files +
                    ", dirs=" + dirs +
                    '}';
        }
        static TreeInfo recurseDirs(File startDir,String regex){
            TreeInfo result=new TreeInfo();
            for(File item:startDir.listFiles()){
                if(item.isDirectory()){
                    result.dirs.add(item);
                    result.addAll(recurseDirs(item,regex));
                }else{
                    if(item.getName().matches(regex)){
                        result.files.add(item);
                    }
                }
            }
            return result;
        }

        public static TreeInfo walk(String start,String regex){
            return recurseDirs(new File(start),regex);
        }
        public static TreeInfo walk(File start,String regex){
            return recurseDirs(start,regex);
        }
        public static TreeInfo walk(File start){
            return recurseDirs(start,".*");
        }
        public static TreeInfo walk(String start){
            return recurseDirs(new File(start),".*");
        }
        public static void main(String[] args) {
            if(args.length==0){
                System.out.println(walk("."));
            }else{
                for (String arg:args){
                    System.out.println(walk(arg));
                }
            }
        }
    }


}

18.1.3目录的检查及创建
1、File类不仅仅只代表存在的文件或目录,也可以用File对象来创建新的目录或尚不存在的整个目录路径。还可以查看文件的特性(如:大小,最后修改日期,读/写),检查某个File对象代表的是一个文件还是一个目录,并可以删除文件。

package com18;

import java.io.File;

/**
 * Created by Panda on 2018/5/18.
 */
public class MakeDirectories {
    private static void usage(){
        System.out.println("Usage:MakeDirectories path1...\n"+
        "Creates each path\n"+
        "Usage: MakeDirectories -d path1...\n"+
        "Deletes each path\n"+
        "Usage:MakeDirectories -r path1 path2\n"+
        "Renames from path1 to path2");
        System.exit(1);
    }
    private static void fileData(File f){
        System.out.println("Absolute path: "+f.getAbsolutePath()
        +"\n Can read: "+f.canRead()
        +"\n Can write: "+f.canWrite()
        +"\n getName: "+f.getName()
        +"\n getParent: "+f.getParent()
        +"\n getPath: "+f.getPath()
        +"\n length: "+f.length()
        +"\n lastModified: "+f.lastModified());
        if(f.isFile()){
            System.out.println("it is a file");
        }else if(f.isDirectory()){
            System.out.println("it is a directory");
        }
    }

    public static void main(String[] args) {
        if(args.length<1) usage();
        if(args[0].equals("-r")){
            if(args.length!=3) usage();
            File old = new File(args[1]);
            File rname=new File(args[2]);
            old.renameTo(rname);
            fileData(old);
            fileData(rname);
            return;
        }
        int count=0;
        boolean del=false;
        if(args[0].equals("-d")){
            count++;
            del=true;
        }
        count--;
        while (++count<args.length){
            File file = new File(args[count]);
            if(file.exists()){
                System.out.println(file+" exists");
                if(del){
                    System.out.println("deleting..."+file);
                    file.delete();
                }
            }else {
                if(!del){
                    file.mkdirs();
                    System.out.println("created "+file);
                }
            }
            fileData(file);

        }
    }

}

18.2输入和输出
1、通过继承,任何来自InputStream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何来自OutputStream或Writer派生而来的类都含有名为write()的基本方法,用于写单个字节或者字节数组。
2、Java中“流”类库让人迷惑的主要原因在于:创建单一的结果流,却需要创建多个对象。
18.2.1InputStream
1、InputStream的作用用来表示那些从不同数据源产生输入的类。这些数据源包括:
1)字节数组 ByteArrayInputStream
2)String对象 StringBufferInputStream
3)文件 FileInputStream
4)“管道”,工作方式与实际管道相似,即,从一端输入,从另一端输出。PipedInputStream
5)一个由其他种类的流组成的序列,以便可以将它们收集合并到一个流内。SequenceInputStream
6)其他数据源。 FilterInputStream
18.2.2OutputStream
1、该类别决定了输出所要去往的目标:字节数组(但不是String,不过可以用字节数组自己创建)文件或管道。ByteArrayOutputStream FileOutputStream PipedOutputStream FilterOutputStream
18.3 添加属性和有用的接口
1、Java I/O类存在filter类的原因所在抽象类filter是所有装饰器类的基类。
2、装饰器必须具有和它所装饰的对象相同的接口,但它也可以扩展接口,这种情况只发生在个别filter类中。
18.3.1 通过FileInputStream 从InputStream读取数据
18.3.2 通过FileOutputStream 向OutStream写入
18.4 Reader和Writer
1、InputStream和OutputStream在以面向字节形式的I/O仍可以提供极有价值的功能,Reader和Writer则提供兼容Unicode与面向字符的I/O功能。
2、InputStreamReader可以把InputStream转换为Reader。OutputStreamWriter可以把OutputStream转换为writer。
18.4.1数据的来源和去处
18.4.2更改流的行为
18.5自我独立的类RandomAccessFile
1、适用于由大小已知的记录组成的文件,可以使用seek()将记录从一处转移到另一处,然后读取或者修改记录。文件中记录的大小不一定相同,只要能够确定那些记录有多大以及它们在文件中的位置即可。
2、只有RandomAccessFile支持搜索方法,并且只适用于文件。
18.6I/O流的典型使用方式。
18.6.1缓冲输入文件

package com18;

import java.io.BufferedReader;
import java.io.FileReader;

/**
 * Created by Panda on 2018/5/18.
 */
public class BufferInputFile {
    public static String read(String filename) throws Exception{
        BufferedReader bufferedReader  = new BufferedReader(new FileReader(filename));
        String s;
        StringBuffer stringBuffer = new StringBuffer();
        while ((s=bufferedReader.readLine())!=null)
            stringBuffer.append(s+"\n");
        bufferedReader.close();
        return stringBuffer.toString();
    }

    public static void main(String[] args) throws Exception{
        System.out.println(read("BufferInputFile.java"));

    }
}

18.6.2 从内存输入

public class MemoryInput {
    public static void main(String[] args) throws Exception{
        StringReader stringReader = new StringReader(BufferInputFile.read("MemoryInput.java"));
        int c;
        while((c=stringReader.read())!=-1){
            System.out.println((char)c);
        }
    }
}

18.6.3格式化的内存输入
1、available()的工作方式会随着所读取的媒介类型的不同而有所不同;字面意思就是“在没有阻塞的情况下所能读取的字节数”。对于文件,这意味着整个文件;但是对于不同类型的流,可能就不是这样的,因此要谨慎使用。
2、也可以通过捕获异常来检测输入的末尾。但是,使用异常进行流控制,被认为是对异常特性的错误使用。
18.6.4基本的文件输出
1、FileWriter对象可以向文件写入数据。首先创建一个与制定文件连接的FileWriter。
18.6.5 存储和恢复数据
1、

package com18;

import java.io.*;

/**
 * Created by Panda on 2018/5/20.
 */
public class StringAndRecoveringData {
    public static void main(String[] args) throws Exception{
        DataOutputStream  dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
        dataOutputStream.writeDouble(3.14259);
        //Unicode 编码
        dataOutputStream.writeUTF("milk");
        dataOutputStream.close();

        DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
        System.out.println(dataInputStream.readDouble());
        System.out.println(dataInputStream.readUTF());
    }
}

18.6.6读写随机访问文件
18.6.7 管道流
1、PipedInputStream PipedOutStream PipedReader PipedWriter 管道流用于任务之间的通信。
18.7文件读写的实用工具
1、

package com18;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;

/**
 * Created by Panda on 2018/5/20.
 */
public class TextFile extends ArrayList<String>{
    public static  String read(String fileName){
        StringBuffer stringBuffer = new StringBuffer();
        try{
            BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(fileName).getAbsoluteFile()));
            try{
                String s;
                while((s=bufferedReader.readLine())!=null){
                    stringBuffer.append(s);
                    stringBuffer.append("\n");
                }
            }finally {
                bufferedReader.close();
            }
        }catch (IOException e){
            throw  new RuntimeException(e);
        }
        return stringBuffer.toString();
    }
    public static void write(String fileNam,String text){
        try{
            PrintWriter printWriter = new PrintWriter(new File(fileNam).getAbsoluteFile());
            try{
                printWriter.print(text);
            }finally {
                printWriter.close();
            }
        }catch (IOException e){
            throw  new RuntimeException(e);
        }
    }

     //利用read()方法将文件转换成字符串,接着使用String.spilt()以换行符为界把结果划分成行。
     public TextFile(String fileName,String splitter){
        super(Arrays.asList(read(fileName).split(splitter)));
        if(get(0).equals("")) remove(0);
     }
     public TextFile(String fileName){
         this(fileName,"\n");
     }

     public void write(String fileName){
         try{
             PrintWriter printWriter = new PrintWriter(new File(fileName).getAbsoluteFile());
             try{
                 for(String item:this) printWriter.println(item);
             }finally {
                 printWriter.close();
             }
         }catch (IOException e){
             throw new RuntimeException(e);
         }
     }

    public static void main(String[] args) {
        String file = read("TextFile.java");
        write("test.txt",file);
        TextFile textFile = new TextFile("test.txt");
        textFile.write("test2.txt");
        TreeSet<String> words= new TreeSet<>(new TextFile("Text.java","\\W+"));
        System.out.println(words.headSet("a"));
    }
}

18.7.1 读取二进制文件
1

/**
 * Created by Panda on 2018/5/20.
 */
public class BinaryFile {
    public static byte[] read(File bFile) throws IOException{
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(bFile));
        try {
             //available()被用来产生恰当的数组尺寸
            byte[] bytes = new byte[bufferedInputStream.available()];
            bufferedInputStream.read(bytes);
            return bytes;
        }finally {
            bufferedInputStream.close();
        }
    }
    public static byte[] read(String bFile) throws IOException{
        return read(new File(bFile).getAbsoluteFile());
    }
}

18.8标准I/O
18.8.1从标准输入中读取
1、

public class Echo {
    public static void main(String[] args) throws Exception{
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String s ;
        while((s=bufferedReader.readLine())!=null&&s.length()!=0){
            System.out.println(s);
        }
    }
}

18.8.2将System.out 转换成PrintWriter

public class ChangeSystemOut {
    public static void main(String[] args) {
        //要使用有两个参数的PrintWriter的构造器,并将第二个参数设置为true,以便开启自动清空功能。
        PrintWriter printWriter = new PrintWriter(System.out,true);
        printWriter.println("hello world");
    }
}

18.8.3 标准I/O重定向
1、Java的System类提供了一些简单的静态方法调用,以允许我们对标准输入、输出和错误I/O流进行重定向。setIn(InputStream) setOut(PrintStream) setErr(PrintStream)
18.9进程控制
1、两种类型的错误:普通的导致异常的错误—对这些错误只需要重新抛出一个运行时异常,以及从进程自身的执行过程中产生的错误。

package com18;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * Created by Panda on 2018/5/20.
 */
public class OSExecute {
    public static void command(String command){
        boolean err=false;
        try{
            Process process = new ProcessBuilder(command.split(" ")).start();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String s;
            while((s=bufferedReader.readLine())!=null){
                System.out.println(s);
            }
            BufferedReader errors = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            while ((s=errors.readLine())!=null){
                System.out.println(s);
                err=true;
            }
        }catch (Exception e){
            if(!command.startsWith("CMD/C")){
                command("CMD/C"+command);
            }else {
                throw new RuntimeException(e);
            }
        }

    }
}

18.10 新I/O
1、速度的提高来自于所使用的结果更接近于操作系统执行I/O的方式:通道和缓冲器。通道要么从缓冲器获得数据,要么向缓冲器发送数据。

package com18;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by Panda on 2018/5/20.
 */
public class GetChannel {
    private static final int Bsize=1024;
    public static void main(String[] args) throws Exception{
        FileChannel fc= new FileOutputStream("data.txt").getChannel();
        //warp()将已经存在的字节数组“包装”到ByteBuffer中
        fc.write(ByteBuffer.wrap("Some text".getBytes()));
        fc.close();

        fc=new RandomAccessFile("data.txt","rw").getChannel();
        //可以在文件内随意移动FileChannel
        fc.position(fc.size());  //move to end
        fc.write(ByteBuffer.wrap("Some more".getBytes()));
        fc.close();

        fc=new FileInputStream("data.txt").getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(Bsize);
        fc.read(buffer);
        buffer.flip();
        while (buffer.hasRemaining()){
            System.out.print((char) buffer.get());
        }
    }
    /**
     * Some textSome more
     */
}

18.10.1转换数据
18.10.2获取基本类型
1、ByteBuffer只能保存字节类型的数据,但是它具有可以从其所容纳的字节中产生各种不同基本类型值的方法。

package com18;

import java.nio.ByteBuffer;

/**
 * Created by Panda on 2018/5/20.
 */
public class GetData {
    private static final int BSIZE=1024;

    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(BSIZE);
        int i=0;
        while (i++<byteBuffer.limit()){
            if(byteBuffer.get()!=0) System.out.println("nonzero");
        }
        System.out.println("i= "+i);
        byteBuffer.rewind();


        byteBuffer.asCharBuffer().put("Howdy");
        char c;
        while ((c=byteBuffer.getChar())!=0) System.out.print(c);
        System.out.println();
        byteBuffer.rewind();

        byteBuffer.asShortBuffer().put((short)471142);
        System.out.println(byteBuffer.getShort());
        byteBuffer.rewind();

        byteBuffer.asIntBuffer().put(99471142);
        System.out.println(byteBuffer.getInt());
        byteBuffer.rewind();

        byteBuffer.asLongBuffer().put(99471142);
        System.out.println(byteBuffer.getLong());
        byteBuffer.rewind();

        byteBuffer.asFloatBuffer().put(99471142);
        System.out.println(byteBuffer.getFloat());
        byteBuffer.rewind();

    }
    /**
     * i= 1025
     Howdy
     12390
     99471142
     99471142
     9.9471144E7
     */
}

18.10.3视图缓冲器
1、视图缓冲器可以让我们通过某个特定的基本数据类型的视窗查看其底层的ByteBuffer。可以很方便地向ByteBuffer插入数据,还允许从ByteBuffer一次一个地或者成批地读取基本类型值。
2、一旦底层的ByteBuffer通过视图缓冲器填满了整数或其他基本类型时,就可以直接被写到通道中了。正像从通道中读取那样容易,然后使用视图缓冲器可以把任何数据都转换成某一特定的基本类型。
3、ByteBuffer通过一个被“包装”过的8字节数组产生,然后通过各种不同的基本类型的视图缓冲器显示了出来。
4、字节存放次序。不同的机器可能会使用不同的字节排序方法来存储数据。ByteBuffer是以高位有限的形式存储数据的。
18.10.4用缓冲器操纵数据
1、如果想把一个字节数组写到文件中去,就应该使用ByteBuffer.warp()方法把字节数组包装起来,然后用getChannel()方法在FileOutputStream上打开一个通道,接着将来自ByteBuffer的数据写到FileChannel中。
2、ByteBuffer是将数据移进移出通道的唯一方式,并且只能创建一个独立的基本类型缓冲器,或者使用”as”方法从ByteBuffer中获得。不能把基本类型的缓冲器转换成ByteBuffer
18.10.5 缓冲器的细节
1、Buffer由数据和可以高效地访问及操作这些数据的四个索引组成,这四个索引是;mark
(标记),postion(位置),limit(界限)和capacity(容量)。
mark() 将mark设置为positoon
positon() 返回pisition值
positon(int pos) 设置position值
18.10.6 内存映射文件
1、内存映射文件允许创建和修改因为太大而不能放入内存的文件。有了内存映射文件,就可以假定整个文件都在内存中,而且可以完全把它当做非常大的数组来访问。

package com18;

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by Panda on 2018/5/20.
 */
public class LargeMappedFiles {
    static int length=0x8FFFFFF;
  //映射文件访问 可以显著加快速度
    public static void main(String[] args) throws Exception{
        MappedByteBuffer 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');
        }
        System.out.println("Finished writing");
        for (int i = length/2; i <length/2+6 ; i++) {
            System.out.println((char)out.get(i));
        }
    }
}

18.10.7文件加锁
1、文件加锁机制允许同步访问某个作为共享资源的文件。竞争同一个文件的两个线程可能在不同的Java虚拟机上;或者一个是Java线程,另一个是操作系统中其他的某个本地线程。文件锁对其他的操作系统进程是可见的。

package com18;

import java.io.FileOutputStream;
import java.nio.channels.FileLock;
import java.util.concurrent.TimeUnit;

/**
 * Created by Panda on 2018/5/20.
 */
public class FileLocking {
    public static void main(String[] args) throws Exception{
        FileOutputStream fileOutputStream = new FileOutputStream("file.txt");
        //tryLock()是非阻塞的  lock()是阻塞的
        FileLock fileLock=fileOutputStream.getChannel().tryLock();
        if(fileLock!=null){
            System.out.println("Locked File");
            TimeUnit.MILLISECONDS.sleep(100);
            //释放锁
            fileLock.release();
            System.out.println("Released Lock");
        }
        fileOutputStream.close();
    }
}

2、可以使用如下方法对文件的一部分上锁:
tryLock(long position,long size,boolean shared)或者lock(long position,long size,boolean shared)其中,加锁的区域由size_position决定。第三个参数指定是否是共享锁。
3、五参数的加锁方法将根据文件尺寸的变化而变化,但是具有固定尺寸的锁不随文件尺寸的变化而变化。如果获得了某一区域上(position 到position+size)的锁,当文件增大超出
Position+size时,那么在position+size之外的部分不会被锁定。无参数的加锁方法会对整个文件进行加锁,甚至文件变大之后也是如此。对独占锁或者共享锁的支持必须由底层的操作系统提供。如果操作系统不支持共享锁并为每一个请求都创建一个锁,那么就会使用独占锁。锁的类型(共享或独占)可以通过FileLock.isShared()进行查询。
18.11 压缩
1、Java I/O类库中的类支持读写压缩格式的数据流。可以用它们对其他的I/O类进行封装,以提供压缩功能。
18.11.1用GZIP进行简单压缩
18.11.2用Zip进行多文件保存
1、GZIP或Zip库的使用并不仅仅局限于文件—它可以压缩任何东西,包括需要通过网络发送的数据。
18.11.3Java档案文件
1、Zip格式也被应用于JAR文件格式中。这种文件格式就像Zip一样,可以将一组文件压缩到单个压缩文件中。同Java文件中其他任何东西一样,JAR文件是跨平台的。声音和图像文件可以像类文件一样被包含在其中。
2、一个JAR文件由一组压缩文件构成。
18.12对象序列化
1、Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
2、“持久性”意味着一个对象的生存周期并不取决于程序是否正在执行,它可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后在重新调用程序时恢复该对象,就能够实现持久性的效果。
3、对象序列化的概念支持两种主要。一是 Java的远程方法调用,它使存活于其他计算机上的对象使用起来就像是存活于本机上一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。二是对 Java Beans来说,对象的序列化也是必需的。
18.12.1 寻找类
18.12.2序列化的控制
1、如果要考虑特殊的安全问题,而且不希望对象的某一部分被序列化;或者一个对象被还原以后,某个对象需要重新创建,从而不必将该子对象序列化。
2、通过实现Externalizable接口—–代替实现Serializable接口,来对序列化过程进行控制。这个Externalizable接口继承了Serializable接口,同时还增添了两个方法;writeExtrenal()和readExtrenal()这两个办法会在序列化和反序列化还原的过程中被自动调用。
3、对于一个Externalizable()对象,所有普通的默认构造器都会被调用,才能使Externalizable对象产生正确的行为。
4、Transient(瞬时)关键字 。当对序列化进行控制时,可能某个特定子对象不想让Java的序列化机制自动保存与恢复。如果子对象表示的是不希望将其序列化的敏感信息,通常就会面临这种情况。即使对象中的这些信息是private(私有)属性,一经序列化处理,就可以通过读取文件或者拦截网络传输的方式来访问到它。
5、有一种办法可防止对象的敏感部分被序列化,就是将类实现为Externalizable。没有任何东西可以自动序列化,并且可以在writeExternal()内部只对所需部分进行显示的序列化。
6、如果正在操作的是一个Serializable对象,那么所有序列化操作都会自动进行。为了能够予以控制,可以用予以控制,可以用transient(瞬时)关键字逐个字段地关闭序列化,它的意思是“不用麻烦保存或恢复数据—–会自己处理的”
7、Externalizable的替代方法
可以实现Serializable接口,并添加名为writeObject()和readObject()的方法。这样一旦对象被序列化或者反序列化还原,就会自动分别调用这两个方法。也就是说,只要提供了这两个方法,就会使用它们而不是默认的序列化机制。

package com18;

import java.io.*;

/**
 * Created by Panda on 2018/5/20.
 */
public class SerialCtl implements Serializable{
   private String a;
   //transient 必须在程序中明确保存和恢复
   private transient String b;
   public SerialCtl(String aa,String bb){
       a="not transient: "+aa;
       b="transient: "+bb;
   }
   public String toString(){return a+"\n"+b;}
   private void writeObject(ObjectOutputStream stream) throws IOException,ClassNotFoundException{
       stream.defaultWriteObject();
       stream.writeObject(b);
   }

   private void readObject(ObjectInputStream stream) throws IOException,ClassNotFoundException{
       stream.defaultReadObject();
       b=(String)stream.readObject();
   }

    public static void main(String[] args) throws IOException,ClassNotFoundException  {
        SerialCtl serialCtl = new SerialCtl("Test1","Test2");
        System.out.println("Before:\n"+serialCtl);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(serialCtl);

        ObjectInputStream inputStream=new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
        SerialCtl serialCtl1 =(SerialCtl)inputStream.readObject();
        System.out.println("After: \n"+serialCtl1);
    }
    /**
     * Before:
     not transient: Test1
     transient: Test2
     After:
     not transient: Test1
     transient: Test2
     */
}

18.12.3使用“持久性”
18.13XML
1、只有Java程序才能反序列化这种对象。一种更具互操作性的解决方案是将数据转换为XML格式,可以使其被各种各样的平台和语言使用。
18.14Perferences
1、Perferences是一个键值集合(类似映射),存储在一个节点层次结构中,尽管节点层次结构可用来创建更为复杂的结构,但通常是创建以类名明明的单一节点,然后将信息存储其中。
18.15总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值