java I/O流详解

  • Post author:
  • Post category:java



目录


一、 I/O(Input/Output)流是什么?


什么是流?


输入输出如何理解?


流的分类?


二、 字节流、字符流、缓冲流。


字节流、字符流能做什么?


字节流读取文件?


字节流写出文件?


字节流缓冲区拷贝文件?


字节流缓冲流拷贝文件?


字符流读取文件?


字符流写出文件?


字符流拷贝文件?


字符缓冲区拷贝文件?


字符缓冲流拷贝文件?


字符流底层是什么??


转换流


File类


一、 I/O(Input/Output)流是什么?

什么是流?

流定义:

流是一组有顺序

的,有起点和终点的字节集合,是对数据传输的总称或抽象。



数据在两设备间的传输称为流



流的本质是数据传输

输入输出如何理解?

I/O 流定义:I/O流 即 输入流和输出流。

分析:输入就是将数据从各种输入设备(包括文件、键盘等)读取到内存中。

输出就是将数据写入到各种输出设备(如文件、显示器、磁盘)中.

键盘为标准的输入设备,显示器为标准的输出设备,文件既是输入设备、也是输出设备。

流的分类?

流的方向:

输入流:程序可以中读取数据的流。

输出流:程序能向其中写入数据的流。

流的单位:

字节流:以字节为单位传输数据的流

字符流:以字符为单位传输数据的流

流的功能:

节点流:直接和文件进行交互

处理流:不是直接作用在文件上


详解:

1. 一种方式是以

按照流的方向

进行分类

输入流:以内存为参照物:往内存中去,叫做输入(Input),或者叫做读(Read)。

输出流:从内存中出来,叫做输出(Output),或者叫做写(Write)

2.另一种方式是以按照

读取数据方式

不同进行分类

字节流:按照

字节的方式读取数据

,称为字节流。一次读取1个字节,等同于一次读取8个二进制位。这种

流什么类型的文件都可以读取

。如文本文件、图片、声音、文件、视频文件。

字符流:按照

字符的方式读取数据

,称为字符流、

一次读取一个字符

,这种流是为了方便读取普通的文件文件而存在的,这种流不能读取:图片、声音、视频等文件,

只能读取纯文本文件

,连word文件都可以读取。


二、 字节流、字符流、缓冲流。

字节流、字符流能做什么?

字节流图解:

输入流

输出流

字节流读取文件?

    public static void main(String[] args)throws IOException {
        // 创建输入流对象
        FileInputStream a = new FileInputStream("a.txt");
        // 定义临时变量,每次读取数据让变量记录
         int i;
         // 读取到-1的时候说明读取结束,跳出循环
        while ((i=a.read())!=-1){
            System.out.print((char) i+" ");
        }
        // 关闭流释放资源
        a.close();
    }

字节流写出文件?

    public static void main(String[] args)throws IOException {
        // 创建字节输出流对象   不清楚原有内容加上true
        FileOutputStream a = new FileOutputStream("a.txt",true);
        //   写入的字符串返回字节数组写入
        a.write("Hello,world".getBytes());
        // 关闭流释放资源
        a.close();
    }

字节流缓冲区拷贝文件?

    public static void main(String[] args) throws IOException {
        // 创建字节输入输出流对象
        FileInputStream a = new FileInputStream("a.txt");
        FileOutputStream b = new FileOutputStream("b.txt");
        byte [] arr = new byte[1024];
        // 创建临时变量
        int i;
        while ((i=a.read(arr))!=-1){
            // 读取的数据写入进去  完成文件拷贝
            b.write(arr,0,i);  // 数组 从0开始 到i结束写入
        }
        // 关闭流释放资源
        a.close();b.close();
    }

字节流缓冲流拷贝文件?

    public static void main(String[] args) throws IOException {
        // 创建字节输入输出缓冲流对象
        BufferedInputStream a = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream b = new BufferedOutputStream(new FileOutputStream("b.txt"));
        // 创建临时变量
        int i;
        while ((i = a.read()) != -1) {
            // 读取的数据写入进去  完成文件拷贝
            b.write(i);  //
        }
        // 关闭流释放资源
        a.close();
        b.close();
    }

字符流图解:

输入流


输出流

字符流读取文件?

    public static void main(String[] args) throws IOException {
        // 创建字符流对象
        FileReader fileReader = new FileReader("E:\\a.txt");
        // 创建临时变量 存储数据
        int i;
        while ((i=fileReader.read())!=-1){
            System.out.println((char) i);

        }
        // 关闭流释放资源
        fileReader.close();
    }

字符流写出文件?

  public static void main(String[] args) throws IOException {
        // 创建字符输出流对象 写入文件
        FileWriter fileWriter = new FileWriter("E:\\b.txt");
        // 写入 
        fileWriter.write("你好,世界");
        // 关闭流释放系统资源
        fileWriter.close();
    }

字符流拷贝文件?

 public static void main(String[] args) throws IOException {
        // 创建输入输出流对象
        FileReader a = new FileReader("E:\\a.txt");
        FileWriter b = new FileWriter("E:\\b.txt");
        // 定义临时变量
        int i ;
        // 读取到的写入进去
        while ((i=a.read())!=-1){
            b.write(i);
        }
        // 关闭流释放系统资源
         a.close();b.close();
    }

字符缓冲区拷贝文件?

    public static void main(String[] args) throws IOException {
        // 创建输入输出流对象
        FileReader a = new FileReader("E:\\a.txt");
        FileWriter b = new FileWriter("E:\\b.txt");
        // 定义字符数组
        char[] chars = new char[1024];
        // 定义临时变量
        int i ;
        // 读取到的存储到数组在写入数据
        while ((i=a.read(chars))!=-1){
            b.write(i);
        }
        // 关闭流释放系统资源
         a.close();b.close();
    }

字符缓冲流拷贝文件?

    public static void main(String[] args) throws IOException {
        // 创建缓冲流对象
        BufferedReader a = new BufferedReader(new FileReader("a.txt"));
        BufferedWriter b = new BufferedWriter(new FileWriter("b.txt"));
        // 定义临时变量
        String c = null;
        //  循环每次读取一行文本
        // readLine不会读取到回车换行符  new Line可以读取到回车换行符
        while ((c=a.readLine())!=null){
            b.write(c);
            b.newLine();
        }
        // 关闭流释放系统资源
        a.close();b.close();
    }

字符流底层是什么??

解决问题:字符流底层通过字节流 + 编号表的形式读取。

编号表:  GBK->  一个中文占2个字符

UTF-8-> 一个中文占3个字符

例如windows txt文件默认是utf-8,java编译时也应该是utf-8,否则会出现乱码问题。

转换流

当文件含有中文、英文、数字时,使用字节流将文件内容在内存中显示

,英文和数字显示正常,中文却现实乱码,可以使用转换流将其转化为字符流显示在内存中

转换流:InputStreamReader: 将InputStream转换为Reader

OutputStreamWriter: 将Writer转换为OutputStream

作用:

文本文件在硬盘中以

字节流的形式存储时

通过InputStreamReader读取后转化为字符流给程序处理,程序处理的字符流通过OutputStramWriter转化为字节流保存。

特点:

读取到的字节数据经过指定编码转换为字符。

可对读取到的字符数据经过指定编码转换成字节。

何时使用转换流?

当字节和字符之间有转换动作时;

流操作的数据需要编码或解码时;

作用:提供字节流与字符流之间的转换,很多时候使用转换流来处理文件乱码问题,实现编码和解码的功能。

解码:字节,字节数组->字符、字符数组

编码:字符,字符数组->字节、字节数组

 public static void main(String[] args) throws IOException {
        // 创建缓冲流对象 指定编码格式
        InputStreamReader a = new InputStreamReader(new FileInputStream("a.txt"), "utf-8");
        OutputStreamWriter b = new OutputStreamWriter(new FileOutputStream("b.txt"), "utf-8");
        // 创建 字符缓冲流
        BufferedReader c = new BufferedReader(a);
        BufferedWriter d = new BufferedWriter(b);
        String e;
        while ((e=c.readLine())!=null){
            d.write(e);
            d.newLine();
        }
        // 关闭流释放系统资源
        c.close();d.close();
    }

三、File类

File类可以做什么?

定义:File类是I/O包中唯一代表磁盘文件本身的对象。向文件名、路径、目录等等

作用:用于封装一个路径,提供了一系列的方法用于操作该路径所指向的文件。

File类的构造方法

    public static void main(String[] args) throws IOException {
        // 指定路径创建文件夹对象
        File file = new File("E:\\a.txt");
        //  父路径 子路径 创建文件夹对象
        File file2 = new File("E:","a.txt");
        // File类的父路径   子路径
        File file3 = new File(new File("E:"),"a.txt");
    }

File类的常用方法

    public static void main(String[] args)throws IOException {
        // 创建目录对象
        File file = new File("E:\\a.txt");
        // 判断目录或文件是否存在,存在true,反之false
        System.out.println(file.exists());
        // 删除目录或文件夹
        System.out.println("E:\\a.txt");
        // 当File对应的文件或目录不存在时,创建一个新的文件,成功true,反之false。
        System.out.println(file.createNewFile());
        // 返回文件夹或文件名称
        System.out.println(file.getName());
        //  返回file对象对应的路径
        System.out.println(file.getPath());
        // 返回file对象对应的绝对路径
        System.out.println(file.getAbsoluteFile());
        // 返回路file对象对应的父目录
        System.out.println(file.getParent());
        //判断文件是否可读
        System.out.println(file.canRead());
        //判断文件是否可写
        System.out.println(file.canWrite());
        // 判断是否是文件
        System.out.println(file.isFile());
        // 判断是否是文件夹
        System.out.println(file.isDirectory());
        // 判断对应的文件是否是绝对路径
        System.out.println(file.isAbsolute());
        //返回1970年1月1日0时0分0秒最后修改时间的毫秒值
        System.out.println(new Date(file.lastModified()));
        // 返回文件的长度
        System.out.println(file.length());
    }

File遍历文件夹

    public static void main(String[] args)throws IOException {
        //  String [ ] list : 列出指定目录的全部内容,只是列出名称
        File file = new File("E:");
        String[] list = file.list();
        for (String a:list){
            System.out.println(a);
        }
        // String [] list  FilenameFilterfilter  接受一个FilenameFilter参数,通过该参数可以列出符合条件的文件
        File file2 = new File("E:");
        String[] list1 = file2.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                File file1 = new File(dir,name);
                return name.endsWith("txt");
            }
        });
        //  File [] listFiles    返回一个包含了File对象所有子文件和子目录的File数组
        System.out.println(Arrays.toString(list1));
        File file3 = new File("E:");
        File[] files = file3.listFiles();
        System.out.println(Arrays.toString(files));
    }
   public static void main(String[] args) throws IOException {
        //  遍历文件夹
        File file = new File("E:");
        // 判断是否是文件夹
        if (file.isDirectory()) {
            // 创建数组
            String[] list = file.list();
            // 转换流循环遍历
            Arrays.stream(list).forEach((s -> System.out.println(s)));
        }

        // 筛选文件夹
        File file2 = new File("E:");
        // 判断是否是文件夹
        if (file2.isDirectory()) {
            String[] list2 = file.list((dir, name) -> name.endsWith("txt"));
            Arrays.stream(list2).forEach((s -> System.out.println(s)));
        }

       // 遍历指定目录下的文件名称
        bian(new File("E:"));
    }
      public static void bian(File dir){
          File[] files = dir.listFiles();
          for (File a:files){
              if(a.isFile()){
                  System.out.println(a.getName());
              } else if (a.isDirectory()) {
                  if((a.listFiles())!=null){
                      bian(a);
                  }
              }
          }
      }

递归删除文件及目录

    public static void main(String[] args) throws IOException {
     //在使用该方法时需要判断当前目录下是否存在文件,如果存在则需要先删除内部文件然后在删除空的文件夹
        shan(new File("E:"));
    }
    public static void shan(File dir){
        // 创建File数组
        File[] files = dir.listFiles();
        // 循环遍历
        for (File a:files){
            // 判断是否为文件
            if(a.isFile()){
                a.delete();
                // 判断是否为文件夹
            }else if(a.isDirectory()){
                // 判断文件夹是否为空
                if ((a.listFiles())!=null){
                    shan(a);
                }
            }
            a.delete();
        }
    }


RandomAccesseFile

定义:不属于流类,但具有读写文件数据的功能。

作用:可以随机从文件的任何位置开始并以指定的操作权限(只读、写入)执行读取数据的操作。

实现原理:

(1) 新建RandomAccessFile对象时,该对象的文件记录指针会在文件开始出(表示为0的位置)

(2)读写的n个字节后,文件记录指针会向后移动n个字节。

(3)除了按顺序读写外,RandomAccseeFile对象还可以自由的移动记录指针,既可以向前移动,也可以向后移动。

    public static void main(String[] args) throws IOException {
        // 创建对象, 写入的方式写入。
        RandomAccessFile c = new RandomAccessFile("a.txt", "rw");
        // ReadLine   从指针文件当去指针读取下一行内容
        String s = c.readLine();
        // 字符串转换为int类型 -1 
        int i = Integer.parseInt(s) - 1;
        if (i > 0) {
            System.out.println("剩余" + i + "次");
            // seek,设定读写指针的位置,与文件开头相隔pos个字节数
            c.seek(2);  // 与开头相隔2个
            // 转换为字节数组写入
            c.write((i + "").getBytes());
        } else {
            System.out.println("没了");
        }
        c.close();
    }


对象序列化

定义:java对象转换成一个I/O流中字节序列的过程

作用:可以将对象中的数据保存到磁盘上。

功能类

public class Day_01 implements Serializable {
    private static final long serialVersionUID = 1L;
  private String name;
  private  int age;

    public Day_01(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Day_01{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类

    public static void main(String[] args) throws Exception {
        write();
        read();
    }

    public static void write() throws IOException {
        ObjectOutputStream b = new ObjectOutputStream(new FileOutputStream("a.txt"));
        Day_01 day_01 = new Day_01("a", 15);
        b.writeObject(day_01);
        b.close();
    }

    public static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream c = new ObjectInputStream(new FileInputStream("a.txt"));
        Object o = c.readObject();
        System.out.println(o);
        c.close();
    }

NIO

NIO了解

定义:NIO即new n/o, 处理输入输出的新功能。

NIO的三大核心

Buffer(缓冲器): 是一个数组缓冲器,读取或写出到channnel中的对象都会先放在Buffer中(它是双向的)。

Channel(通道):对传统的输入/输出的模拟,在NIO中,所有的数据都需要通过通道流的形式传输。

Selecter(选择器):用于监听多个通道的时间,主要作用于线程(多线程进行讲解)。

注意:通道本身不能完成传输,需要依赖于缓冲器,两者是并存的。

Buffer缓冲器

作用:主要用于和Channel通道配合,完成数据的传输。

说明:Buffer是一个抽象类,它需要使用其子类:ByteBuffer、charBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和shortBuffer。

方法:

Capacity()           容量

Limit()         可以操作到哪个索引(界限)

Position()    当前准备操作的索引

Mark()                 标记,用来记录当前position 的值

Reset()          如果position的值发生了变化,那么通道随reset可以反馈mark记录的那个值

Put()                    向缓冲器中添加数据

Get()                    获取缓冲器中的数据

    public static void main(String[] args) throws Exception {
        // 写入模式,缓冲器放入2个字节,容量为5,界限为5,准备索引为2
        ByteBuffer allocate = ByteBuffer.allocate(5); // 分配新的字节缓冲区
        allocate.put("a".getBytes());
        allocate.put("b".getBytes());
        System.out.println(allocate.capacity());  // 容量
        System.out.println(allocate.limit()); // 可以操作到哪个索引
        System.out.println(allocate.position());  // 准备操作的索引
        // 切换读取模式
        allocate.flip();
        System.out.println(allocate.capacity());
        System.out.println(allocate.limit());
        System.out.println(allocate.position());
        // 标记
        allocate.mark();
        // 放入字节数组,转为字符串读取
        byte[] bytes = new byte[2];
        allocate.get(bytes);
        System.out.println(new String(bytes));
        System.out.println(allocate.capacity());
        System.out.println(allocate.limit());
        System.out.println(allocate.position());
        // mark 反馈记录的值
        allocate.reset();
        allocate.get(bytes);
        System.out.println(new String(bytes));
        System.out.println(allocate.capacity());
        System.out.println(allocate.limit());
        System.out.println(allocate.position());
    }

channel通道

定义:Channel是一个接口对象,从Channel中读取数据,也可以将数据写道Channel中。

方法:

Int write()            从给定的缓冲区写入这个通道的字节序列

Long size()          返回该通道文件的当前大小

Int read()                    从这个通道读取一个字节序列到给定的缓冲区

Long transferTo()      读取该通道文件中给定位置的字节数,将它们写入目标通道中

案例:使用通道  缓冲器 实现对文件的拷贝

    public static void main(String[] args) throws Exception {
        // 创建对象
        FileInputStream a = new FileInputStream("a.txt");
        FileOutputStream b = new FileOutputStream("b.txt");
        // 创建通道
        FileChannel c = a.getChannel();
        FileChannel d = b.getChannel();
        //创建缓冲器
        ByteBuffer allocate = ByteBuffer.allocate(1024);
      // 读取到的数据放进通道中,切换读取模式,写入通道,清楚缓冲器数据。
        while ((c.read(allocate)) != -1) {
            allocate.flip();
            d.write(allocate);
            allocate.clear();
        }
        // 关闭流释放系统资源
        a.close();
        b.close();
        c.close();
        d.close();
    }

案例:使用RandomAccessFile创建通道拷贝文件

    public static void main(String[] args) throws Exception {
         // 创建对象
        RandomAccessFile a = new RandomAccessFile("a.txt","rw");
        RandomAccessFile b = new RandomAccessFile("a.txt","rw");
       //  创建通道
        FileChannel c= a.getChannel();
        FileChannel d = b.getChannel();
        //  读取该通道文件中给定位置的字节数,将它们写入目标通道中。
        long l = c.transferTo(0, c.size(), d);
        if(l>0){
            System.out.println("拷贝成功");
        }
    }

NIO.2 path接口和Files工具类

Files工具类

常用方法:

createDirectories(  )   创建多级文件夹

createFile( )         创建文件

write(  )                    将文本写入文件,并以传入指定的写入方式。

readllLines(   )         从文件中读取所有行

size(  )                     返回文件的大小,以字节为单位

    public static void main(String[] args) throws Exception {
        // 创建多级文件夹
        Path c = Paths.get("E:\\DD\\CC");
        Files.createDirectories(c);
        // 创建多级文件
        Path path = Paths.get("E:\\a.txt");
        Files.createFile(path);
        // 从文件中读取所有行,并传入指定的写入方式
        ArrayList<String> d = new ArrayList<>();
        d.add("D行");
        d.add("李S");
        Files.write(path, d, StandardOpenOption.APPEND); // 路径  内容 枚举
        // 从文件中读取所有行
        List<String> strings = Files.readAllLines(path);
        System.out.println(strings);
        // 返回文件的大小,以字节为单位。
        long size = Files.size(path);
        System.out.println(size);
    }



版权声明:本文为weixin_67573348原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。