美文网首页
Java I/O流基础

Java I/O流基础

作者: Tinyspot | 来源:发表于2022-08-29 07:28 被阅读0次

1. 流

概念:内存与存储设备之间传输数据的通道

1.1 流的分类

按方向
输入流:将存储设备中的数据读取到内存
输出流:将内存中的数据写入存储设备
文件 ---输入流--> 程序 ---输出流--> 文件

按单位
字节流:以字节为单位,可以读写所有数据
字符流:以字符为单位,只能读写文本数据

按功能
节点流:具有实际传输数据的读写功能
过滤流:在节点流的基础之上增强功能

1.2 字节 VS 字符

  • 字节(英语:Byte),通常用作计算机信息计量单位,不分数据类型。
  • 字符,任何一个文字或符号都是一个字符,但所占字节不一定,不同的编码导致一个字符所占的内存不同
  • 字符的集合就叫字符集

1 Byte = 8 bits
1 KB = 1024 Bytes
1 MB = 1024 KB
1 GB = 1024 MB

2. 字节流

基本的流按字节读写,没有缓冲区
抽象父类 InputStream / OutputStream

public abstract class InputStream implements Closeable {
  /**
   *  Reads the next byte of data from the input stream
   *  If no byte is available, the value -1 is returned
    */
  public abstract int read() throws IOException;
  public int read(byte b[]) throws IOException {}
  // len – the maximum number of bytes to read.
  public int read(byte b[], int off, int len) throws IOException {}
}
public abstract class OutputStream implements Closeable, Flushable {
  // The byte to be written is the eight low-order bits of the argument b. The 24 high-order bits of b are ignored
    public abstract void write(int b) throws IOException;
}

2.1 FileInputStream

如果文件不存在,会抛出异常FileNotFoundException,如果当前用户没有读的权限,会抛出异常SecurityException

    // demo.txt  内容:abcd
    InputStream fis = new FileInputStream("src/main/resources/demo.txt");
    int length = 0;
    while ((length = fis.read()) != -1) {
        System.out.println(length);
    }
    fis.close();

打印的结果是:97 98 99 100
原因 read() 是一个字节一个字节的读取
改为 System.out.println((char) length); 会打印 a b c d

一次读取多个字节

    InputStream fis = new FileInputStream("src/main/resources/demo.txt");
    byte[] buf = new byte[3];
    int bytes = fis.read(buf);
    System.out.println(new String(buf)); // abc

    // new String(buf, 0, bytes)
    因为最后一次读取的数据可能不够 3 个字节,所以要指定长度

循环读取多次

    InputStream fis = new FileInputStream("src/main/resources/input.txt");
    byte[] buf = new byte[3];
    int bytes = 0;
    while ((bytes = fis.read(buf)) != -1) {
        System.out.println(new String(buf, 0, bytes));
    }
    fis.close();

// String(byte bytes[], int offset, int length, String charsetName)
new String(buf, 0, bytes, "UTF-8");

2.2 FileOutputStream

    OutputStream out = new FileOutputStream("src/main/resources/out.txt");
    out.write(97);
    out.write('b');
    out.close();
    // OutputStream out = new FileOutputStream("src/main/resources/out.txt");
    // append:true 追加的方式写入文件,默认时覆盖文件内容
    OutputStream out = new FileOutputStream("src/main/resources/out.txt", true);
    String str = "hello world";
    out.write(str.getBytes());
    out.close();

边读边写

public static void main(String[] args) throws Exception {
    InputStream input = new FileInputStream("src/main/resources/input.txt");
    OutputStream out = new FileOutputStream("src/main/resources/out.txt");
    // 1024 Byte = 1K
    byte[] buf = new byte[1024];
    int bytes = 0;
    while ((bytes = input.read(buf)) != -1) {
        out.write(buf, 0, bytes);
    }
    input.close();
    out.close();
}

读取全部后再打印

byte[] buf = new byte[1024];
int off = 0;
int len = 0;
// 每次读取 buf.length 到 buf 数组
while ((len = fis.read(buf)) != -1) {
    off += len;
}
String data = new String(buf, 0, off, "UTF-8");

2.3 ByteArrayInputStream / ByteArrayOutputStream

  • ByteArrayOutputStream的输出目标是一个byte数组,这个数组的长度是根据数据内容动态扩展的

3. 字节缓冲流

缓冲流:BufferedInputStream / BufferedOutputStream
数据存储在缓冲区,提高 I/O 效率,减少访问磁盘的次数

public class BufferedInputStream extends FilterInputStream {
    // 默认缓存区:8K
    private static int DEFAULT_BUFFER_SIZE = 8192;
    public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
    }
}

public class BufferedOutputStream extends FilterOutputStream {
    public BufferedOutputStream(OutputStream out) {
        this(out, 8192);
    }
}

3.1 BufferedInputStream

    InputStream input = new BufferedInputStream(new FileInputStream("src/main/resources/input.txt"));
    int bytes = 0;
    while ((bytes = input.read()) != -1) {
        System.out.println((char) bytes);
    }
    input.close();

也可以自己设置缓存区大小

    InputStream input = new BufferedInputStream(new FileInputStream("src/main/resources/input.txt"));
    byte[] buf = new byte[1024];
    int bytes = 0;
    while ((bytes = input.read(buf)) != -1) {
        System.out.println(new String(buf, 0, bytes));
    }
    input.close();

3.2 BufferedOutputStream

    OutputStream out = new BufferedOutputStream(new FileOutputStream("src/main/resources/out.txt", true));
    for (int i = 0; i < 10; i++) {
        // 写入缓冲区,此时还未写入文件,需要再调用 flush()
        out.write("hello\r\n".getBytes());
        out.flush();
    }
    // 关闭,内部也会调用flush()
    out.close();

4. 对象流

  • 增强了缓存区功能
  • 可以读写 8 种基本数据类型和字符串
  • 可以读写对象
    • readObject() 从流中读取一个对象
    • writeObject(Object obj) 向流中写入一个对象

4.1 ObjectInputStream / ObjectOutputStream

public class Server {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ServerSocket serverSocket = null;
        serverSocket = new ServerSocket(8080);

        while (true) {
            Socket socket = serverSocket.accept();
            ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
            User user = (User) input.readObject();
            System.out.println(user);
        }
    }
}
public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = null;
        socket = new Socket("localhost", 8080);

        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
        User user = new User("Tinyspot", 20);
        out.writeObject(user);

        socket.close();
    }
}

4.2 序列化多个对象

  • 可以借助集合实现
public static void main(String[] args) throws Exception {
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("src/main/resources/student.bin"));
    List<Student> list = Arrays.asList(new Student("tinyspot", 20), new Student("echo", 25));
    out.writeObject(list);
    out.close();

    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/main/resources/student.bin"));
    List<Student> students = (List<Student>) ois.readObject();
    ois.close();
    System.out.println(JSON.toJSONString(students));
}

public class Student implements Serializable {
    // 序列化版本号,保证序列化和反序列化的是同一个类
    private static final long serialVersionUID = -3881208742057626511L;

    private String name;
    private transient Integer age;
}

相关文章

  • Java基础知识15-I/O流1

    I/O的基础知识 流 Java 程序通过流执行 I/O. 流是一种抽象, 要么产生信息, 要么使用信息. 流通过 ...

  • Java基础--I/O流

    导语: 记得刚刚学习Java I/O的时候,被输入输出流的层次结构吓得不轻,一整个流家族里面,包含了各种流类型,其...

  • java基础-I/O流

    知识点 I/O流的基本知识 I/O流中常用流的关系 I/O流之FileInputSrteam,FileOutput...

  • Java I/O流基础

    1. 流 概念:内存与存储设备之间传输数据的通道 1.1 流的分类 按方向输入流:将存储设备中的数据读取到内存输出...

  • Java IO

    两个基础流 基于字节 InputStream OutputStream Java 的 I/O 操作类在包 java...

  • [Java Tutorials] 05 | Java Basic

    Basic I/O 基本输入输出 本节包含了Java平台所提供的用于基础I/O的类。首先介绍的是I/O流,一个非常...

  • I/O流

    java常见的I/O流

  • Java I/O流

    文件的读写是java i/o流常用的也是最基础的操作,然而字节流,字符流,InputStream,OutpurSt...

  • Java中的I/O流

    谷歌I/O大会,现在赶一下时髦,在这里说一下Java的I/O流。I/O流可以简单的理解input/output流,...

  • JavaSE Day19 IO

    1. Java 中常用的 I/O 流常用类型在哪个包?常用类型有哪些? I/O 流的常用类型都在 java.io ...

网友评论

      本文标题:Java I/O流基础

      本文链接:https://www.haomeiwen.com/subject/myarsrtx.html