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

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打印出来的并不是我们指定的
        //缓冲区的大小,而是缓冲区中实际的字符个数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值