文章目录提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
- 同步与异步,阻塞与非阻塞的区别
- BIO、NIO、AIO的区别和应用场景
- BIO
- NIO
- AIO
- BIO和NIO、AIO的区别
- IO与NIO区别
- Java中流类的超类主要有那些?
- IO 流
- IO 流概述:
- IO 流的分类:
- IO 流的使用场景
- 字节流
- 输出流
- 输入流
- 复制
- 字节缓冲流
- 编码
- 字符流
- 字符输入流
- 字符输出流
- 字符缓冲流
- 什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别
- 什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作
- 对象序列化流: ObjectOutputStream
- 对象反序列化流:ObjectInputStream
- 打印流
- 字节打印流
- 字符打印流
- 标准流
- 标准输出流
- 标准输入流
同步与异步,阻塞与非阻塞的区别
- 同步,一个任务的完成之前不能做其他操作,必须等待(等于在打电话)
- 异步,一个任务的完成之前,可以进行其他操作(等于在聊QQ)
- 阻塞,是相对于CPU来说的, 挂起当前线程,不能做其他操作只能等待
- 非阻塞,,无须挂起当前线程,可以去执行其他操作
- Blocking I/O,同步阻塞I/O模型,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- 应用场景:适用于连接数目比较小且固定的架构,这种方式对服务端资源要求比较高,并发局限于应用中,在JDK 1.4以前是唯一的I/O实现,但程序直观简单易理解。
- 通俗理解为数据的读取写入必修阻塞在一个线程内,直到其完成。
- 例子:A拿着一支鱼竿在河边钓鱼,并且一直在鱼竿前等,在等的时候不做其他的事情,十分专心。只有鱼上钩的时,才结束掉等的动作,把鱼钓上来。
- New I/O,同步非阻塞I/O模型,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。应用场景:NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK 1.4开始支持。
- 是传统I/O的升级版,客户端和服务端通过Channel(通道)通讯,实现了多路复用。
- NIO采用的是一种多路复用的机制,利用单线程轮询事件,高效定位就绪的Channel来决定做什么,只是Select阶段是阻塞式的,能有效避免大量连接数时,频繁线程的切换带来的性能或各种问题。
- 例子:B也在河边钓鱼,但是B不想将自己的所有时间都花费在钓鱼上,在等鱼上钩这个时间段中,B也在做其他的事情(一会看看书,一会读读报纸,一会又去看其他人的钓鱼等),但B在做这些事情的时候,每隔一个固定的时间检查鱼是否上钩。一旦检查到有鱼上钩,就停下手中的事情,把鱼钓上来。 B在检查鱼竿是否有鱼,是一个轮询的过程。
- Asynchronous I/O,异步非阻塞I/O模型,服务器实现模式为一个有效请求一个线程,客户端的 I/O 请求都是由 OS 先完成了再通知服务器应用启动线程进行处理。 应用场景:适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK 7 开始支持。
- 例子:C也想钓鱼,但C有事情,于是他雇来了D、E、F,让他们帮他等待鱼上钩,一旦有鱼上钩,就打电话给C,C就会将鱼钓上去。
- BIO是阻塞的,NIO是非阻塞的.
- BIO是面向流的,只能单向读写,NIO是面向缓冲的, 可以双向读写
- 使用BIO做Socket连接时,由于单向读写,当没有数据时,会挂起当前线程,阻塞等待,为防止影响其它连接,,需要为每个连接新建线程处理.,然而系统资源是有限的,,不能过多的新建线程,线程过多带来线程上下文的切换,从来带来更大的性能损耗,因此需要使用NIO进行BIO多路复用,使用一个线程来监听所有Socket连接,使用本线程或者其他线程处理连接
- AIO是非阻塞 以异步方式发起 I/O 操作。当 I/O 操作进行时可以去做其他操作,由操作系统内核空间提醒IO操作已完成
- IO面向流,NIO面向缓冲区;IO的各种流是阻塞I/O模型,NIO是非阻塞I/O模型。
- NIO的选择允许一个单独的线程来监视多个输入通道,可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入或选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
- 超类代表顶端的父类(都是抽象类)
- java.io.InputStream
- java.io.OutputStream
- java.io.Reader
- java.io.Writer
- IO:输入/输出(Input/Output)
- 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
- IO流就是用来处理设备间数据传输问题的。
- 常见的应用:文件复制;文件上传;文件下载
- 按照数据的流向
- 输入流:读数据
- 输出流:写数据
- 按照数据类型来分
- 字节流:以字节为单位,每次次读入或读出是8位数据。可以读任何类型数据。
Java代码接收数据只能为byte数组- 字节输入流
- 字节输出流
- 字符流:以字符为单位,每次次读入或读出是16位数据
- 字符输入流
- 字符输出流
- 字节流:以字节为单位,每次次读入或读出是8位数据。可以读任何类型数据。
- 如果操作的是纯文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件。优先使用字节流
- 如果不确定文件类型,优先使用字节流。字节流是万能的流
package IO流.字节流;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//FileOutputStream(String name):创建文件输出流以指定的名称写入文件
FileOutputStream fos = new FileOutputStream("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流\FileOutputStream.txt");
//FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件
//File file = new File("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流\FileOutputStream2.txt");
//FileOutputStream fos2 = new FileOutputStream(file);
//FileOutputStream fos2 = new FileOutputStream(new File("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流\FileOutputStream3.txt"));
//void write(int b):将指定的字节写入此文件输出流
fos.write(97);//a
//byte[] getBytes():返回字符串对应的字节数组
byte[] bys = "abcde".getBytes();
//fos.write(bys);//abcde
//void write(byte[] b, int off, int len):将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流
// fos.write(bys,0,bys.length);
fos.write(bys,1,3);//abcd
FileOutputStream fos2 = new FileOutputStream("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流\FileOutputStream.txt",true);
//写数据
for (int i = 0; i < 10; i++) {
fos.write("hello".getBytes());
fos.write("rn".getBytes());
}
//最后都要释放资源
//void close():关闭此文件输出流并释放与此流相关联的任何系统资源。
fos.close();
}
}
输入流
package IO流.字节流;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
//FileInputStream(String name)
FileInputStream fis = new FileInputStream("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流\FileOutputStream.txt");
//调用字节输入流对象的读数据方法
//int read():从该输入流读取一个字节的数据
//优化
int by;
while ((by=fis.read())!=-1) {
System.out.print((char)by);
}
//释放资源
fis.close();
}
}
复制
package IO流.字节流;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyDemo {
public static void main(String[] args) throws IOException {
//根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流\mn.jpg");
//根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("D:\IntelliJ IDEA 2021.1.1\workspace\study\src\IO流2\mn.jpg");
//读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
byte[] bys = new byte[1024];
int len;
while ((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
//释放资源
fos.close();
fis.close();
}
}
字节缓冲流
package IO流.字节流;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
//字节缓冲输出流:BufferedOutputStream(OutputStream out)
//字节缓冲输入流:BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myByteStream\bos.txt"));
//一次读取一个字节数据
// int by;
// while ((by=bis.read())!=-1) {
// System.out.print((char)by);
// }
//一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
//释放资源
bis.close();
}
}
编码
package IO流.字符流;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义一个字符串
String s = "中国";
//byte[] getBytes():使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
//byte[] bys = s.getBytes(); //[-28, -72, -83, -27, -101, -67]
//byte[] getBytes(String charsetName):使用指定的字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
// byte[] bys = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67]
byte[] bys = s.getBytes("GBK"); //[-42, -48, -71, -6]
System.out.println(Arrays.toString(bys));
//String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的 String
// String ss = new String(bys);
//String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String
// String ss = new String(bys,"UTF-8");
String ss = new String(bys,"GBK");
System.out.println(ss);
}
}
字符流
字符输入流
package IO流.字符流;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//InputStreamReader(InputStream in):创建一个使用默认字符集的InputStreamReader
// InputStreamReader isr = new InputStreamReader(new FileInputStream("IO流\osw.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("IO流\ConversionStreamDemo.java"));
//int read():一次读一个字符数据
// int ch;
// while ((ch=isr.read())!=-1) {
// System.out.print((char)ch);
// }
//int read(char[] cbuf):一次读一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
//释放资源
isr.close();
}
}
字符输出流
package IO流.字符流;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//OutputStreamWriter(OutputStream out):创建一个使用默认字符编码的OutputStreamWriter
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("IO流\osw.txt"));
//void write(int c):写一个字符
// osw.write(97);
// //void flush():刷新流
// osw.flush();
//void write(char[] cbuf):写入一个字符数组
char[] chs = {'a', 'b', 'c', 'd', 'e'};
// osw.write(chs);
//void write(char[] cbuf, int off, int len):写入字符数组的一部分
// osw.write(chs, 0, chs.length);
// osw.write(chs, 1, 3);
//void write(String str):写一个字符串
// osw.write("abcde");
//void write(String str, int off, int len):写一个字符串的一部分
osw.write("abcde", 0, "abcde".length());
//释放资源
osw.close();
//Exception in thread "main" java.io.IOException: Stream closed
// osw.write(100);
}
}
字符缓冲流
package IO流.字符流;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedStreamDemo02 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("IO流\bw.txt"));
//public String readLine():读一行文字。
String line;
while ((line=br.readLine())!=null) {
System.out.println(line);
}
br.close();
}
}
什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别
- bit(位)最小的二进制单位 ,是计算机的操作部分 取值0或者1
- byte(字节)是计算机操作数据的最小单位由8位bit组成 取值(-128-127)
- char(字符)是用户的可读写的最小单位,在Java里面由16位bit组成 取值(0-65535)
- 一般 utf-8 编码下,一个汉字 字符 占用 3 个 字节;
- 一般 gbk 编码下,一个汉字 字符 占用 2 个 字节;
- 对象序列化,将对象以二进制的形式保存在硬盘上
- 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存 储的属性等信息
- 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
- 对象序列化流: ObjectOutputStream
- 反序列化;将二进制的文件转化为对象读取
- 将字节序列从文件中读取回来,重构对象
- 实现serializable接口,不想让字段放在硬盘上就加transient
package IO流.序列化;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
//ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("IO流\oos.txt"));
//创建对象
Student s = new Student("哈哈",20);
//void writeObject(Object obj):将指定的对象写入ObjectOutputStream
oos.writeObject(s);
//释放资源
oos.close();
}
}
对象反序列化流:ObjectInputStream
package IO流.序列化;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("IO流\oos.txt"));
//Object readObject():从ObjectInputStream读取一个对象
Object obj = ois.readObject();
Student s = (Student) obj;
System.out.println(s.getName() + "," + s.getAge());
ois.close();
}
}
打印流
字节打印流
package IO流.特殊流;
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
//PrintStream(String fileName):使用指定的文件名创建新的打印流
PrintStream ps = new PrintStream("IO流\ps.txt");
//写数据
//字节输出流有的方法
// ps.write(97);
//使用特有方法写数据
ps.print(97);
ps.println(98);
//释放资源
ps.close();
}
}
字符打印流
package IO流.特殊流;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
//PrintWriter(String fileName) :使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新
// PrintWriter pw = new PrintWriter("IO流\pw.txt");
// pw.write("haha");
// pw.write("rn");
// pw.flush();
// pw.write("hehe");
// pw.write("rn");
// pw.flush();
// pw.println("haha");
// pw.flush();
// pw.println("hehe");
// pw.flush();
//PrintWriter(Writer out, boolean autoFlush):创建一个新的PrintWriter
PrintWriter pw = new PrintWriter(new FileWriter("IO流\pw.txt"),true);
// PrintWriter pw = new PrintWriter(new FileWriter("IO流\pw.txt"),false);
pw.println("haha");
pw.println("hehe");
pw.close();
}
}
标准流
标准输出流
package IO流.特殊流;
import java.io.PrintStream;
public class SystemOutDemo {
public static void main(String[] args) {
//public static final PrintStream out:标准输出流
PrintStream ps = System.out;
//能够方便地打印各种数据值
// ps.print("hello");
// ps.print(100);
// ps.println("hello");
// ps.println(100);
//System.out的本质是一个字节输出流
System.out.println("hello");
System.out.println(100);
System.out.println();
// System.out.print();
}
}
标准输入流
package IO流.特殊流;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class SystemInDemo {
public static void main(String[] args) throws IOException {
//public static final InputStream in:标准输入流
// InputStream is = System.in;
// int by;
// while ((by=is.read())!=-1) {
// System.out.print((char)by);
// }
//如何把字节流转换为字符流?用转换流
// InputStreamReader isr = new InputStreamReader(is);
// //使用字符流能不能够实现一次读取一行数据呢?可以
// //但是,一次读取一行数据的方法是字符缓冲输入流的特有方法
// BufferedReader br = new BufferedReader(isr);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入一个字符串:");
String line = br.readLine();
System.out.println("你输入的字符串是:" + line);
System.out.println("请输入一个整数:");
int i = Integer.parseInt(br.readLine());
System.out.println("你输入的整数是:" + i);
//自己实现键盘录入数据太麻烦了,所以Java就提供了一个类供我们使用
Scanner sc = new Scanner(System.in);
}
}



