IO流
1 file类使用
2 IO流概述
2.1 流的三种分类
- 流向 : 输入流和输出流
- 数据单位 : 字节流和字符流
- 流的角色 : 节点流和处理流
2.2 四个IO流中的抽象基类
- OutputStream 字节输出流
- Inputstream 字节输入流
- Reader 字符输入流
- Writer 字符输出流
3 文件流(节点流)
3.1 FileOutputStream
字节流操作不会用到缓存区,不需要刷新缓存,fileOutputStream.flush();但字节流操作时用到缓存(内存),一般会调用close()方法关闭时刷新缓存。
面试题:close()和flush()的区别?
A:close()关闭流对象,但是先刷新一次缓冲区,关闭之后,流对象不可以继续再使用了。
B:flush()仅仅是刷新缓冲区(一般写字符时要用,因为字符是先进入的缓冲区),流对象还可以继续使用
构造方法
-  public FileOutputStream(File file) throws FileNotFoundException{}
 若使用第一个默认以后写都是把之前的清空再写
-  public FileOutputStream(File file,boolean append) throws FileNotFoundException{}
 第二个参数为true,则字节将写入文件的末尾而不是开头。
public static void main(String[] args) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream("F:\\a.txt");
            String value = "你好世界";
            byte[] bytes = value.getBytes();
            fileOutputStream.write(bytes);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
3.2 FileInputStream
public static void main(String[] args) {
        InputStream f = null;
        int len = 0;   //记录读取到的字节
        try {
            f = new FileInputStream("F:\\a.txt");
             //int read(byte[] b):一次读取一个字节数组,输入流会把读取到的内容放入到这个字节数组中,并返回读取到的个数, 如果读取结束返回-1.
            while((len = f.read()) != -1){    //从文件中读取一个字节数的数据。并返回读取到的这个字节。 如果读取结束,返回的是-1.
                System.out.println((char) len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(f != null){
                    f.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
3.3 FileReader
 public static void main(String[] args) {
        Reader reader = null;
        try {
            reader = new FileReader("F:\\a.txt");
            char[] str = new char[55];
            int len = 0;
            while((len = reader.read(str)) != -1){
                System.out.println(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(reader != null){
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
3.4 FileWriter
需要注意的是构造方法中的是否追加参数,还有就是writer的write并没有将数据直接写进文件而是保存在缓冲区,flush方法才是将缓冲去的数据写入到文本。
public static void main(String[] args) {
        Writer writer = null;
        try {
            writer = new FileWriter("F:\\a.txt",true);
            writer.append("你好");
            writer.write("你好你好");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
4 缓冲流
目的:通过使用缓存,加快读取和写入数据的速度。
 原因:内部提供了一个缓冲区,默认情况下是8192,即8kb
 如果需要大量的读写,使用缓冲流效果更好
4.1 BufferedOutputStream
4.2 BufferedInputStream
4.3 BufferedWriter
4.4 BufferedReader
操作和3中类似
4.4 案例:实现图片复制
 public static void main(String[] args) {
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            bufferedInputStream = new BufferedInputStream(new FileInputStream("F:\\01.jpg"));
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("F:\\02.jpg"));
            byte[] bytes = new byte[1024];
            int len = 0;
            while((len = bufferedInputStream.read(bytes)) != -1){
                bufferedOutputStream.write(bytes,0,len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(bufferedInputStream != null){
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bufferedOutputStream != null){
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
4 转换流
转化流属于字符流
4.1 OutputStreamWriter
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
 public static void main(String[] args) {
        FileOutputStream fileOutputStream = null;
        OutputStreamWriter outputStreamWriter = null;
        try {
            fileOutputStream = new FileOutputStream("F:\\a.txt");
            outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");
            outputStreamWriter.write("你好");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(outputStreamWriter != null){
                try {
                    outputStreamWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
4.2 InputStreamReader
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
public static void main(String[] args) {
        FileInputStream fileInputStream = null;
        //将字节转换为字符
        InputStreamReader inputStreamReader = null;
        try {
            fileInputStream = new FileInputStream("F:\\a.txt");
            inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
            char[] buf = new char[20];
            int len = 0;
            while((len = inputStreamReader.read(buf)) != -1){
                String str = new String(buf,0,len);
                System.out.println(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
5 对象流
有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入输出流。
- 序列化: 是对象转换成一个字节序列的过程,是一个写操作
- 反序列化: 一个字节序列转换成对象的过程 ,是一个读操作
- 当使用对象流写入或者读取对象的时候,必须保证该对象是序列化的
5.1 ObjectOutputStream(OutputStream out)
 public static void main(String[] args) {
        //序列化:将内存中的java对象读取到硬盘中或通过网络传输出去,使用ObjectOutputStream实现
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:\\object.dat"));
            objectOutputStream.writeObject(new String("我爱it"));
            objectOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(objectOutputStream != null){
                try {
                    objectOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
5.2 ObjectInputStream (InputStream in)
public static void main(String[] args) {
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream("F:\\object.dat"));
            Object o = objectInputStream.readObject();
            String str = (String) o;
            System.out.println(str);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(objectInputStream != null){
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
5.3 自定义类实现序列化
需要满足的条件
- 实现Serializable接口
- 对象所在的类提供常量:序列版本号 public static final Long serializableID = 698515664L;随便数字多少
- 要求对象的属性也必须是可序列化的。(基本数据类型本身是可序列化的)
- static、transient修饰的属性不能被序列化不能被ObjectOutputStream和ObjectIntputStream序列化
public class Person implements Serializable {
    public static final Long serializableID = 698515664L;
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = 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;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
一般情况下用JSON
6 随机存取文件流
RandomAccessFile
6.1 基础使用

public static void main(String[] args) {
        //既可以作为输入流又可以作为输出流
        RandomAccessFile randomAccessFile1 = null;
        RandomAccessFile randomAccessFile2 = null;
        try {
            randomAccessFile1 = new RandomAccessFile("F:\\01.jpg","r");
            randomAccessFile2 = new RandomAccessFile("F:\\02.jpg","rw");
            byte[] bytes = new byte[1024];
            int len = 0;
            while((len = randomAccessFile1.read(bytes)) != -1){
                randomAccessFile2.write(bytes,0,len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(randomAccessFile1 != null){
                try {
                    randomAccessFile1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(randomAccessFile2 != null){
                try {
                    randomAccessFile2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
6.2 seek方法
/*
    使用RandomAccessFile实现数据的插入效果
     */
    @Test
    public void test3() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len)) ;
        }
        //调回指针,写入“xyz”
        raf1.seek(3);
        raf1.write("xyz".getBytes());
        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());
        raf1.close();
        //思考:将StringBuilder替换为ByteArrayOutputStream
    }
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号