Bit 位,是计算机最小的二进制单位 ,取0或1,主要用于计算机操作。 Byte 字节,是数据的最小单位,由8位bit组成,取值(-128-127),主要用于计算机操作数据。 Char 字符,是用户可读写的最小单位,由16位bit(2个byte)组成,取值(0-65535),主要用于用户操数数据。
IO流就是以流的方式进行输入输出 主要用来处理设备之间的传输,文件的上传,下载和复制 流分输入和输出,输入流从文件中读取数据存储到进程中,输出流从进程中读取数据然后写入到目标文件。
按照传输单位分为字符流和字节流。 字节流的父类是:InputStream,OutputStream 字节流的父类是:Reader,Writer 常用的IO流有: 输入–>InputStream:FileInputStream,BufferedInputStream 输出–>OutputStream:FileOutputStream,BufferedOutputStream Reader: BufferedReader Writer:BufferedWriter
按照传输方向主要分为输入流(InputStream)和输出流(OutputStream)
按照功能分为:节点流OutputStream、处理流 OutputStreamWriter 节点流 :直接与数据源相连,用于输入或输出 处理流:在节点流的基础上对之进行加工,进行一些功能的扩展
属于处理流中的缓冲流,可以将读取的内容存在内存里面,有readLine()方法读取一行文本,从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。
这种处理流的构造器需要传入字点流。
FileInputStream fil = new FileInputStream("D:\\0823.txt"); InputStreamReader inp =new InputStreamReader(fil); BufferedReader buf = new BufferedReader(inp); String data=null; //readLine()读一行文字 while ((data=buf.readLine())!=null){ System.out.println(data); } buf.close();是字节流通向字符流的桥梁,封裝了InputStream在里头, 它以较高级的方式,一次读取一个一个字符,以文本格式输入 / 输出,可以指定编码格式;
InputStreamReader isr = newInputStreamReader(new FileInputStream("ming.txt")); while((ch =isr.read())!=-1){ System.out.print((char)ch); }在拷贝文件操作的时候,经常用到的两个类。这两个流比较小,一般在处理小文件的时候,他们性能表现还不错,在大文件的时候,最好使用BufferedInputStream(或BufferedReader)和BufferedOutputStream(或BufferedWriter)
BufferedInputStream 使用缓冲流能够减少对硬盘的损伤
println是PrintStream的一个方法。Out是一个静态PrintStream类型的成员变量,system是一个java.lang包中的类,用于和底层的操作系统进行交互。
Printwriter 可以打印各种数据类型 PrintWriter和PrintStream类似,只不过PrintStream是针对字节流的,而PrintWriter是针对字符流的。
public static void main(String[] args) throws FileNotFoundException { String s1="我们"+"\n"; String s2="you"+"\n"; PrintWriter writer = new PrintWriter("D:\\01.txt"); writer.println(s1); writer.println(s2); writer.close(); }SetOut(printWriter,printStream)重定向
使用转换处理流OutputStreamWriter 可以将字节流转为字符流
New OutputStreamWriter(new FileOutputStream(File file));
DataInputStream DataOutputStream
ObjectInputStream ObjectOutputStream
对象序列化是将对象以二进制的形式保存在硬盘上或者传输到网络;而反序列化则是将二进制的文件转化为对象读取。 Jre本身就提供了序列化支持,我们可以调OutputStream的writeObject方法来做,如果要让java 帮我们做,要被传输的对象必须实现serializable接口,这样,javac编译时就会进行特殊处理,编译的类才可以被writeObject方法操作,这就是所谓的序列化。
serializable接口是一个mini接口,其中没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的。 如果不想让字段放在硬盘上就加transient。
是版本号,要保持版本号的一致 来进行序列化,主要是为了防止序列化出错 实现Serializable接口的目的是为类可持久化,比如在网络传输或本地存储,为系统的分布和异构部署提供先决条件。若没有序列化,现在我们所熟悉的远程调用,对象数据库都不可能存在 具体序列化的过程是这样的: 序列化操作时会把系统当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会自动检测文件中的serialVersionUID,判断它是否与当前类中的serialVersionUID一致。如果一致说明序列化文件的版本与当前类的版本是一样的,可以反序列化成功,否则就失败; serialVersionUID有两种显示的生成方式: 一是默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据包名,类名,继承关系,非私有的方法和属性,以及参数,返回值等诸多因子计算得出的,极度复杂生成的一个64位的哈希字段。基本上计算出来的这个值是唯一的。比如:private static final long serialVersionUID = xxxxL;
把一个对象写入数据源或者从一个数据源读出来,使用可序列化,需要实现Serializable接口
read()返回的是所读取的字节的int型(范围0-255) read(byte [ ] data)将读取的字节储存在这个数组, 返回的就是传入数组参数个数
Read 字节读取字节 字符读取字符
write将指定字节传入数据源 Byte b[ ]是byte数组,b[off]是传入的第一个字符,我的理解就是数组的下标,b[off+len-1]是传入的最后的一个字符 ,len是数组的实际长度
流一旦打开就必须关闭,要使用close方法关闭,一般放在finally语句块中(finally 语句一定会执行)执行。
多个流互相调用只关闭最外层的流即可。
使用File对象获取文件路径; 通过字符流Reader加入文件; 使用字符缓存流BufferedReader处理Reader; 再定义一个字符串,循环遍历出文件。
代码如下:
public static void main(String[] args) { //1.获取文件路径 File file = new File("D:\\28.txt"); try { //2.Reader加入文件 FileReader reader = new FileReader(file); //3.使用BufferedReader来处理Reader BufferedReader buf = new BufferedReader(reader); //4.定义一个字符串,循环遍历出文件 String data=null; while ((data=buf.readLine())!=null){ System.out.println(data); } buf.close(); } catch (Exception e) { e.printStackTrace(); } }通过递归的方法来获取该目录下的所有的文件
public static void showFile(String pathName){ File f1=new File(pathName); //判断文件夹是否存在 boolean flag1=f1.isDirectory(); //选择某个文件下面的所有文件 if(flag1){//如果是文件夹 File[] files=f1.listFiles(); for (int i=0;files!=null && i<files.length;i++){ boolean flag2=files[i].isDirectory(); if (flag2){//是文件夹 showFile(files[i].getPath()); }else{ String path =f1.getPath(); System.out.println("获取普通文件路径为:"+path); } } }else {//如果不是一个文件夹 String filepath =f1.getPath(); System.out.println("获取普通文件路径为:"+filepath); } } public static void main(String[] args) { fileDemo1.showFile("D:\\"); } }PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream
BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用BufferedInputStream。
PrintWriter的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush);
Filter Stream是一种IO流主要作用是用来对存在的流增加一些额外的功能,像给目标文件增加源文件中不存在的行数,或者增加拷贝的性能。
在java.io包中主要有4个可用的filterStream。两个字节filterStream,两个字符filterStream。分别是FilterInputStream,FilterOutputStream,FilterReader and FilterWriter。这些类是抽象类,不能被实例化。
有些Filter流的子类:
LineNumberInputStream给目标文件增加行号
DataInputStream有些特殊的方法如readInt(),readDouble()和readLine()等可以读取一个int,double和一个string一次性的
BufferedInputStream增加性能
PushbackInputStream推送要求的字节到系统中
这个类的作用是将多个输入流合并成一个输出流,通过SequenceInputStream类包装后形成新的一个总的输入流。在拷贝多个文件到一个目标文件的时候是非常有用的。可以使用很少的代码实现。
它们两个的功能相同,但是属于不同的分类。字节流和字符流,它们都有println()方法。
在字节流的时候,使用BufferedInputStream和BufferedOutputStream。 在字符流的时候,使用BufferedReader和BufferedWriter
有四种管道流,PipedInputStream,PipedOutputStream,PipedReader和PipedWriter。在多个线程或进程中传递数据的时候管道流非常有用。 PipedOutputStream、PipedWriter 是写入者/生产者/发送者; PipedInputStream、PipedReader 是读取者/消费者/接收者。
它在java.io包中是一个特殊的类,既不是输入流也不是输出流,它两者都可以做到。他是Object的直接子类。通常来说,一个流只有一个功能,要么读,要么写。但是RandomAccessFile既可以读文件,也可以写文件。DataInputStream和DataOutStream有的方法,在RandomAccessFile都存在
Java BIO: 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
Java NIO: 同步非阻塞,服务器实现模式为一个请求一个线程,即当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。
Java AIO(NIO.2): 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
名词解释
同步:指的是用户进程触发IO操作需要等待或者轮询的去查看IO操作执行完成才能执行其他操作.这种方式性能比较差,只有一些对数据安全性要求比较高的场景中才会使用.
异步:异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知(异步的特点就是通知)
阻塞:所谓阻塞方式的意思是指, 当试图对该文件描述符进行读写时, 如果当时没有东西可读,或者暂时不可写, 程序就进入等待 状态, 直到有东西可读或者可写为止
非阻塞:非阻塞状态下, 如果没有东西可读, 或者不可写, 读写函数马上返回, 而不会等待
BIO、NIO、AIO适用场景分析 BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。 Java NIO和IO的主要区别
面向流与面向缓冲. Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。
阻塞与非阻塞IO Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
选择器(Selectors) Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
原文出处:https://blog.csdn.net/_Terence/article/details/89513420