从流动方向来看,input代表从读取外部文件内容到java程序里,ouput代表从内存写入数据到文件里
https://blog.csdn.net/qq_34626097/article/details/84112199
程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件 IO 资源。
- 节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader.
- 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

https://www.cnblogs.com/wxgblogs/p/5647415.html
一般output,input都是相对于当前运行的内存。
//解读以下PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("pw2.txt"), "UTF-8")));FileOutputStream:输出节点流OutputStream(OutputStream out, String charsetName): 使用指定的字符集将字符编码为字节out:字节输出流,可以用来写转换之后的字节到文件中charsetName:指定的编码表名称,不区分大小写,可以是utf-8/UTF-8,gbk/GBK,...不指定默认使用UTF-8
BufferedReader和BufferedWriter是带有默认缓冲区的字符输入输出流,其效率相较于没有缓冲区要高:
1.java.io.BufferedReader和java.io.BufferedWriter类各拥有8192字符的缓冲区。当BufferedReader在读取文本文件时,会先尽量从文件中读入字符数据并置入缓冲区,而之后若使用read()方法,会先从缓冲区中进行读取。如果缓冲区数据不足,才会再从文件中读取,使用BufferedWriter时,写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出。2. 从标准输入流System.in中直接读取使用者输入时,使用者每输入一个字符,System.in就读取一个字符。为了能一次读取一行使用者的输入,使用了BufferedReader来对使用者输入的字符进行缓冲。readLine()方法会在读取到使用者的换行字符时,再一次将整行字符串传入。3. System.in是一个位流,为了转换为字符流,可使用InputStreamReader为其进行字符转换,然后再使用BufferedReader为其增加缓冲功能。
—————————————————————————————————
综合案例 https://segmentfault.com/a/1190000012316621
printWrite 不开自动刷, 会等缓冲区数据到一定大小,才会从缓冲区写入
public class MyServer {private static ExecutorService executorService = Executors.newCachedThreadPool(); //创建一个线程池//一旦有新的客户端请求,创建这个线程进行处理private static class HandleMsg implements Runnable{Socket client; //创建一个客户端public HandleMsg(Socket client){ //构造传参绑定this.client = client;}@Overridepublic void run() {BufferedReader bufferedReader = null; //创建字符缓存输入流PrintWriter printWriter = null; //创建字符写入流try {//1,从client中获得输入流,用于读取client输入内容;//2,基于以上节点流转换为inputstreamreader处理(转换流,实现字节-字符转换//3,根据以上处理流创建缓冲流,优化性能//获取客户端的输入流bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));//获取客户端的输出流,true是随时刷新,等待写入;printWriter = new PrintWriter(client.getOutputStream(),true);String inputLine = null;long a = System.currentTimeMillis();while ((inputLine = bufferedReader.readLine())!=null){printWriter.println(inputLine);}long b = System.currentTimeMillis();System.out.println("此线程花费了:"+(b-a)+"秒!");} catch (IOException e) {e.printStackTrace();}finally {try {bufferedReader.close();printWriter.close();client.close();} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) throws IOException { //服务端的主线程是用来循环监听客户端请求ServerSocket server = new ServerSocket(8686); //创建一个服务端且端口为8686Socket client = null;while (true){ //循环监听client = server.accept(); //服务端监听到一个客户端请求System.out.println(client.getRemoteSocketAddress()+"地址的客户端连接成功!");executorService.submit(new HandleMsg(client)); //将该客户端请求通过线程池放入HandlMsg线程中进行处理}}}public class MyClient {public static void main(String[] args) throws IOException {Socket client = null;PrintWriter printWriter = null;BufferedReader bufferedReader = null;try {client = new Socket();client.connect(new InetSocketAddress("localhost",8686));printWriter = new PrintWriter(client.getOutputStream(),true);printWriter.println("hello");printWriter.flush();bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream())); //读取服务器返回的信息并进行输出System.out.println("来自服务器的信息是:"+bufferedReader.readLine());} catch (IOException e) {e.printStackTrace();}finally {printWriter.close();bufferedReader.close();client.close();}}}
零拷贝收集:
mmap,sendfile,DMA gather 知乎 https://zhuanlan.zhihu.com/p/357820303
