• Thinking in java Chapter18 IO


    1 File类

    File这个名字并非指代文件,它既能代表一个特定的文件,又能代表一个目录下的文件集合。如果指代的是文件集合的话,可以调用list()方法得到一个包含该目录下文件集合的数组。

    1.1 目录列表器

    查看一个目录列表,有两种方法:
    1.调用不带参数的list()获取全部文件的集合
    2.使用“目录过滤器”获得符合条件的文件集合

     package io;
    
    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Arrays;
    import java.util.regex.Pattern;
    
    // args: .*.java
    
    public class DirList {
        public static void main(String[] args) {
    //        File path = new File(".");
            File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
            String[] list;
            if (args.length== 0)
                list = path.list();//指定目录的全部列表
            else
                list = path.list(new DirFilter(args[0]));//指定目录的受限列表,使用FilenameFilter 筛选器
            Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
            for (String dirItem: list)
                System.out.println(dirItem);
        }
    }
    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();
        }
    }
    
    
    list方法 会将该目录下的每个文件调用accept,来判断该文件是否包含在内。
        public String[] list(FilenameFilter filter) {
            String names[] = list();
            if ((names == null) || (filter == null)) {
                return names;
            }
            List<String> v = new ArrayList<>();
            for (int i = 0 ; i < names.length ; i++) {
                if (filter.accept(this, names[i])) {
                    v.add(names[i]);
                }
            }
            return v.toArray(new String[v.size()]);
        }
    

    匿名内部类改写

    package io;
    
    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Arrays;
    import java.util.regex.Pattern;
    
    // args: .*.java
    
    public class DirList2 {
        public static FilenameFilter filter(String regex){ //编译器默认会给匿名内部类的外部变量
            return new FilenameFilter() {
                private Pattern pattern = Pattern.compile(regex);
                @Override
                public boolean accept(File dir, String name) {
                    return pattern.matcher(name).matches();
                }
            };
    
        }
        public static void main(String[] args) {
            File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
            String[] list;
            if (args.length== 0)
                list = path.list();//指定目录的全部列表
            else
                list = path.list(filter(args[0]));//指定目录的受限列表,使用FilenameFilter 筛选器
            Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
            for (String dirItem: list)
                System.out.println(dirItem);
        }
    }
    
    
    package io;
    
    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Arrays;
    import java.util.regex.Pattern;
    
    
    // args: .*.java
    
    
    public class DirList3 {
        public static void main(String[] args) {
            File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
            String[] list;
            if (args.length== 0)
                list = path.list();//指定目录的全部列表
            else
                list = path.list(new FilenameFilter() {
                    private Pattern pattern = Pattern.compile(args[0]);
                    
                    @Override
                    public boolean accept(File dir, String name) {
                        return pattern.matcher(name).matches();
                    }
                });//指定目录的受限列表,使用FilenameFilter 筛选器
            Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
            for (String dirItem: list)
                System.out.println(dirItem);
        }
    
    }
    
    优点:代码隔离,聚拢
    缺点:不易阅读,谨慎使用
    
    作业1
    package io.e1;
    
    import net.mindview.util.TextFile;
    
    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    import java.util.regex.Pattern;
    
    
    // args: .*.java
    
    
    public class DirList3 {
        public static void main(String[] args) {
    //        File path = new File(".");
            File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
            String[] list;
            if (args.length == 0)
                list = path.list();//指定目录的全部列表
            else
                list = path.list(new FilenameFilter() {
                    // 只分析指定后缀的文件,否则对于目录,需要额外处理
                    private String ext = args[0].toLowerCase();
                    @Override
                    public boolean accept(File dir, String name) {
                        if (name.toLowerCase().endsWith(ext)){
                            //只过滤指定文件类型
                            if (args.length == 1)
                                return true;
                            Set<String> words = new HashSet<>(new TextFile(new File(dir, name).getAbsolutePath(), "\W+"));
                            for (int i = 1;i < args.length;i++)// 除第一个参数为后缀,尾随参数,是需要遍历检查,是否在文件中
                                if (words.contains(args[i]))
                                    return true;
                        }
                        return false;
                    }
                });//指定目录的受限列表,使用FilenameFilter 筛选器
            Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
            for (String dirItem : list)
                System.out.println(dirItem);
        }
    
    }
    
    
    package io.e2;
    
    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Arrays;
    import java.util.regex.Pattern;
    
    public class SortedDirList {
        private File path;
    
        public SortedDirList() {
            path = new File(".");
        }
    
        public SortedDirList(File path) {
            this.path = path;
        }
    
        String[] list() {
            String[] list = path.list();
            Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
            return list;
        }
    
        String[] list(String regex) {
            String[] list = path.list(new FilenameFilter() {
                private Pattern pattern = Pattern.compile(regex);
    
                @Override
                public boolean accept(File dir, String name) {
                    return pattern.matcher(name).matches();
                }
            });
            Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
            return list;
        }
    
        public static void main(String[] args) {
            SortedDirList dir = new SortedDirList();
            System.out.println((Arrays.asList(dir.list(".*\.java"))));
        }
    }
    
    package io.e3;
    
    import java.io.File;
    import java.io.FilenameFilter;
    import java.util.Arrays;
    import java.util.regex.Pattern;
    
    // args: .*.java
    
    public class DirList3 {
        public static void main(String[] args) {
            File path = new File("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io");
            String[] list;
            if (args.length == 0)
                list = path.list();//指定目录的全部列表
            else
                list = path.list(new FilenameFilter() {
                    private Pattern pattern = Pattern.compile(args[0]);
    
                    @Override
                    public boolean accept(File dir, String name) {
                        return pattern.matcher(name).matches();
                    }
                });//指定目录的受限列表,使用FilenameFilter 筛选器
            long total = 0;
            long fs;
            for (String dirItem : list) {
                fs = new File(path, dirItem).length();
                System.out.println(dirItem + ", " + fs + " bytes");
                total += fs;
            }
            System.out.println("=========");
            System.out.println(list.length + "files(s)," + total + " bytes");
        }
    }
    
    

    1.2 目录实用工具

    package io;
    
    import net.mindview.util.PPrint;
    
    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;
    
    public final class Directory {
    
        public static File[]
        local(File dir,final String regex){
            return dir.listFiles(new FilenameFilter() {
                private Pattern pattern = Pattern.compile(regex);
                @Override
                public boolean accept(File dir, String name) {
                    return pattern.matcher(new File(name).getName()).matches();
                }
            });
        }
    
        // Overloaded
        public static File[]
        local(String path,final String regex){
            return local(new File(path),regex);
        }
    
        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(); //默认迭代是file
            }
    
            void addAll(TreeInfo other) {
                files.addAll(other.files);
                files.addAll(other.dirs);
            }
    
            public String toString() {
                return "dirs: " + PPrint.pformat(dirs) +
                        "
    
    files:: " + PPrint.pformat(files);
            }
        }
    
        public static TreeInfo walk(String start,String regex){
            return reCurseDirs(new File(start),regex);
        }
    
        public static TreeInfo walk(File start){
            return reCurseDirs(start,".*");
        }
    
        public static TreeInfo walk(String start) {
            return reCurseDirs(new File(start),".*");
        }
    
    
        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 void main(String[] args) {
            if (args.length == 0)
                System.out.println(walk("."));
            else
                for (String arg:args)
                    System.out.println(walk(arg));
        }
    }
    
    

    策略模式,处理目录中的文件

    package io;
    
    import java.io.File;
    import java.io.IOException;
    
    public class ProcessFiles {
        public interface Strategy {
            void process(File file);
        }
    
        private Strategy strategy;
        private String ext;
    
        public ProcessFiles(Strategy strategy, String ext) {
            this.strategy = strategy;
            this.ext = ext;
        }
    
        public void start(String[] args) {
            try {
                if (args.length == 0)
                    processDirectoryTree(new File("."));
                else for (String arg : args) {// 指定一个或多个目录,或指定特定文件
                    File fileArg = new File(arg);
                    if (fileArg.isDirectory()) // 目录
                        processDirectoryTree(fileArg);
                    else {// 文件
                        // Allow user to leave off extension:
                        if (!arg.endsWith("." + ext)) //文件没有扩展名,给加上
                            arg += "." + ext;
                        strategy.process(new File(arg).getCanonicalFile());
                    }
    
                }
            }catch (IOException e){
                throw new RuntimeException(e);
            }
        }
    
        public void processDirectoryTree(File root) throws IOException {
            for (File file: Directory.walk(root.getAbsolutePath(),".*\." + ext))
                strategy.process(file.getCanonicalFile());
    
        }
    
        public static void main(String[] args) {
            new ProcessFiles(new Strategy() {
                @Override
                public void process(File file) {
                    System.out.println(file);
                }
            }, "java").start(args);
        }
    }
    
    
    作业4
    package io.e4;
    
    import io.Directory;
    import java.io.File;
    
    // args: .*.java
    public class E4 {
        public static void main(String[] args) {
            Directory.TreeInfo ti;
            String start = new File(".").getAbsolutePath()+"/src/main/java/io";
    
            if (args.length == 0)
                ti = Directory.walk(start);
            else
                ti = Directory.walk(start,args[0]);
            long total = 0;
            for (File file: ti)
                total += file.length();
            System.out.println( ti.files.size() + " file(s), " + total + "bytes");
        }
    }
    

    1.3目录的检查及创建

    package io;
    
    import java.io.File;
    
    // {Args: MakeDirectoriesTest}
    public class MakeDirectories {
        private static void usage() {
            System.err.println(
                    "Usage:MakeDirectories path1 ... 
    " +
                            "Creates each path
    " +
                            "Usage:MakeDirectories -d path1 ...
    " +
                            "Deletes each path
    " +
                            "Usage:MakeDirectories -r path1 path2
    " +
                            "Renames from path1 to path2");
            System.exit(1);
    
        }
    
        private static void fileData(File f) {
            System.out.println(
                    "Absolute path: " + f.getAbsolutePath() +
                            "
     Can read: " + f.canRead() +
                            "
     Can write: " + f.canWrite() +
                            "
     getName: " + f.getName() +
                            "
     getParent: " + f.getParent() + //路径名是MakeDirectoriesTest,从这个路径字符串解析不出来上级路经 所以是null
                            "
     getPath: " + f.getPath() +
                            "
     length: " + f.length() +
                            "
     lastModified: " + f.lastModified());
            if (f.isFile())
                System.out.println("It's a file");
            else if (f.isDirectory())
                System.out.println("It's a directory.");
        }
    
        public static void main(String[] args) {
            if (args.length < 1) usage();
            if (args[0].equals("-r")) { // rename
                if (args.length != 3) usage(); // 需要三个参数,若参数数量不正确,告知usage,退出
                File
                        old = new File(args[1]),// 源文件
                        rname = new File(args[2]);// 重命名文件
                old.renameTo(rname);//重命名
                fileData(old);//被删除的文件信息
                fileData(rname);//新文件信息
                return;//Exit main
            }
            int count = 0;
            boolean del = false;
            if (args[0].equals("-d")) {//删除标记
                count++;
                del = true;
            }
            count--; //将删除 和 创建dir 统一处理
            while (++count < args.length) {
                File f = new File(args[count]);
                if (f.exists()) {
                    System.out.println(f + " exists");
                    if (del) {
                        System.out.println("deleting..." + f);
                        f.delete();
                    }
                } else {// 不存在
                    if (!del) {//不是删除,也就是 mkdir
                        f.mkdirs();
                        System.out.println("created " + f);
                    }
                }
                fileData(f);
            }
        }
    }
    
    
    /*
    
    args: -d /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1 /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
    
    /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1 exists
    deleting.../Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
    Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
     Can read: false
     Can write: false
     getName: test1
     getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
     getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
     length: 0
     lastModified: 0
    /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2 exists
    deleting.../Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
    Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
     Can read: false
     Can write: false
     getName: test2
     getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
     getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test2
     length: 0
     lastModified: 0
    
    
    args: -r /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
    
    Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test
     Can read: false
     Can write: false
     getName: test
     getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
     getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test
     length: 0
     lastModified: 0
    Absolute path: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
     Can read: true
     Can write: true
     getName: test1
     getParent: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io
     getPath: /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test1
     length: 26
     lastModified: 1576557859000
    It's a file
    
    
    args:   -d MakeDirectoriesTest
    
    MakeDirectoriesTest exists
    deleting...MakeDirectoriesTest
    Absolute path: /Users/erin/JavaProject/thinking_in_java_example/MakeDirectoriesTest
     Can read: false
     Can write: false
     getName: MakeDirectoriesTest
     getParent: null
     getPath: MakeDirectoriesTest
     length: 0
     lastModified: 0
    Disconnected from the target VM, address: '127.0.0.1:60489', transport: 'socket'
    
    
    args:   MakeDirectoriesTest
    
    Connected to the target VM, address: '127.0.0.1:60500', transport: 'socket'
    created MakeDirectoriesTest
    Absolute path: /Users/erin/JavaProject/thinking_in_java_example/MakeDirectoriesTest
     Can read: true
     Can write: true
     getName: MakeDirectoriesTest
     getParent: null
     getPath: MakeDirectoriesTest
     length: 64
     lastModified: 1576562665000
    It's a directory.
    
    再次运行
    
     */
    

    2 输入和输出

    Java中“流”类库让人迷惑的主要原因就在于:创建单一的结果流,却需要创建多个对象。

    2.1 InputStream类型

    6 典型的I/O流使用方式

    6.1 缓冲输入文件

    package io;
    
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class BufferedInputFile {
        public static String read(String filename) throws IOException {
            // 逐行读入
    //        public class FileReader extends InputStreamReader
    //        public class InputStreamReader extends Reader
            BufferedReader in =new BufferedReader(new FileReader(filename));//提高速度,对文件进行缓冲
            String s;
            StringBuilder sb = new StringBuilder();
            while ((s = in.readLine())!=null)
                sb.append(s + "
    ");// readline 已经将
    删掉,故需要 添加换行符
            in.close(); // 显式调用close
            return sb.toString();
        }
    
        public static void main(String[] args) throws IOException {
            System.out.println(read("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/BufferedInputFile.java"));
        }
    }
    
    

    6.2从内存输入

    从内存读入字符串

    package io;
    
    import java.io.IOException;
    import java.io.StringReader;
    
    // public class StringReader extends Reader
    // public StringReader(String s)
    public class MemoryInput {
        public static void main(String[] args) throws IOException {
            StringReader in = new StringReader(BufferedInputFile.read("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/MemoryInput.java"));
            int c;
            while ((c = in.read()) != -1)
                System.out.print((char)c);
        }
    }
    
    

    6.3 格式化的内存输入

    package io;
    
    import java.io.ByteArrayInputStream;
    import java.io.DataInputStream;
    import java.io.IOException;
    
    public class FormattedMemoryInput {
        public static void main(String[] args) {
            try {
                DataInputStream in = new DataInputStream(
                        new ByteArrayInputStream(
                                BufferedInputFile.read(
                                "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/FormattedMemoryInput.java").getBytes()));
                while (true)
                    System.out.print((char)in.readByte());
            } catch (IOException e){
                System.err.println("End of stream");
            }
        }
    }
    
    
    package io;
    
    import java.io.*;
    
    public class TestEOF {
        public static void main(String[] args) throws IOException {
            DataInputStream in = new DataInputStream(
                    new BufferedInputStream(
                            new FileInputStream("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/TestEOF.java")));
            while (in.available() != 0)
                System.out.print((char)in.readByte());
        }
    }
    
    

    6.4 基本的文件输出

    PrintWriter

    package io;
    
    import java.io.*;
    
    public class BasicFileOutput {
        static String fileJava = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/BasicFileOutput.java";//读入文件
        static String fileOutput = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/BasicFileOutput.out";//输出文件
    
        public static void main(String[] args) throws IOException {
            BufferedReader in = new BufferedReader(
                    new StringReader(
                            BufferedInputFile.read(fileJava)
                    )
            );
    
            PrintWriter out = new PrintWriter(
                    new BufferedWriter(new FileWriter(fileOutput))
            );
            int lineCount = 1;
            String s;
            while ((s = in.readLine())!= null)
                out.println(lineCount++ + ": " + s);
            out.close();//显式调用close,若不close,缓冲区内容不会刷新清空。它们就不完整。
            in.close(); // 关闭 源文件
            System.out.println(BufferedInputFile.read(fileOutput));
        }
    }
    /*
    LineNumberReader 是个 silly class 没有用。
    记录行号很容易。
     */
    

    文本文件输出的快捷方式

    同上,但其他常见的写入任务 没有快捷方式

    package io;
    
    import chapter6access.Print;
    
    import java.io.*;
    
    public class FileOutputShortcut {
        static String base = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/";
    
        static String file = base + "FileOutputShortcut.out";
        static String fileJava = base + "FileOutputShortcut.java";
    
        public static void main(String[] args) throws IOException {
            BufferedReader in = new BufferedReader(
                    new StringReader(
                            BufferedInputFile.read(fileJava)));
            // shortcut
            PrintWriter out = new PrintWriter(file);
            /*
                public PrintWriter(String fileName) throws FileNotFoundException {
            this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
                 false);
        }
             */
            int lineCount = 1;
            String s;
            while ((s = in.readLine()) != null)
                out.println(lineCount++ + ": " + s);
            out.close();
            System.out.println(BufferedInputFile.read(file));
            in.close();
        }
    
    }
    
    

    写入文件,有无IO的比较

    package io.e14;
    
    import io.e7.E7;
    
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.List;
    
    public class E14_BufferPerformance {
        static String base = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/e14/";
    
        static String fileOutput = base + "E14_BufferPerformance.out";
        static String fileJava = base + "E14_BufferPerformance.java";
    
        public static void main(String[] args)
                throws IOException {
            List<String> list = E7.read(fileJava);
            PrintWriter out = new PrintWriter(
                    new BufferedWriter(new FileWriter(fileOutput)));
            int lineCount = 1;
            long t1 = System.currentTimeMillis();
            for(String s : list) {
                for(int i = 0; i < 10000; i++)
                    out.println(lineCount + ": " + s);
                lineCount++;
            }
            long t2 = System.currentTimeMillis();
            System.out.println("buffered: " + (t2 - t1));
            out.close();
    
            out = new PrintWriter(new FileWriter(fileOutput));
            lineCount = 1;
            t1 = System.currentTimeMillis();
            for(String s : list) {
                for(int i = 0; i < 10000; i++)
                    out.println(lineCount + ": " + s);
                lineCount++;
            }
            t2 = System.currentTimeMillis();
            System.out.println("unbuffered: " + (t2 - t1));
            out.close();
        }
    }
    /*
    buffered: 104
    unbuffered: 227
     */
    

    6.5 存储和恢复数据

    package io;
    
    import java.io.*;
    
    public class StoringAndRecoveringData {
        static String base = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/";
    
        static String file = base + "test0";
    
    
        public static void main(String[] args) throws IOException {
            DataOutputStream out = new DataOutputStream(
                    new BufferedOutputStream(
                            new FileOutputStream(file))); //创建文件
            out.writeDouble(3.14159);
            out.writeUTF("That was pi");
            out.writeDouble(1.41413);
            out.writeUTF("Square root of 2");
            out.close();
    
            DataInputStream in = new DataInputStream(
                    new BufferedInputStream(
                            new FileInputStream(file)));
            System.out.println(in.readDouble());//按存的顺序读取
            System.out.println(in.readUTF());
            System.out.println(in.readDouble());
            System.out.println(in.readUTF());
        }
    }
    /*
    DataInputStream DataOutputStream 面向字节流,使用OutputStream InputStream
    这种方式不常用。
    
    3.14159
    That was pi
    1.41413
    Square root of 2
     */
    
    http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
    UTF-8 的编码规则很简单,只有二条:
    
    1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
    
    2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
    
    
    UTF-8 的编码
     
    Unicode符号范围     |        UTF-8编码方式
    (十六进制)          |              (二进制)
    ----------------------+---------------------------------------------
    0000 0000-0000 007F | 0xxxxxxx
    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    
       static int writeUTF(String str, DataOutput out) throws IOException {
            int strlen = str.length();
            int utflen = 0;
            int c, count = 0;
    
            /* use charAt instead of copying String to char array */
            for (int i = 0; i < strlen; i++) {
                c = str.charAt(i);
                if ((c >= 0x0001) && (c <= 0x007F)) {
                    utflen++;
                } else if (c > 0x07FF) {
                    utflen += 3;
                } else {
                    utflen += 2;
                }
            }
    
            if (utflen > 65535)
                throw new UTFDataFormatException(
                    "encoded string too long: " + utflen + " bytes");
    
            byte[] bytearr = null;
            if (out instanceof DataOutputStream) {
                DataOutputStream dos = (DataOutputStream)out;
                if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
                    dos.bytearr = new byte[(utflen*2) + 2];
                bytearr = dos.bytearr;
            } else {
                bytearr = new byte[utflen+2];
            }
            
            
            // 字节数组 的前两个字节,保存UTF-8的长度
            bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
            bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
    
            // 单字节预处理
            int i=0;
            for (i=0; i<strlen; i++) {
               c = str.charAt(i);
               if (!((c >= 0x0001) && (c <= 0x007F))) break;
               bytearr[count++] = (byte) c;
            }
    
            // 预处理后,数据处理
            for (;i < strlen; i++){
                c = str.charAt(i);
                if ((c >= 0x0001) && (c <= 0x007F)) {
                    bytearr[count++] = (byte) c;
    
                } else if (c > 0x07FF) {
                    bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                    bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
                    bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
                } else {
                    bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
                    bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
                }
            }
            out.write(bytearr, 0, utflen+2);
            return utflen + 2;
        }
    
    

    6.6 读写随机访问文件

    6.7 管道流

    21章 多线程

    7 文件读写的使用工具

    8 标准I/O

    8.1 从标准输入中读取

    System.in public final static InputStream in = null;

    System.out public final static PrintStream out = null;

    System.err public final static PrintStream err = null;

    package io;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class Echo {// 回显输入的每一行
        public static void main(String[] args) throws IOException {
            BufferedReader stdin = new BufferedReader(
                  new InputStreamReader(System.in));
            String s;
            while ((s = stdin.readLine()) != null && s.length() != 0)
                System.out.println(s);
        }
    }
    

    8.2 将System.out 转换成 PrinterWriter

    package io;
    
    import java.io.PrintWriter;
    
    public class ChangeSystemOut {
        public static void main(String[] args) {
            PrintWriter out = new PrintWriter(System.out,true);//打印流是输出流的子类,true 自动清空功能
            out.println("hello,world");
        }
    }
    
    

    8.标准I/O重定向

    import java.io.*;
    
    public class Redirecting {
        static String filePath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Redirecting.java";
        public static void main(String[] args) throws IOException { // io 操纵字节流
            PrintStream console = System.out;
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(filePath));
            PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.out")));
            System.setIn(in); // 重定向
            System.setOut(out);// 重定向
            System.setErr(out);// 重定向
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String s;
            while ((s = br.readLine())!= null)
                System.out.println(s);
            out.close();// 输出流关闭
            System.setOut(console);// 改回来
        }
    }
    
    

    9 进程控制

    package io;
    
    public  class OSExcuteException extends RuntimeException{ // 继承运行时异常
        public OSExcuteException(String why){
            super(why);
        }
    }
    
    package io;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    public  class OsExecute {
        public static void command(String command){
            boolean err = false; //  命令执行 过程中,是否有错
            try {
                Process process = new ProcessBuilder(command.split(" .")).start();
    
                BufferedReader results = new BufferedReader(
                        new InputStreamReader(process.getInputStream()));// 子进程的输入流,包装带缓冲的读取器
                String s;
                while ((s = results.readLine()) != null) // 读到输入流的内容
                    System.out.println(s);
    
                BufferedReader errors = new BufferedReader(// 错误流
                        new InputStreamReader(process.getErrorStream()));
                while ((s = errors.readLine()) != null) {
                    System.err.println(s);
                    err = true;
                }
    
            } catch (Exception e) {
                if(! command.startsWith("CMD /c "))
                    command("CMD /C " + command);
                else
                    throw new RuntimeException(e);
            }
            if (err)
                throw new OSExcuteException("Errors executing " + command); // 抛出自定义异常
        }
    }
    
    
    package io;
    
    public class OsExecuteDemo {
        public static void main(String[] args) {
            OsExecute.command("ls");
            //        OsExecute.command("javap /Users/erin/JavaProject/thinking_in_java_example/src/main/java/jvm/OsExecuteDemo");
        }
    }
    
    

    10 新 I/O

    NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。

    传统IO 基于字节流和字符流进行操作,

    NIO 基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。

    演示三种类型的流,用以产生可写,可读可写,可读的通道

    package io;
    
    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class GetChannel {
        private static final int BSIZE = 1024; // 1K
        static String filePath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/data.txt";
    
        public static void main(String[] args) throws IOException {
            // 写文件
            FileChannel fc = new FileOutputStream(filePath).getChannel();
            fc.write(ByteBuffer.wrap("Some text ".getBytes()));
            fc.close();
    
            // 追加文件
            fc = new RandomAccessFile(filePath,"rw").getChannel();
            fc.position(fc.size());//移动FileChannel
            fc.write(ByteBuffer.wrap("Some more".getBytes()));
            fc.close();
    
            // 只 读文件
            fc = new FileInputStream(filePath).getChannel();
            ByteBuffer buff = ByteBuffer.allocate(BSIZE);
            fc.read(buff);
            buff.flip();
            while (buff.hasRemaining())
                System.out.print((char) buff.get());
        }
    }
    
    

    简单的文件复制

    package io;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    // {Args:/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/ChannelCopy.java /Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.txt }
    public class ChannelCopy {
        private static final int BSIZE = 1024;
    
        public static void main(String[] args) throws IOException {
            if (args.length != 2){
                System.out.println("Arguments: sourcefile destfile");
                System.exit(1);
            }
    
            FileChannel
                    in = new FileInputStream(args[0]).getChannel(),
                    out = new FileOutputStream(args[1]).getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
            while (in.read(buffer) != -1){
                buffer.flip(); // 准备读
                out.write(buffer);
                buffer.clear();//准备写
            }
        }
    }
    
    

    上述不是处理此类操作的理想方式。transferTo transferFrom将一个通道和另一个通道相连

    package io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.channels.FileChannel;
    
    public class TransferTo {
        static String srcPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/TransferTo.java";
        static String desPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/TransferTo.txt";
    
        public static void main(String[] args) throws IOException {
            FileChannel
                    in = new FileInputStream(srcPath).getChannel(),
                    out = new FileOutputStream(desPath).getChannel();
            in.transferTo(0,in.size(),out);
    //        out.transferFrom(in,0,in.size());
        }
    }
    
    

    10.1 转换数据

    GetChannel 是字节缓冲器

    10.2 获取基本类型

    10.3 视图缓冲器

    10.4 用缓冲器操纵数据

    10.5 缓冲器细节

    10.6 内存映射文件

    10.7 文件加锁

    11 压缩

    属于InputStream OutputStream继承层次结构,压缩类库,按字节方式,而不是字符方式处理。

    ZIP 和GZIP最常用

    11.1 用GZIP进行简单压缩

    单数据流进行压缩

    package io;
    
    import java.io.*;
    import java.util.zip.GZIPInputStream;
    import java.util.zip.GZIPOutputStream;
    
    //{Args:/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/GZIPcompress.java}
    public class GZIPcompress {
        static String gzFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.gz";
        public static void main(String[] args) throws IOException {
    
            if (args.length == 0){
                System.out.println(
                        "Usage: 
    GZIPcompress file
    " +
                                "	Uses GZIP compression to compress " +
                                "the file to test.gz");
                System.exit(1);
            }
    
    
            // 1. 被压缩的文件
            BufferedReader in = new BufferedReader(
                    new FileReader(args[0]));
    
            // 2. 生成压缩文件 将输出流 封装成 GZIPOutputStream
            BufferedOutputStream out = new BufferedOutputStream(
                    new GZIPOutputStream(
                            new FileOutputStream(gzFile)));
    
            // 写入压缩文件
            System.out.println("Writing file");
            int c;
            while ((c = in.read())!= -1)
                out.write(c);
            in.close();
            out.close();
    
            // 读取压缩文件 将输入流 封装成 GZIPOutputStream
            System.out.println("Reading file");
            BufferedReader in2 = new BufferedReader(
                    new InputStreamReader(new GZIPInputStream(
                            new FileInputStream(gzFile))));
            String s;
            while ((s = in2.readLine())!= null)
                System.out.println(s);
        }
    }
    
    

    11.2 用Zip进行多文件保存

    Checksum 类 用来计算和校验文件的校验和的方法。有两种Checksum类型:Adler32(更快些)和 CRC32(慢一些,但更准确)

    package io;
    
    import java.io.*;
    import java.util.Enumeration;
    import java.util.zip.*;
    
    public class ZipCompress {
        static String zipFile= "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/test.zip";
        public static void main(String[] args) throws IOException {
            FileOutputStream f = new FileOutputStream(zipFile);
            // public class CheckedOutputStream extends FilterOutputStream 校验和 用于验证输出数据的完整性
            CheckedOutputStream csum = new CheckedOutputStream(f,new Adler32());
            ZipOutputStream zos = new ZipOutputStream(csum);
            BufferedOutputStream out = new BufferedOutputStream(zos);
    
            zos.setComment("A test of Java Zipping"); // 设置ZIP 文件注释
    
            for (String arg: args){
                System.out.println("Writing file "  + arg);
                BufferedReader in = new BufferedReader(new FileReader(arg));
                //开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处
                //ZipEntry是Java中进行压缩与解压缩的单位,它用来标记ZIP压缩文件中每个原始文件的入口
    
                zos.putNextEntry(new ZipEntry(arg));
                int c;
                while ((c = in.read()) != -1)
                    out.write(c);
                in.close();
                out.flush();
            }
            out.close();
    
            System.out.println("Checksum: " + csum.getChecksum().getValue());
    
            // 解压缩
            System.out.println("Reading file");
            FileInputStream fi = new FileInputStream(zipFile);
            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); //输出字符流
            }
    
            if (args.length == 1)
                System.out.println("Checksum: " + csumi.getChecksum().getValue());
            bis.close();
    
            // 另种方式 打开和读取zip文件 查看压缩文件的目录
            ZipFile zf = new ZipFile(zipFile);
            Enumeration e = zf.entries();
            while (e.hasMoreElements()){
                ZipEntry ze2 = (ZipEntry)e.nextElement();
                System.out.println("File: " + ze2);
                //...and extract the data as before
            }
            // if args.length == 1
          }
    }
    
    

    11.3 Java档案文件

    Zip格式应用于JAR(Java ARchive)文件格式中,JAR跨平台
    JAR文件 一组压缩文件构成,且有一张“文件清单”(自行创建或jar程序自动生成)

    Sun JDK自带jar程序 jar [options] destination [manifest] inputfile(s)
    jar cf myJarFile.jar *.class
    jar cmf myJarFile.jar myManifestFile.mf *.class 自建清单文件
    jar tf myJarFile.jar 产生所有文件的一个目录表
    jar tvf myJarFile.jar 详尽
    jar cvf myApp.jar audio classes image 将子目录合并到文件myAppljar中
    0选项创建JAR文件,文件可放入类路径变量(CLASSPATH)中

    12 对象序列化

    package io;
    
    import java.io.*;
    import java.util.Random;
    
    class Data implements Serializable{
        private int n;
        public Data(int n){this.n = n;}
        public String toString(){return Integer.toString(n);}
    
    }
    public class Worm  implements Serializable{
        private static Random rand = new Random(47);
        private Data[] d ={ // 数据成员也是可序列化
                new Data(rand.nextInt(10)),
                new Data(rand.nextInt(10)),
                new Data(rand.nextInt(10))
        };
        private Worm next;
        private char c;
        public Worm(int i,char x){
            System.out.println("Worm constructor: " + i);
            c = x;
            if (--i > 0)
                next = new Worm(i,(char)(x + 1));
        }
        public Worm(){
            System.out.println("Default constructor");
        }
        public String toString(){
            StringBuilder result = new StringBuilder(":");
            result.append(c);
            result.append("(");
            for (Data dat:d)
                result.append(dat);
            result.append(")");
            if (next != null)
                result.append(next);
            return  result.toString();
        }
    
        // 可序列化到文件或数据库
        static String wormOut = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Worm.out";
        public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            //
            Worm w = new Worm(6,'a');
            System.out.println("w = " + w);
    
            //读写文件
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(wormOut));
            out.writeObject("Worm storage
    ");
            out.writeObject(w);
            out.close();
    
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(wormOut));
            String s = (String)in.readObject();
            Worm w2 = (Worm)in.readObject();
            System.out.println(s + "w2 = " + w2);
    
            //读写字节数组
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            ObjectOutputStream out2 = new ObjectOutputStream(bout);
            out2.writeObject("Worm storage
    ");
            out2.writeObject(w);
            out2.flush();
    
            ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
            s = (String)in2.readObject();
            Worm w3 = (Worm)in2.readObject();
            System.out.println(s + "w3 = " + w3);
        }
    }
    
    

    12.1 寻找类

    package io;
    
    import java.io.*;
    
    public class Alien implements Serializable {
    }
    
    package io;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    
    public class FreezeAlien {
        static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/X.file";
        public static void main(String[] args) throws IOException {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(outFile));
            Alien auellek = new Alien();
            out.writeObject(auellek);
        }
    }
    

    保证java虚拟机能找到.class文件

    package io.Xfiles;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    
    public class ThawAlien {//解冻外星人
        static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/X.file";
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
            Object mystery = in.readObject();
            System.out.println(mystery.getClass()); //删掉 class后,ClassNotFoundException
        }
    }
    /*
    class io.Alien
     */
    
    

    12.2 序列化的控制

    Externalizable 对序列化过程进行控制
    自动调用
    public void writeExternal(ObjectOutput out) throws IOException { //序列化
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {//反序列化

    Serializable 以存储的二进制为基础来构造,不需要调用构造器

    Externalizable 普通的默认构造器都会被调用

    package io;
    
    import java.io.*;
    
    class Blips1 implements Externalizable {
        public Blips1(){
            System.out.println("Blips1 Constructor");
        }
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            System.out.println("Blips1.writeExternal");
    
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            System.out.println("Blips1.readExternal");
        }
    }
    
    
    class Blips2 implements Externalizable {
        Blips2(){
            System.out.println("Blips2 Constructor");
        }
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            System.out.println("Blips2.writeExternal");
    
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            System.out.println("Blips2.readExternal");
        }
    }
    
    
    public class Blips{
        static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Blips.out";
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            System.out.println("Constructing objects:");
            Blips1 b1 = new Blips1();
            Blips2 b2 = new Blips2();
    
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outFile));
            System.out.println("Saving objects:");
            o.writeObject(b1);
            o.writeObject(b2);
            o.close();
    
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
            System.out.println("Recovering b1:");
            b1 = (Blips1) in.readObject();
            System.out.println("Recovering b2:");
            b2 = (Blips2) in.readObject(); //调用默认构造器,但不是public  InvalidClassException
        }
    }
    /*
    Constructing objects:
    Blips1 Constructor
    Blips2 Constructor
    Saving objects:
    Blips1.writeExternal
    Blips2.writeExternal
    Recovering b1:
    Blips1 Constructor
    Blips1.readExternal
    Recovering b2:
     */
    

    对象的某一部分被序列化 Externalizable writeExternal/readExternal

    package io;
    
    import java.io.*;
    
    public class Blip3 implements Externalizable {
        // 未初始化
        private int i;
        private String s;
    
        public Blip3(){//默认构造器
            System.out.println("Blip3 Constructor");
        }
    
        public Blip3(String x, int a){//非默认构造器
            System.out.println("Blip3(String s, int i)");
            s = x;
            i = a;
        }
    
        public String toString(){return s + i; }
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException { // 把希望序列化的部分存起来
            System.out.println("Blip3.writeExternal");
    
            // you must do this
            out.writeObject(s);
            out.writeInt(i);
    
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            System.out.println("Blip3.readExternal");
    
            // you must do this
            s =(String)in.readObject();
            i = in.readInt();
        }
        static String outFile= "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Blip3.out";
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            System.out.println("Construction objects:");
            Blip3 b3 = new Blip3("A String ", 47);
            System.out.println(b3);
    
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outFile));
            System.out.println("Saving object:");
            o.writeObject(b3);
            o.close();
    
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
            System.out.println("Recoving b3: ");
            b3 = (Blip3)in.readObject();
            System.out.println(b3);
    
        }
    }
    
    

    transient(瞬时)关键字

    Externalizable 没有任何东西可以自动序列化,可以在writeExternal内部对所需部分进行显示的序列化

    Serializable 序列化自动进行。可以用transient 逐个字段关闭序列化

    package io;
    
    import java.io.*;
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    
    public class Logon implements Serializable {
        private Date date = new Date();
        private String username;
        private transient String password;
    
        public Logon(String name, String pwd) {
            username = name;
            password = pwd;
        }
    
        public String toString() {
            return "Logon info: 
     username: " + username + "
     date: " + date + "
     password: " + password;
        }
    
        static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Logon.out";
    
        public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
            Logon a = new Logon("Hulk", "myLittlePony");
            System.out.println("Logon a = " + a);
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outFile));
            o.writeObject(a);
            o.close();
    
            TimeUnit.SECONDS.sleep(1);
    
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
            System.out.println("Recoving object at " + new Date());
            a = (Logon) in.readObject();
            System.out.println("logon a = " + a);
    
        }
    }
    /*
    Logon a = Logon info: 
     username: Hulk
     date: Fri Dec 27 14:40:14 CST 2019
     password: myLittlePony
    Recoving object at Fri Dec 27 14:40:15 CST 2019
    logon a = Logon info: 
     username: Hulk
     date: Fri Dec 27 14:40:14 CST 2019 
     password: null
    
     */
    
    
    

    12.3 使用“持久性”

    两个对象都有指向第三个对象的引用,进行序列化

    package io;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    
    class House implements Serializable {
    }
    
    class Animal implements Serializable {
        private String name;
        private House preferredHouse;
    
        Animal(String nm, House h) {
            name = nm;
            preferredHouse = h;
        }
    
        public String toString() {
            return name + "[" + super.toString() + "]," + preferredHouse + "
    ";
        }
    }
    
    public class MyWorld {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            House house = new House();
            List<Animal> animals = new ArrayList<>();
            animals.add(new Animal("Bosco the dog", house));
            animals.add(new Animal("Ralph the hamster", house));
            animals.add(new Animal("Molly the cat", house));
    
            System.out.println("animals: " + animals);
            ByteArrayOutputStream buf1 = new ByteArrayOutputStream(); // 字节数组, 对Serializable对象对“deep copy”
            ObjectOutputStream o1 = new ObjectOutputStream(buf1);
            o1.writeObject(animals);
            o1.writeObject(animals);
    
            ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
            ObjectOutputStream o2 = new ObjectOutputStream(buf2);
            o2.writeObject(animals);
    
    
            ObjectInputStream in1 = new ObjectInputStream(new ByteArrayInputStream(buf1.toByteArray()));
            ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(buf2.toByteArray()));
            List
                    animals1 = (List) in1.readObject(),
                    animals2 = (List) in1.readObject(),
                    animals3 = (List) in2.readObject();
    
            System.out.println("animals1: " + animals1);
            System.out.println("animals2: " + animals2);
            System.out.println("animals3: " + animals3);
        }
    }
    /*
    animals: [Bosco the dog[io.Animal@5e481248],io.House@66d3c617
    , Ralph the hamster[io.Animal@63947c6b],io.House@66d3c617
    , Molly the cat[io.Animal@2b193f2d],io.House@66d3c617
    ]
    animals1: [Bosco the dog[io.Animal@1b2c6ec2],io.House@4edde6e5
    , Ralph the hamster[io.Animal@70177ecd],io.House@4edde6e5
    , Molly the cat[io.Animal@1e80bfe8],io.House@4edde6e5
    ]
    animals2: [Bosco the dog[io.Animal@1b2c6ec2],io.House@4edde6e5
    , Ralph the hamster[io.Animal@70177ecd],io.House@4edde6e5
    , Molly the cat[io.Animal@1e80bfe8],io.House@4edde6e5
    ]
    animals3: [Bosco the dog[io.Animal@66a29884],io.House@4769b07b //系统无法知道流内的对象是第一个流的对象的别名,因此会产生除完全不同的对象网
    , Ralph the hamster[io.Animal@cc34f4d],io.House@4769b07b
    , Molly the cat[io.Animal@17a7cec2],io.House@4769b07b
    ]
     */
    
    

    保存系统状态,最安全对做法是 将其作为“原子”操作进行序列化

    package io;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    abstract class Shape implements Serializable{
        public static final int RED = 1,BLUE = 2,GREEN=3;
        private int xPos,yPos,dimension;
        private static Random rand = new Random();
        private static int counter = 0;
        public abstract void setColor(int newColor);
        public abstract int getColor();
        public Shape(int xVal,int yVal,int dim){
            xPos = xVal;
            yPos = yVal;
            dimension = dim;
        }
        public String toString(){
            return getClass() + "color[" + getColor() + "] xPos[" + xPos + "] yPos[" + yPos + "] dim[" +dimension + "]
    ";
        }
    
        public static Shape randomFactory(){
            int xVal = rand.nextInt(100);
            int yVal = rand.nextInt(100);
            int dim = rand.nextInt(100);
            switch (counter++ % 3){
                default:
                case 0: return new Circle(xVal,yVal,dim);
                case 1: return new Square(xVal,yVal,dim);
                case 2: return new Line(xVal,yVal,dim);
            }
    
        }
    }
    
    class Circle extends Shape{
        private static int color = RED; // 静态成员变量有初值
    
        public Circle(int xVal, int yVal, int dim) {
            super(xVal, yVal, dim);
        }
    
        @Override
        public void setColor(int newColor) { color = newColor;}
    
        @Override
        public int getColor() { return color;}
    }
    
    class Square extends Shape{
        private static int color;// 静态成员变量无初值
    
    
        public Square(int xVal, int yVal, int dim) {
            super(xVal, yVal, dim);
            color = RED; // 构造函数内 设置静态成员变量值
        }
    
        @Override
        public void setColor(int newColor) { color = newColor;}
    
        @Override
        public int getColor() { return color;}
    }
    
    class Line extends Shape{
        private static int color = RED; // 静态成员变量有初值
    
        public static void serializeStaticState(ObjectOutputStream os) throws IOException {
            os.writeInt(color);
        }
        public static void derializeStaticState(ObjectInputStream is) throws IOException {
            color = is.readInt();
        }
    
        public Line(int xVal, int yVal, int dim) {
            super(xVal, yVal, dim);
        }
    
        @Override
        public void setColor(int newColor) { color = newColor;}
    
        @Override
        public int getColor() { return color;}
    }
    
    public class StoreCADState {
        static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/StoreCADState.out";
        public static void main(String[] args) throws IOException {
            List<Class<? extends Shape>> shapeTypes = new ArrayList<>();
            shapeTypes.add(Circle.class);
            shapeTypes.add(Square.class);
            shapeTypes.add(Line.class);
            List<Shape> shapes = new ArrayList<>();
            for (int i = 0; i < 10; i++)
                shapes.add(Shape.randomFactory());
    
            // 设置全部 颜色 为绿色
            for (int i = 0; i < 10; i++)
                shapes.get(i).setColor(Shape.GREEN);
    
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(outFile));
            out.writeObject(shapeTypes); // 保存class对象
            Line.serializeStaticState(out);
            out.writeObject(shapes);// 保存几何形状
    
            System.out.println(shapes);
        }
    }
    /*
    [class io.Circlecolor[3] xPos[70] yPos[7] dim[19]
    , class io.Squarecolor[3] xPos[86] yPos[65] dim[56]
    , class io.Linecolor[3] xPos[36] yPos[56] dim[20]
    , class io.Circlecolor[3] xPos[94] yPos[35] dim[0]
    , class io.Squarecolor[3] xPos[41] yPos[99] dim[88]
    , class io.Linecolor[3] xPos[64] yPos[69] dim[79]
    , class io.Circlecolor[3] xPos[53] yPos[21] dim[19]
    , class io.Squarecolor[3] xPos[28] yPos[86] dim[75]
    , class io.Linecolor[3] xPos[90] yPos[85] dim[16]
    , class io.Circlecolor[3] xPos[20] yPos[65] dim[63]
    ]
     */
    
    
    package io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.util.List;
    
    public class RecoverCADState {
        static String outFile = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/StoreCADState.out";
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(outFile));
    
            List<Class<? extends Shape>> shapeTypes = (List<Class<? extends Shape>>)in.readObject();
            Line.derializeStaticState(in);
            List<Shape> shapes = (List<Shape>) in.readObject();
            System.out.println(shapes);
    
        }
    }
    /*
    [class io.Circlecolor[1] xPos[70] yPos[7] dim[19]
    , class io.Squarecolor[0] xPos[86] yPos[65] dim[56]
    , class io.Linecolor[3] xPos[36] yPos[56] dim[20]
    , class io.Circlecolor[1] xPos[94] yPos[35] dim[0]
    , class io.Squarecolor[0] xPos[41] yPos[99] dim[88]
    , class io.Linecolor[3] xPos[64] yPos[69] dim[79]
    , class io.Circlecolor[1] xPos[53] yPos[21] dim[19]
    , class io.Squarecolor[0] xPos[28] yPos[86] dim[75]
    , class io.Linecolor[3] xPos[90] yPos[85] dim[16]
    , class io.Circlecolor[1] xPos[20] yPos[65] dim[63]
    ]
     */
      
    

    13 XML

    对象序列化 只是java的解决方案,只有java程序才能反序列化。

    XML太流行,用XML编程的选择太多,包括JDK的javax.xml.*

    我们选择开源的XOM类库,最简单,直观 产生和修改XML,并强调XML的正确性。

    http://www.xom.nu/ 获得

    <dependency>
      <groupId>xom</groupId>
      <artifactId>xom</artifactId>
      <version>1.3.2</version>
    </dependency>
    
    package io;
    import nu.xom.*;
    
    import java.io.*;
    import java.util.*;
    
    public class Person {
        private String first,last;
        public Person(String first,String last){
            this.first =first;
            this.last = last;
        }
        // 从这个Person对象生成XML元素
        public Element getXML(){
            Element person = new Element("person");
            Element firstName = new Element("first");
            firstName.appendChild(first);
            Element lastName = new Element("last");
            lastName.appendChild(last);
            person.appendChild(firstName);
            person.appendChild(lastName);
            return person;
        }
    
        // 从XML 还原 Person
        public Person(Element person){
            first = person.getFirstChildElement("first").getValue();
            last = person.getFirstChildElement("last").getValue();
        }
    
        public String toString(){ return first + " " + last; }
    
        public static void format(OutputStream os,Document doc) throws IOException {
            Serializer serializer = new Serializer(os,"ISO-8859-1");
            serializer.setIndent(4);
            serializer.setMaxLength(60);
            serializer.write(doc);
            serializer.flush();
        }
    
        static String outPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Person.xml";
        public static void main(String[] args) throws IOException {
            List<Person> people = Arrays.asList(
                    new Person("Dr. Bunsen", "Honeydew"),
                    new Person("Gonzo","The Great"),
                    new Person("Phillip J.", "Fry")
            );
            System.out.println(people);
            Element root = new Element("people");
            for (Person p: people)
                root.appendChild(p.getXML());
            Document doc = new Document(root);
            format(System.out,doc);
            format(new BufferedOutputStream(new FileOutputStream(outPath)),doc);
        }
    }
    /*
    [Dr. Bunsen Honeydew, Gonzo The Great, Phillip J. Fry]
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <people>
        <person>
            <first>Dr. Bunsen</first>
            <last>Honeydew</last>
        </person>
        <person>
            <first>Gonzo</first>
            <last>The Great</last>
        </person>
        <person>
            <first>Phillip J.</first>
            <last>Fry</last>
        </person>
    </people>
     */
    
    

    反序列化Person

    package io;
    
            import nu.xom.*;
    
            import java.io.IOException;
            import java.util.ArrayList;
    
    public class People extends ArrayList<Person> {
        public People(String fileName) throws Exception {
            Document doc = new Builder().build(fileName);
            Elements elements = doc.getRootElement().getChildElements();
            for (int i = 0; i < elements.size();i++)
                add(new Person(elements.get(i)));
        }
    
        static String outPath = "/Users/erin/JavaProject/thinking_in_java_example/src/main/java/io/Person.xml";
    
        public static void main(String[] args) throws Exception {
            People p = new People(outPath);
            System.out.println(p);
        }
    }
    /*
    [Dr. Bunsen Honeydew, Gonzo The Great, Phillip J. Fry]
     */
    

    14 Preferences

    自动存储和读取信息,用于小的,受限的数据集合。

    只能存储基本类型和字符串,且每个字符串长度不能超过8K

    用于存储和读取用户偏好及程序配置项的设置

    package io;
    
    import java.util.prefs.Preferences;
    
    public class PreferencesDemo {
        public static void main(String[] args) throws Exception {
            // systemNodeForPackage  通用的安装配置 userNodeForPackage 个别用户的偏好
            Preferences prefs = Preferences.userNodeForPackage(PreferencesDemo.class);//标识结点 非静态方法中,通常使用getClass
            prefs.put("Location","Oz");
            prefs.put("Footwear","Ruby Slippers");
            prefs.putInt("Companions",4);
            prefs.putBoolean("Are there witches?",true);
            int usageCount = prefs.getInt("UsageCount",0);
            usageCount++;
            prefs.putInt("UsageCount",usageCount);//每运行一次会增加,windows 存注册表 mac 存 /Users/erin/Library/Preferences/com.apple.java.util.prefs.plist
            for (String key: prefs.keys())
                System.out.println(key + ":" + prefs.get(key,null));
            System.out.println("How many companions does Dorothy hava ?" + prefs.getInt("Companions",0  ));
        }
    }
    /*
    Footwear:Ruby Slippers
    Are there witches?:true
    Location:Oz
    Companions:4
    UsageCount:4
    How many companions does Dorothy hava ?4
     */
    
    

    15 总结

    控制台,文件,内存块,网络

  • 相关阅读:
    iphone4 系统ios4电话截获
    获取iPhone通话记录(需越狱)
    漫谈SRM主数据迁移及同步(3. 供应商主数据篇)
    对于收货确认的取消,参考此2个Notes 1292032 & 1300861
    漫谈SRM主数据迁移及同步(4. 工厂主数据篇)
    漫谈SRM主数据迁移及同步(2.2 物料主数据篇)
    漫谈SRM主数据迁移及同步(2.1 物料主数据篇)
    采购需求者离职后,其他用户无法操作其创建的购物车
    漫谈SRM主数据迁移及同步(1.2 基本设置篇)
    漫谈SRM主数据迁移及同步(1.1 基本设置篇)
  • 原文地址:https://www.cnblogs.com/erinchen/p/12113395.html
Copyright © 2020-2023  润新知