• Java基础学习 -- I/O系统、流


      Java类库里有四个表示流的抽象父类:InputStream、OutputStream、Reader、Writer。

      其中 InputStream 和 OutputStream 是对字节进行操作的输入流和输出流;Reader 和 Writer 是对字符操作的输入输出流。

      它们是抽象类,在用它们的时候必须要对其进行实例化,因此类库也提供了具有不同功能的它们的子类,比如,以文件形式输入输出的 FileInputStream、FileOutputStream 和FileReader、FileWriter 等。

      以下列出了 Java IO 中一些比较常用的流类以及它们的方法使用,更多的流类请查阅API文档。

      --------------------------------------------------------------

      一、字节流

      1. InputStream、OutputStream 只能进行字节的传输数据

             InputStream抽象了应用程序读取数据的方式

           OutputStream抽象了应用程序写出数据的方式

      2. EOF = End,读到 -1 就读到结尾。

      3. 输入流的基本方法(以下的 in 代表输入流的对象)

          int b = in.read();

          从流读取一个字节无符号填充到int的低8位。(一个int变量是4个字节,1字节=8位,read()方法只能读取一个字节并返回int,所以该字节填充到int的低八位。)若读到结尾,返回 -1。用该方法读取大文件时,要使用while循环,这样效率较低,时间也较长,可以使用下面的批量读取方式。

          in.read(byte[] buf);

          从流读取数据直接填充到字节数组buf,读取字节的个数取决于数组的长度。返回的是读到的字节的个数。如果读到结尾返回-1。

          in.read(byte[] buf, int start, int size);

          从流读取数据到字节数组buf,从buf的start位置开始,存放最多size长度的数据。返回的是读到的字节的个数。如果读到结尾返回-1。

      4. 输出流的基本方法(以下的 out 代表输出流的对象)

          out.write(int b);

          写出一个byte到流,写出的是b的低8位。

          out.write(byte[] buf);

          将一个字节数组写出到流。

          out.write(byte[] buf, int start, int size);

          从buf的start位置开始,写size长度的数据到流。

      5. FileInputStream 是 InputStream 的子类,具体实现了在文件上读取字节数据:

    package test;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    public class TestDemo {
        
        public static void main(String[] args) throws Exception {
            //我们在D盘下创建了一个demo.txt,内容为“你好hello”。
            File file = new File("D:\demo.txt");
            if(!file.exists()) file.createNewFile();
            InputStream in = new FileInputStream(file);
            int temp;
            while((temp = in.read()) != -1) {
                System.out.print(Integer.toHexString(temp & 0xff) + " ");
            }
            in.close();
            System.out.println();
            
            InputStream in2 = new FileInputStream(file);
            byte[] buf = new byte[1024];
            int bytes = in2.read(buf);
            String s = new String(buf,0,bytes,"GBK");
            System.out.println(s);
            in2.close();
        }
        
    }
    
    Output: c4 e3 ba c3 68 65 6c 6c 6f
          你好hello

      6. FileOutputStream 是InputStream的子类,具体实现了在文件上读写出字节数据:

    //这是一个拷贝文件的例子

    package
    test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class TestDemo { public static void copyFile(File srcFile,File destFile) throws IOException{ if(!srcFile.exists()) { throw new IllegalArgumentException("文件 " + srcFile + " 不存在!"); }else if(!srcFile.isFile()) { throw new IllegalArgumentException(srcFile + " 不是文件!"); }else { FileInputStream in = new FileInputStream(srcFile); FileOutputStream out = new FileOutputStream(destFile); byte[] bytes = new byte[8*1024]; int b; while((b = in.read(bytes, 0, bytes.length)) != -1) { out.write(bytes, 0, b); out.flush(); //对于字节流而言,此句不加也没关系。 } in.close(); out.close(); } } public static void main(String[] args) { try { copyFile(new File("D:\demo.txt"),new File("D:\demo_copy.txt")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

      7. DataInputStream / DataOutputStream

          对“流”功能的扩展,可以更加方便的读写int,long,字符等基本数据类型

          如:DataOutputStream的方法有 writeInt() , writeDouble() , writeUTF() 等。 

          在构造Data流时,要用到其他的流作为参数。如:DataOutputStream dos = new DataOutputStream(new FileOutputStream(file)); 

          这其实是一种“装饰器(过滤器)”设计模式:首先用“其他的流”来构造Data流,然后像 writeInt() 这些方法里面其实都是用“其他的流”的 write() 方法来实现的,如:一个Int有4个字节,用 write() 八位八位地写,做4次 write() ,然后再做移位操作。说白了就是用 writeInt() 将这些操作包装好,方便以后的直接使用。

         

    writeInt()源码 

    package test;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class TestDemo {
        
        public static void main(String[] args) throws IOException{    
            
            DataOutputStream dos = new DataOutputStream(
                    new FileOutputStream("D:\demo.dat"));
            dos.writeInt(10);
            dos.writeInt(-10);
            dos.writeUTF("中国");      //采用utf-8编码写出
            dos.writeChars("中国");   //采用utf-16be编码写出
            PrintHex.printHex("D:\demo.dat");
            dos.close();
            
            DataInputStream dis = new DataInputStream(
                    new FileInputStream("D:\demo.dat"));
            System.out.println();
            int i = dis.readInt();
            System.out.println(i);
            i = dis.readInt();
            System.out.println(i);
            String s = dis.readUTF();
            System.out.println(s);
            dis.close();
        }
        
    }
        /*--------------------------------------------*/
    package test;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class PrintHex {
        
        public static void printHex(String fileName) throws IOException {
            FileInputStream in = new FileInputStream(fileName);
            int b;
            while((b = in.read()) != -1) {
                System.out.print(Integer.toHexString(b & 0xff) + " ");
            }
            in.close();
        }
        
    }
    
    /**
     * Output:
     * 0 0 0 a ff ff ff f6 0 6 e4 b8 ad e5 9b bd 4e 2d 56 fd 
     * 10
     * -10
     * 中国
     */

      8. BufferedInputStream / BufferedOutputStream

          这两个流类为IO提供了带缓冲区的操作,一般打开文件进行读写操作时都会加上缓冲,这种流模式提高了IO的性能。

          从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
          FileOutputStream  --->  write() 方法相当于一滴一滴地把水“转移”过去。
          DataOutputStream  --->  writeXxx() 方法会方便一些,相当于一瓢一瓢把水“转移”过去。
            BufferedOutputStream  --->  write 方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高了。

          这种字节缓冲流同样是采用装饰模式,要用其他的流来参与构造。

          以下是四种不同方式的文件拷贝,效率对比:

    package test;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class CopyMethod {
        //以单字节传输
        public static void copyByByte(String srcFile,String destFile) throws IOException {
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(destFile);
            int i;
            while((i = fis.read()) != -1) {
                fos.write(i);
            }
            fis.close();
            fos.close();
        }
        //以字节数组传输
        public static void copyByBytes(String srcFile,String destFile) throws IOException {
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(destFile);
            byte[] bytes = new byte[8*1024];
            int i;
            while((i = fis.read(bytes, 0, bytes.length)) != -1) {
                fos.write(bytes, 0, i);
            }
            fis.close();
            fos.close();
        }
        //以单字节缓冲流传输
        public static void copyByByteBuffer(String srcFile,String destFile) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream(srcFile));
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(destFile));
            int i;
            while((i = bis.read()) != -1) {
                bos.write(i);
                bos.flush();  //缓冲流要冲刷,否则写入不到文件
            }
            bis.close();
            bos.close();
        }
        //以字节数组缓冲流传输
        public static void copyByBytesBuffer(String srcFile,String destFile) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream(srcFile));
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(destFile));
            byte[] bytes = new byte[8*1024];
            int i;
            while((i = bis.read(bytes, 0, bytes.length)) != -1) {
                bos.write(bytes, 0, i);
                bos.flush();   //缓冲流要冲刷,否则写入不到文件
            }
            bis.close();
            bos.close();
        }
        
    }
    package test;
    
    import java.io.IOException;
    
    public class TestDemo {
        
        public static void main(String[] args) {
            try {
           //比较这四种拷贝方式的效率。
    long start = System.currentTimeMillis(); //Copy.copyByByte("D:\1.mp3", "D:\2.mp3"); //用时2908ms //Copy.copyByByteBuffer("D:\1.mp3","D:\2.mp3"); //用时1854ms //Copy.copyByBytes("D:\1.mp3","D:\2.mp3"); //用时7ms //Copy.copyByBytesBuffer("D:\1.mp3","D:\2.mp3"); //用时37ms,以字节数组缓冲流的方式反而比不带缓冲的字节数组传输得慢。 long end = System.currentTimeMillis(); System.out.println(end-start); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

      ------------------------------------------------------------------

      二、字符流 

      1) 认识文本和文本文件:

        java的文本(char) 是16位无符号整数,是字符的unicode编码(双字节编码)。

        文件 是byte byte byte ... 的数据序列。

        文本文件 是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果。

      2) 字符流(Reader Writer为抽象类) ---> 一般操作的是文本文件

      1. InputStreamReader / OutputStreamWriter 

        字符的处理:一次处理一个字符。字符的底层依然是基本的字节序列,字符流的基本实现:

        InputStreamReader   完成byte流解析为char流,按照编码解析。

        OutputStreamWriter  提供char流到byte流,按照编码处理。

        字符流在构造时依然要用到字节流对象作为构造参数。

    //我们利用字符流同时做了文本文件的打印和拷贝。
    package test;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    
    public class IsrAndOswDemo {
        public static void main(String[] args)throws IOException {
            FileInputStream in = new FileInputStream("D:\douban-utf-8.txt");
            InputStreamReader isr = new InputStreamReader(in,"utf-8"); //如不写编码方式就默认为项目的编码。操作的时候,要写文件本身的编码格式。
        
            FileOutputStream out = new FileOutputStream("D:\douban-utf-8-copy.txt");
            OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8");
            /*int c ;
            while((c = isr.read())!=-1){
                System.out.print((char)c);
            }*/
            char[] buffer = new char[8*1024];
            int c;
            /*批量读取,放入buffer这个字符数组,从第0个位置开始放置,最多放buffer.length个
              返回的是读到的字符的个数
            */
            while(( c = isr.read(buffer,0,buffer.length))!=-1){
                String s = new String(buffer,0,c);
                System.out.print(s);
                osw.write(buffer,0,c);
                osw.flush();
            }
            isr.close();
            osw.close();
        }
    }

      2. FileReader / FileWriter

        方便直接读写文本文件,不用像 InputStreamReader 和 OutputStreamWriter 一样需要嵌套一个File字节流。

        在构造文件字符流时,有两点需要注意:

         1) 不能使用编码方式的参数,也就是说只能读取编码方式和项目编码方式相同的文本文件,否则读取进来再做输出时会乱码。

         2) 构造FileWriter时,可以使用append参数,如果设置为true,会在输出的文本文件后面追加文本内容。

    //文本文件拷贝实例

    package
    test; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class FrAndFwDemo { public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("D:\douban-gbk.txt"); FileWriter fw = new FileWriter("D:\douban-gbk-copy.txt",true); //可以添加append参数,如果有,则在文件后面追加内容。 char[] buffer = new char[2056]; int c ; while((c = fr.read(buffer,0,buffer.length))!=-1){ fw.write(buffer,0,c); fw.flush(); } fr.close(); fw.close(); } }

      3. 字符流的过滤器 BufferedReader / BufferedWriter / PrintWriter

        这两个过滤器最强大的功能是具有读写一整行的方法:

        BufferedReader ---> readLine() 读一行,但是不能识别换行符

        BufferedWriter / PrintWriter ---> 写一行  

    package test;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    
    public class BrAndBwOrPwDemo {
        public static void main(String[] args) throws IOException{
             //对文件进行读写操作 
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(
                            new FileInputStream("D:\douban-utf-8.txt"),"utf-8"));
            /*BufferedWriter bw = new BufferedWriter(
                    new OutputStreamWriter(
                            new FileOutputStream("D:\douban-utf-8-copy.txt"),"utf-8")); //写出时如果不加编码方式,会按默认的编码方式写出,copy的文件不再是utf-8编码,而是gbk编码。*/
            PrintWriter pw = new PrintWriter("e:\javaio\imooc4.txt","utf-8");
            //PrintWriter pw1 = new PrintWriter(outputStream,boolean autoFlush);
            String line ;
            while((line = br.readLine())!=null) {  //readLine方法一次读一行,但并不能识别换行
                System.out.println(line);
                /*bw.write(line);
                //单独写出换行操作
                bw.newLine();//换行操作
                bw.flush();*/
                pw.println(line); //写入到文件
                pw.flush();
            }
            br.close();
            //bw.close();
            pw.close();
        }
    }

       ------------------------------------------------------------------

      三、对象的序列化和反序列化

        对象序列化,就是将 Object 转换成 byte序列,反之叫对象的反序列化。对对象进行序列化和反序列化为的是 方便将来在 网络上 或者 本地 进行对象的传输。

      1. 序列化的基本操作 ObjectOutputStream / ObjectInputStream

        1) 序列化流(ObjectOutputStream) ---> 方法 writeObject(Object)

          反序列化流(ObjectInputStream) ---> 方法 readObject() ,返回的是Object类

        2) 序列化接口(Serializable)

          要对对象进行序列化,那么这个对象必须要实现序列化接口Serializable,否则将出现异常。这个接口,没有任何方法,只是一个标准。

    package test;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class ObjectSeriaDemo1 {
        public static void main(String[] args) throws Exception{
            String file = "demo/obj.dat";
            //对象的序列化,将stu对象转化为字节序列存入file。
            ObjectOutputStream oos = new ObjectOutputStream(
                    new FileOutputStream(file));
            Student stu = new Student("10001", "张三", 20);
            oos.writeObject(stu);
            oos.flush();
            oos.close();
            //对象的反序列化,将file中的字节序列转化为对象。
            ObjectInputStream ois = new ObjectInputStream(
                    new FileInputStream(file));
            Student stu2 = (Student)ois.readObject(); //需要进行强制类型转换,因为readObject方法返回的是Object类,而不是Student类。
            System.out.println(stu2);
            ois.close();
        }
    }
  • 相关阅读:
    搜索框的实现
    图片瀑布流实现
    git的基本操作总结
    linux中常用命令总结
    JavaScript中的闭包
    springmvc执行过程
    位运算
    MySQL与Oracle数据库连接配置
    java 基础数据类型大小
    spring源码编译控制台输出乱码
  • 原文地址:https://www.cnblogs.com/xingyazhao/p/6005550.html
Copyright © 2020-2023  润新知