Java IO

File类

File类是对文件系统中文件以及文件夹进行操作的类,通过面向思想操作文件和文件夹

不同的系统有不同的分隔符 Window系统的路径名称分隔符是:\\ Linux系统的分隔符是:/ 

可以通过File.separator获取系统分隔符

String path="C:"+File.separator+"hello.txt";
方法作用
createNewFile()当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
mkdir()创建由此抽象路径名命名的目录。只创建一级目录
mkdirs()创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。可以创建多级目录

删除文件/文件夹 

delete()删除由此抽象路径名表示的文件或目录。

获取文件/文件夹

方法作用
getName()返回由此抽象路径名表示的文件或目录的名称。
getParent()返回此抽象路径名的父路径名字符串,如果此路径名未命名为父目录,则返回null
getPath()将此抽象路径名转换为路径名字符串。

 判断文件/文件夹是否存在

exists()测试此抽象路径名表示的文件或目录是否存在。
isFile()测试此抽象路径名表示的文件是否为普通文件
isDirectory()测试此抽象路径名表示的文件是否为目录。

 遍历文件夹

方法作用
list()返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。
listFiles(FileFilter f)返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录

如果只遍历某个目录下的图片实现FileFilter接口和 listFiles(FileFilter f) 方法可以快速实现 。

获取文件的大小

方法作用
length()返回由此抽象路径名表示的文件的长度
    • File​(File parent, String child)

      从父抽象路径名和子路径名字符串创建新的 File实例。

      File​(String pathname)

      通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。

      File​(String parent, String child)

      从父路径名字符串和子路径名字符串创建新的 File实例。

 传入的路径的字符串如果是相对路径是相对于Project所在路径的。

File file = new File("D:\\java\\file1.txt"); //双\\为转义字符
System.out.println(file);
File file2 = new File("D:\\java","file2.txt");//父路径,子路径
System.out.println(file2);
File parent = new File("D:\\java");
File file3 = new File(parent,"file3.txt");//父路径,子路径
System.out.println(file3);
        //获取文件分隔符
        String separator=File.separator;
        File d=new File("c:"+separator+"test");
        if(!d.exists()) {
            /*
                创建新的目录(文件夹),这里只有一级目录,所以可以使用mkdir()创建
                如果是C://test//abc,test目录不存在,必须使用mkdirs()创建,否则报错

            */
            d.mkdirs();
        }
      
        System.out.println("这是目录?"+d.isDirectory());
        //声明文件
        File f=new File("c:"+separator+"test"+separator+"ab.txt");
        //判断文件/文件夹是否存在,!表示flase时执行下面语句
        if(!f.exists()) {
            //创建新的文件
            f.createNewFile();
        }
        //获取文件名
        System.out.println(f.getName());
        //获取上一级目录
        System.out.println(f.getParent());
        //获取全局路径
        System.out.println(f.getPath());
        //判断是不是文件
        System.out.println(f.isFile());
        //获取长度
        System.out.println(f.length());
        //获取目录下的文件/文件夹
        String[] fe=d.list();
        //遍历目录下的所有文件
        for(String s:fe) {
            System.out.println(s);
        }
        //删除文件
        f.delete();
        //删除目录
        d.delete();
        }
  public static void listFiles(File[]files){
        if (files!=null&&files.length>0){
            for (File file : files) {
                if (file.isFile()){
                    if (file.getName().endsWith(".avi")){
                        if (file.length()>200*1024*1024){
                            file.delete();
                            System.out.println(file.getAbsolutePath()+"已被删除");
                        }
                    }
                }else {
                    File[] files1 = file.listFiles();
                    listFiles(files);
                }
            }
        }
    }//递归删除大小超过200MB的.avi文件(删除会彻底删除不会到回收站,因此千万不要随便删除文件,尤其是c盘的文件)

 以上方法可以使用listFiles(FileFilter f)方法简化

什么是IO流?  

流是一种抽象概念,它代表了数据的无结构化传递(数据的流从源头流到目的地)。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。比如文件拷贝,包括了输入流和输出流。输入流从文件中读取数据存储到进程(process)中,输出流从进程中读取数据然后写入到目标文件。简而言之,以流的形式对文件读写操作。数据的传输类似”水流"。所有 I/O 都被视为单个的 字节的移动,通过一个称为 Stream 的对象一次移动一个字节。

Java 中 IO 流的分类?

1 按照流的方向:输入流(inputStream)和输出流(outputStream)

2 按照实现功能分:节点流(可以从或向一个特定的地方读写数据(直接对文件的读写操作),如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写如BufferedReader)

3 按照处理数据的单位: 字节流字符流。分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个)其余的流都是由它们派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输⼊流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
  1. 字节流:操作 byte 类型数据,主要操作类是 OutputStream、InputStream 的子类;不用缓冲区,直接对文件本身操作。字节流适合所有类型文件的数据传输(因为计算机字节(Byte)是电脑中表示信息含义的最小单位)若只是读写文件,和文件内容无关时,一般选择字节流.
  2. 字符流:操作字符类型数据,主要操作类是 Reader、Writer 的子类;使用缓冲区缓冲字符, 不关闭流就不会输出任何内容。字符流只能够处理纯文本数据,其他类型数据不行,但是字符流处理文本要比字节流处理文本方便。在读写文件需要对内容按行处理,比如比较特定字符,处理某一行数据的时候一般会选择字符流.

节点流(类)有:(能直接对文件的读写操作)

  1. 字节流:OutputStream(输出)、InputStream(输入)  -- 子类:FileOutputStream,FileInputStream
  2. 字符流:Writer(输出)、Reader(输入)  -- 子类FileWriter,FileReader

处理流可以分为转化流和装饰流

转化类:在读取文件的时候会常常遇到乱码,而转化类可以帮助转换为对应的字符编码格式。

OutputStreamWriter(输出流使用),InputStreamReader(输入流使用)

装饰类:在流的传输过程中,使用缓存进行了”装饰“。

  • 字节缓存流:BufferedOutputStream(输出缓存)、BufferedInputStream(输入缓存)
  • 字符缓存流:BufferedWriter(输出缓存)、BufferedReader(输入缓存)

既然有了字节流,为什么还要有字符流?

不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流 操作要分为字节流操作和字符流操作呢? 因为字节流是由 Java 虚拟机将字节转换得到的,但是这个过程十分耗时,并且,如果不知道编码类型就很容易出现乱码。所以, I/O 流就提供了⼀个直接操作字符的接口, 方便平时对字符进行流操作。音频,图片等媒体文件使用字节流比较好,如果涉及到字符的话使用字符流比较好。

Java一个汉字占几个字节

https://www.cnblogs.com/lslk89/p/6898526.html

 字节流和字符流哪个好?
大多数情况下使用字节流会更好,因为字符流是字节流的包装,而大多数时候IO操作都是直接操
作磁盘文件、所以任何流在传输时都是以字节的方式进行的(图片,视频等文件都是按字节存储)
如果对于操作需要通过IO在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能。

字节流如何转为字符流?

字节输入流转字符输入流通过 InputStreamReader 实现,该类的构造函数可以传入 InputStream 对 象。 字节输出流转字符输出流通过 OutputStreamWriter 实现,该类的构造函数可以传入 OutputStream 对象。

同步、异步

同步与异步描述的是被调用者的。 如 A 调用 B: 如果是同步,B 在接到 A 的调用后,会立即执行要做的事。A 的本次调用可以得到结 果。 如果是异步,B 在接到 A 的调用后,不保证会立即执行要做的事,但是保证会去做,B 在做好了之后会通知 A。A 的本次调用得不到结果,但是 B 执行完之后会通知 A。

阻塞、非阻塞

阻塞与非阻塞描述的是调用者的。 如 A 调用 B: 如果是阻塞,A 在发出调用后,要一直等待,等着 B 返回结果。 如果是非阻塞,A 在发出调用后,不需要等待,可以去做自己的事情。

从操作系统理解Java的IO

https://mp.weixin.qq.com/s/p5qM2UJ1uIWyongfVpRbCg

IO模型有几种?

阻塞IO,非阻塞IO,多路复用IO,信号驱动IO以及异步IO

什么是阻塞IO?什么是非阻塞IO?

IO操作包括:对硬盘的读写、对socket的读写以及外设的读写。

当用户线程发起一个IO请求操作,内核会去查看要读取的数据是否就绪,对 于阻塞IO来说,如果数据没有就绪,则会一直等待,直到数据就绪.

对于非阻塞IO来说,如果数据 没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪。当数据就绪之后,便将数据 拷贝到用户线程,这样才完成了一个完整的IO读请求操作,也就是说一个完整的IO读请求操作包括两个 阶段:

  1. 查看数据是否就绪;
  2. 进行数据拷贝(内核将数据拷贝到用户线程)

阻塞(blocking IO)和非阻塞(non-blocking IO)的区别就在于第一个阶段,如果数据没有就绪, 在查看数据是否就绪的过程中是一直等待,还是直接返回一个标志信息。 Java中传统的IO都是阻塞IO,比如通过socket来读数据,调用read()方法之后,如果数据没有就绪,当 前线程就会一直阻塞在read方法调用,直到有数据才返回;当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数 据就绪,而用户线程就会处于阻塞状态,用户线程交出 CPU。当数据就绪之后,内核会将 数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除 block 状态。

而如果是非阻塞IO的话,当数据没有就 绪,read()方法应该返回一个标志信息,告知当前线程数据没有就绪,而不是一直在等待。当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果 结果是一个 error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。一旦 内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了 用户线程,然后返回。 所以在非阻塞 IO 模型中,用户线程需要不断地询问内核数据是否就绪,也就是非阻塞 IO 。不会交出 CPU,而会一直占用 CPU

BIO、NIO、AIO的区别?

  • BIO:同步并阻塞,在服务器中实现的模式为一个连接一个线程。也就是说,客户端有连接请求 的时候,服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然这也可以通过线程池机制改善。BIO一般适用于连接数目小且固定的架构,这种方式对 于服务器资源要求比较高,而且并发局限于应用中,是JDK1.4之前的唯一选择,但好在程序直观简单,易理解。数据的读取写入必须阻塞在一个线程内等待其完 成。在活动连接数不是特别高(小于单机 1000)的情况下,这种模型很合适,可以让每 ⼀个连接专注于自己的 I/O 并且编程模型简单,也避免过多考虑系统的过载、限流等问题。线程池本身就是⼀个天然的漏斗,可以缓冲⼀些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要⼀种更高效的 I/O 处理 模型来应对更高的并发量。
  • NIO:同步并非阻塞,在服务器中实现的模式为一个请求一个线程,也就是说,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到有连接IO请求时才会启动一个线程进行处理。 NIO一般适用于连接数目多且连接比较短(轻操作)的架构,并发局限于应用中,编程比较复杂,在 Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象(组件)。NIO 中的 N 可 以理解为 Non-blocking,不仅仅是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。 NIO 提供了与传统 BIO 模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模 式。阻塞模式使用比较简单,但是性能和可靠性都不好;非阻塞模式相反。对于低负载、低并发的应用程序,可以使用同步阻塞 I/O 来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
  • AIO:异步并非阻塞,在服务器中实现的模式为一个有效请求一个线程,也就是说,客户端的IO 请求都是通过操作系统先完成之后,再通知服务器应用去启动线程进行处理。AIO一般适用于连接 数目多且连接比较长(重操作)的架构,充分调用操作系统参与并发操作,编程比较复杂,在 Java 7 中引入了 NIO 的改进版 NIO 2,它是 异步非阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞,当后台处理完成,操作系统会通知相应的线程进行后续操作。虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO 操作本身是同步的。目前AIO的应用不是非常广泛。
Reader reader = new InputStreamReader(inputStream);//适配器模式
new BufferedInputStream(new FileInputStream(inputStream));//装饰者模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值