《Java7编程高级进阶》(三)

来源:互联网 发布:湘雅大数据 编辑:程序博客网 时间:2024/06/03 12:39

        • io编码
        • InputStream的read方法
        • available
        • InputStream的write方法
        • InputReader字符流的read方法
        • OutputStream的write方法
        • BufferReader和BufferWriter
        • 字节流与字符流
        • nio包下的一些常用方法
        • 读写对象OutputObjectInputObject
        • IO数据处理
        • PushbackInputStream
        • Vector
        • SequenceInputStream
        • tip
        • PrintStream
        • CharArrayWriter

io编码

在io中分为字节、字符操作,面向字节的文件工作在8位编码上,面向字符的工作在16位的unicode编码上,其中每一个字符(unicode)是由两个字节数据组成。

InputStream的read方法

read()这个方法是用来读取数据,每次读取一个字节,返回的是下一个数据字节,说明文件指针不是指向第一个字节,而是第一个字节前面的一个,如果读到末尾返回-1。

byte[] b = new byte[3];len = in.read(b)

read(byte[] b)这个方法是每次读取b.length长度的字节,返回是读入缓冲区的字节总数。

available

这个方法是返回不受阻塞地从此输入流中读取(或跳过)的估计剩余字节数,如果是本地文件,我们通常使用这个方法来获取文件总长度,如果在网络,你已经打开输出流,但是没有数据传过来,就阻塞,所以返回为0.在某些情况下,非阻塞的读取(或跳过)操作在执行很慢时看起来受阻塞,例如,在网速缓慢的网络上读取大文件时。

InputStream的write方法

write(int len)将指定字节写入到输出流中。

write(byte[] b)将 b.length 个字节从指定 byte 数组写入此文件输出流中。

flush()这个方法刷新缓冲区的内容到输出流。(这个方法是非常有用的,在多用户的情况下,不同的线程或用户之间要维持数据额的一致性,立即刷新就变得很重要)

正常如果使用这种读写,是配合使用,要么全是一个字节读写,要么就是字节数组读写。

InputReader(字符流)的read方法

read()返回读取的字符编码,如果已到达流的末尾,则返回 -1

OutputStream的write方法

write()返回 指定要写入字符的 int。

BufferReader和BufferWriter

在前面,我们为了方便读写,我们都自己申明了缓冲区。而这两个类内置了java的缓冲区,请记住,不管你是读取单个字符,还是512个字节,均需要相同数量的I/O操作,因此,使用缓冲区将更加高效。

newLine() 写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 (‘\n’) 符。

readLine() 读取一个文本行。通过下列字符之一即可认为某行已终止:换行 (‘\n’)、回车 (‘\r’) 或回车后直接跟着换行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null 。

flush(),在缓冲流中,它会在文件写完后,关闭输出流的时候,自动关闭,而不需要手动,如果你着急,在没有关闭流,之前强制写到文件中,就需要此方法。

字节流与字符流

使用字符流的好处:

  1. 他们处理unicode字符集中的任何字符,而字节流金限于ISO Latin8位字节。
  2. 使用字符流的程序可以很容易进行国际化。
  3. 字符流使用内部缓存,本质比字节流高效。

通常情况下,使用InputStream/OutputStream类针对图像文件,声音文件、视频等写入二进制数据、ascll文件;要读写基于unicode文本文件,还是使用字符流。

nio包下的一些常用方法

遍历当前文件夹下的文件夹和文件,如果有子文件夹不会遍历,并且它不会遍历文件,会报不是文件目录异常。( 注意啦如果是文件夹就直接文件名,没有后缀格式名)

DirectoryStream<Path> d = null;            Path ps = Paths.get("c:\\lib");            try {                d = Files.newDirectoryStream(ps);                for(Path p:d) {                    System.out.println(p.getFileName());                }            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }finally {                if(d!=null) {                    try {                        d.close();                    } catch (IOException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }            }

文件的过滤

            Path p = Paths.get("c:\\hello");            DirectoryStream<Path> ds = null;            try {                ds = Files.newDirectoryStream(p, "*.{txt}");                //这个是文件列举的时候过滤文件格式                for(Path p1:ds) {                    System.out.println(p1.getFileName());                }            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }finally {                if(ds!=null) {                    try {                        ds.close();                    } catch (IOException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }            }//这种方式局限就是只是过滤了后缀文件格式

下面就是自定义过滤文件条件:

        Path p = Paths.get("c:\\hello");        DirectoryStream.Filter<Path> ds = null;        DirectoryStream<Path> ds1 = null;        ds = new DirectoryStream.Filter<Path>() {//后者必须指定泛型,会影响方法参数类型            @Override            public boolean accept(Path entry) throws IOException {                // TODO Auto-generated method stub                return Files.size(entry)==9l;                        //Files这个方法是用来计算文件大小,单位字节,返回是长整型,所以9后面要加表示为长整型                //该方法显示接受返回结果为true的文件。            }        };        try {            ds1 = Files.newDirectoryStream(p, ds);                //注意DirectoryStream.Filter这个是没有迭代器可以遍历,必须通过DirectoryStream来遍历            for(Path p1:ds1) {                System.out.println(p1.getFileName());            }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally {            if(ds1!=null) {                try {                    ds1.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }

读写对象OutputObject、InputObject

先创建对象

public class Test77 implements Serializable {    private String name;    private int age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public Test77(String name, int age) {        super();        this.name = name;        this.age = age;    }    @Override    public String toString() {        // TODO Auto-generated method stub        return name + "      " + age;    }}//需要注意的事,对象创建一定要实现Serializable,不然后面写入,会报异常,没有实现该接口。
  public void writeObject() {           ObjectOutputStream oos  = null;           try {            oos = new ObjectOutputStream(new FileOutputStream(new File("c:\\student.dat")));            Test77 t = new Test77("laoqiang", 12);            oos.writeObject(t);//这里需要注意一个一个对象的写。            Test77 t1 = new Test77("laoqiang1", 22);            oos.writeObject(t1);        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally {            if(oos!=null) {                try {                    oos.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }       }       public void readObject() {            ObjectInputStream ois = null;           try {             ois  =new ObjectInputStream(new FileInputStream(new File("c:\\student.dat")));            for(int i = 0;i<2;i++) {                Object o = ois.readObject();                System.out.println(o.toString());            }        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }           finally {            if(ois!=null) {                try {                    ois.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }       }

I/O数据处理

在Java很多时候,还是注重的是数据的处理,数据很多都是以字节数组的形式出现,为了提高读写效率,有了缓冲区,其实缓冲区就是字节数组。数据以原始的二进制传输是最节省带宽。ByteArrayOutputStream、ByteArratInputStream只处理二进制数据。而DataOutputStream和DataInputStream是主要针对数据对象类。

ByteArrayOutputStream、ByteArratInputStream内部自带缓冲区的。

DataOutputStream和DataInputStream是成对使用的,如果用其他流写进的数据是不可以用DataInputStream
读取。

DataOutputStream和DataInputStream:数据输入、输出流允许应用程序以与机器无关方式从底层输入、输出流中读取基本 Java 数据类型。

特别注意,使用DataOutputStream和DataInputStream,以什么顺序写入,就必须按照什么顺序读取。否测会出现乱码或者异常。

FileOutputStream fos = null;            try {                fos = new FileOutputStream(new File("c:\\java.txt"));            } catch (FileNotFoundException e2) {                // TODO Auto-generated catch block                e2.printStackTrace();            }            DataOutputStream dos = new DataOutputStream(fos);            try {                dos.writeInt(12);                dos.writeDouble(2.909089);                dos.writeLong(124566778);                dos.writeUTF("你好");                dos.writeByte(97);            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            FileInputStream fis = null;            try {                fis = new FileInputStream(new File("c:\\java.txt"));            } catch (FileNotFoundException e1) {                // TODO Auto-generated catch block                e1.printStackTrace();            }            DataInputStream dis = new DataInputStream(fis);            try {                System.out.println(dis.readInt());                System.out.println((Double)dis.readDouble());                long l = dis.readLong();                System.out.println(l);                System.out.println((String)dis.readUTF());                System.out.println((Byte)dis.readByte());            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }

PushbackInputStream

对于这个流,大家可能接触不是太多。它主要在读取的时候,添加一个功能就是取消读取,将字节推回到缓冲区中。而这就给了我们的机会,去对想要处理的字节和不想要处理的字节,提供了方便,话不多少,下面两个例子:

public static void main(String[] args) {        //我们的需求就是在输入eclise控制台输入字节,用*代替你的字节中的.并输出        PushbackInputStream pis= new PushbackInputStream(System.in,3);        char c = 0;        char c1 = 0;        try {            while((c = (char) pis.read())!='q') {                //www.bai.com                System.out.print(c);                if((c1=(char) pis.read())=='.') {//这里的读,是下一个字节的读取                    System.out.print("*");                }else {                    pis.unread(c1);//如果不是你想要的推回到缓冲区,下次开始读的还是这个推回的字节                }                }        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }
/*             * 这个例子,就是键盘录入字节,如果小数点后面联系两个零,就换成**。             */            char c = 0;            char c1 = 0;            char c2 = 0;            PushbackInputStream pis= new PushbackInputStream(System.in,3);            try {                while((c= (char) pis.read())!='e') {                    if(c=='.') {                        System.out.print(".");                        if((c1=(char) pis.read())=='0') {                            if((c2=(char) pis.read())=='0') {                            System.out.println("**");                            }else {                                pis.unread(c2);                                pis.unread(c1);                            }                        }else {                         pis.unread(c1);                        }                    }else {                        System.out.print(c);                    }                }            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            //在这个例子中,我们需要注意,就是unread方法只能推回1个字节,如果要推回几个,需要在PushbackInputStream 指定回退缓冲区size,否则会报出io异常。

Vector

在这里补充将一个知识,之前也没有怎么使用。Vector中文意思:向量。它和数组一样都是用来存储。但是不同的是,它可以动态自增或者缩减长度。下面介绍它的简单使用:

在默认情况下:Vector初始化的时候size是0,这个是表示Vector的元素个数,一开始你没有,当你增加的话,这个数会跟着变化。

构造函数

Vector() 构造一个空向量,使其内部数据数组的大小(初始容量)为 10,其标准容量增量为零。

Vector(int initialCapacity, int capacityIncrement) 使用指定的初始容量(比如是100,就是到了100的时候才自动增量)和容量增量构造一个空的向量。

  1. capacityIncrement 容量增量
  2. setsize()可以用来设置Vector中的容量,在这里需要说明就是你用add(int index,E e)如果index超过size()方法值,会报错的。
  3. capacity() 这个是获取容量的值
  4. 在构造函数中,如果自己设置增量,那么当数组不够的时候就可以进行按设定的增量加,默认标准增量10.

SequenceInputStream

这个输入流提供了逻辑连接,可以把多个输入流合并起来,转化为单个输入流。下面举的例子,就是通过从多个文件中获取流,通过转化为单个流,然后写到一个文件中。

Enumeration其实是多个条目的索引列表,有兴趣的可以自己看,这里只是简单使用。

static Vector filename =  new Vector();    static Vector fileininputstream  = new Vector();    public static void main(String[] args) {    getFilesName();    getFilesInputStream();    WriteToFile();   }   /*    * 将多个文件流写到一个文件中    */    private static void WriteToFile() {    // TODO Auto-generated method stub    try {        OutputStream out = new FileOutputStream("c:\\hello8.txt");        SequenceInputStream sis = new SequenceInputStream(fileininputstream.elements());        byte[] b = new byte[4096];        int len =0;        while((len=sis.read(b))!=-1) {            out.write(b, 0, len);        }        System.out.println(b.length);    } catch (FileNotFoundException e) {        // TODO Auto-generated catch block        e.printStackTrace();    } catch (IOException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    }    /*     * 获取对应的多个文件输入流     */    private static void getFilesInputStream() {    // TODO Auto-generated method stub        Enumeration e = filename.elements();        while(e.hasMoreElements()) {            InputStream in = null;          try {            in=  new FileInputStream((String)e.nextElement());        } catch (FileNotFoundException e1) {            // TODO Auto-generated catch block            e1.printStackTrace();        }          fileininputstream.addElement(in);        }    }    /*     * 用来从键盘获取文件名     */    private static void getFilesName() {    // TODO Auto-generated method stub    String content = null;    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));    try {        while((content=br.readLine())!=null) {            if(content.equals("over")) {                break;            }            System.out.println("每次添加的文件名"+content);            filename.add("c:\\"+content+".txt");        }    } catch (IOException e) {        // TODO Auto-generated catch block        e.printStackTrace();    }    }

tip

Java的字符集是采用的是unioncode编码,一个字符是占两个字节。

PrintStream

PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式,打印的所有字符都使用平台的默认字符编码转换为字节

    String s = "laoqiang";            try {                PrintStream ps = new PrintStream("f:\\testjava\\test1.txt");                ps.print('a');                ps.print(12);                ps.print("laoqiang");                ps.print(true);                ps.printf("你好%s",s);//这个就类似c语言格式化输出列表                boolean b= ps.checkError();//PrintStream 永远不会抛出 IOException;而是,                //异常情况仅设置可通过 checkError 方法测试的内部标志                System.out.println(b);                ps.flush();

CharArrayWriter

此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。

CharArrayWriter caw = new CharArrayWriter(50);        System.out.println(caw.size());        caw.write(97);        try {            caw.write("laoqiang");            String s = caw.toString();//将输出流中的数据转化为字符串。            System.out.println(s);            char[] c = caw.toCharArray();//将输出流中的数据转变成字符数组            for(char c1:c) {                System.out.println(c1);            }            //上面这些只是将东西写到缓冲区中,并不是真正的写在文件上,那么这个存在的            //意义是,通过其他的流去封装,提高效率。        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println(caw.size());        //通过上面测试我们发现size打印出来的并不是我们指定的        //缓冲区的大小,而是缓冲区中实际的字符个数
原创粉丝点击