02 IO 干货

基本内容

Process

1) 确定源

2) 选择流

3) 操作(读,写)

4) 释放资源.

分隔符

建议采用 "C:/JavaWork/asdf/xxx.java"   这种 /

无论是字节处理,还是字符处理, 都要套一层 buffer 来提升性能. (默认是 8k 做一次 I/O 的交互)

文件

File 类 用来定义源, 一般是本地文件

File src = new File("stanford.txt")
也可以直接用FileInputStream("stanford.txt") 这种来导入文件
字节码 处理 (文件copy)

字节可以处理一切文件, 无论是 视频,音频,文本.

InputStream & OutputStream -> BufferedInputStream & BufferedOutputStream,  FileInputStream & FileOutputStream(直接字节流作用于文件)

package com.pratice.java300;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class MyByteCopy {

    public static void main(String[] args) {
        copyByte("stanford.txt", "xxx.txt");
    }
    
    public static void copyByte(String src, String dest) {
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));){
            byte[] temp = new byte[1024];
            int len = -1;
            while ((len = bis.read(temp)) != -1) {
                bos.write(temp, 0, len);
                // 字节copy, 不用考虑换行符问题, 因为换行符包含在字节copy中
            }
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

把文件流封装在 try 的括号里边, 就不用释放资源了, 自动释放了.

字符处理 (文件copy)

只能处理文本

Reader & Writer -> BufferedReader & BufferedWriter,    FileReader & FileWriter(直接字符流作用于文件)

package com.pratice.java300;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;


public class MyCharCopy {

    public static void main(String[] args) {
        copyChar("stanford.txt", "xxx.txt");
    }
    
    public static void copyChar(String src, String dest) {
        try(BufferedReader br = new BufferedReader(new FileReader(src));
        BufferedWriter bw = new BufferedWriter(new FileWriter(dest));){
            String msg = null;
            int line = 0;
            while ((msg = br.readLine()) != null) {
                if (0 == line) {
                    line++;
                } else {
                    bw.newLine();
                }
                bw.write(msg, 0, msg.length());
            }
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}
源并非文件实体, 而是内存, 例子中输出也是内存

字节数组流 ByteArrayInputStream 和 ByteArrayOutputStream, 因为这里不设计到 IO, 所以就没有 buffered。

ByteArrayInputStream 实际上是内存的一个内部缓冲区, 可以接受来自字节流的数据. 相当于读取到内存,转化成流处理,

  我们都知道, 这里的文件处理都是 I/O 之间流的转换, 所以可以先通过 ByteArrayInputStream 将输入转换成流,缓存到内存中, 以备使用.

ByteArrayOutputStream 该类实现了将数据写入字节数组的输出流, 写出内存, 但是你想获得写出的数据, 需要使用 dest = baos.toByteArray()

  可以将内存区缓存的内容读出到输出流来进行实际的处理, 比如 BytemArrayOutputStream -> OutputStream -> file

String -> ByteArrayInputStream(加工, 比如转换成大写字母) -> ByteArrayOutputStream -> byte[] array -> dest file 的例子:

package com.pratice.java300;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;


public class MyMemoryCopy {

    public static void main(String[] args) {
        copyMemoryToFile("asdfxxxjjjgggqqq111", "xxx.txt");
    }
    
    public static void copyMemoryToFile(String src, String dest) {
        try(ByteArrayInputStream bais = new ByteArrayInputStream(src.getBytes());
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest))
                ){
            // 1.读取缓冲区的内容, 转换成大写字母
            int ch = -1;
            byte[] out;
            while ((ch = bais.read()) != -1) {
                int upperCh = Character.toUpperCase((char)ch);
                baos.write(upperCh);
            }
            baos.flush();
            // 2. 将缓冲区的文件输出为字节数组
            out = baos.toByteArray();
            // 3. 将字节数组写出到文件
            bos.write(out);
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}
字节流 转字符流 (文件copy)

 InputStreamReader : 读取字节流并帮助转换成字符流

OutputStreamWriter: 读取的是字符流并帮助转换成字节流

package com.pratice.java300;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;

public class MyByte2Char {

    public static void main(String[] args) {
        byte2Char();
    }
    
    public static void byte2Char() {
        try(
            // 从字节到字符
            BufferedReader reader = 
                new BufferedReader(
                    new InputStreamReader(
                        new URL("http://www.baidu.com").openStream(), "UTF-8"));
            // 从字符到字节
            BufferedWriter writer = 
                new BufferedWriter(
                    new OutputStreamWriter(
                        new FileOutputStream("baidu2.html"), "UTF-8"));){
            String msg = null;
            while ((msg = reader.readLine()) != null) {
                writer.write(msg);
                writer.newLine();
            }
            writer.flush();

        }catch(IOException e) {
            e.printStackTrace();
        }
    }

}
数据流处理(保留了数据类型)

DataInputStream & DataOutputStream

处理的方式与下边的对象流一样. 在类似 socket 编程, 等需要传递时, 很常用

注意, 进入数据流的顺序, 必须和出数据流的顺序一致.

所以, 你可以这么写:

String msg = dis.readWTF();   //这也不是把所有在流里的的 string 类型数据都读取出来, 而是通过顺序(进入数据流流), 顺序到这是String类型的.

int salary = dis.readInt();    // 这里的 dis 就是数据流, readInt() 并不是把所有的 int 型的数据都读取出来, 而是根据顺序的.

对象流(序列化 & 反序列化)

() ObjectInputStream : 将字节流转化为对象 (反序列化), 在你想要反序列化之前, 必须先使用 ObjectOutputStream 把对象序列化成字节流

() ObjectOutputStream : 将对象转换为 字节流(序列化)不是所有的对象都可以序列化, 必须实现一个接口 Serializable 

对象 -> ObjectOutputStream 封装成字节流 ->   ObjectInputStream  -> 对象

package com.pratice.java300;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Date;

public class MyObjectCopy {

    public static void main(String[] args) throws ClassNotFoundException {
        try(
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream dos = new ObjectOutputStream(baos);
            ){
            dos.writeObject("asdf");
            Employee employee = new Employee("张三", 10000);
            dos.writeObject(employee);
            dos.flush();
            byte[] datas = baos.toByteArray();
            
            ObjectInputStream dis = new ObjectInputStream(new ByteArrayInputStream(datas));
            // 调用顺序与写入一样
            Object msg = dis.readObject();
            Object emp = dis.readObject();
            if (msg instanceof String) {
                String msgObj = (String)msg;
                System.out.println(msgObj);
            }
            if (emp instanceof Employee) {
                Employee empObj = (Employee)emp;
                System.out.println(empObj);
            }
        }catch(IOException e) {
            e.printStackTrace();
        }    
    }
}

// javabean, 用来封装数据
class Employee implements Serializable{
    private String name;
    private double salary;
    
    public Employee() {
        
    }
    public Employee(String name, double salary) {
        super();
        this.name = name;
        this.salary = salary;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
    @Override
    public String toString() {
        return "Employee [name=" + name + ", salary=" + salary + "]";
    }
    
}
commonsIO 使用方法

遍历文件夹等, 很多可以直接使用.

工作中更多的使用这种成品工具, 像类似上边的自己实现, 不是很多机会.

原文地址:https://www.cnblogs.com/moveofgod/p/12447138.html