java-io

概览

  • 基础概念
  • File
  • io阻塞流
    • 流相关的概念
    • 随机读写
    • 网络编程
    • PrintStream和PrintWriter的区别
    • 字节流读取文本可能存在的问题
  • NIO多路复用、同步非阻塞的io
    • channel
    • Selector
    • Buffer
  • NIO2
    • Path,Paths,Files
    • AsynchronousChannel
    • NIO与AIO区别
  • 同步 异步 阻塞 非阻塞

基础概念

  • bit一个二进制位
  • byte由8个bit组成你
  • char java中是2个byte,16位
  • java采用的unicode,包含了ascii编码

File

  • File类描述的是一个文件或文件夹。可以获取文件名、创建修改时间、大小、可读可写属性等,同时也可以操作文件及目录
  • 判断:exists() isDirectory() isFile()
  • 创建:createNewFile() mkdir() mkdirs()这会创建路径中所有不存在的目录
  • 删除:delete() deleteOnExit()
  • 获取:getAbsolutePath() list()返回所有文件名 listFiles()返回所有File对象
  • File.separatorChar 区分操作系统的分隔符,windows为:,linux为/

io阻塞流

流相关的概念

  • BufferedReader的作用:是一个处理流,可以将读取到的数据放在内存中
  • 按照流的角色划分
    • 节点流:从特定的io设备读取流 eg:InputStream。创建的时候要传入数据源
    • 处理流:对已经存在的流进行封装处理 eg:InputStreamReader。创建的时候要传入流
  • BufferedInputStream的作用:可以减少对硬盘的读取提高处理速度
  • Printwriter:如果写的数据种类较多,可以考虑使用Printwriter,提供了很多printWrite的重载方法
  • 把我们控制台的输出改成输出到一个文件里面:流的重定向,System.out.setOut(PrintStream)
  • 输出字节流转换成输出字符流:New OutputStreamWriter(new FileOutputStream(File file));
  • PrintWriter和DataOuputSream的区别:https://www.cnblogs.com/skywang12345/p/io_16.html
    • 编码不同:PrintWriter可以用户指定编码,DataOuputSream是utf8
    • 构造函数:DataOutputStream只支持OutputStream,PrintWriter支持很多eg file
    • 自动刷新:PrintWriter可以指定是否自动刷新
    • 目的:DataOutputStream是为了和DataInputStream配合读写java类型的数据,PrintWriter为其他流提供打印的方式
    • 异常:PrintStream 永远不会抛出 IOException
  • 对象序列化:将对象以二进制的形式保存在硬盘上,对象需要实现serializable,使用ObjectInputStream、ObjectOutputStream
  • 如果在对象序列化的时候不想给一个字段的数据保存在硬盘上面:transient
  • serialVersionUID字段,它叫做什么,一般有什么用:确保序列化反序列化版本一致
  • InputStream:
    • read()返回byte
    • read(byte[])返回byte数量,同时将数据放入byte[]
  • OutputStream:
    • write(byte b[], int off, int len)
  • 流一旦打开就必须关闭,使用close方法
  • 放入finally语句块中(finally 语句一定会执行)
  • 调用的处理流就关闭处理流
  • 多个流互相调用只关闭最外层的流

按照传输的单元划分流

  • 字符流,分为输入和输出
    • Reader
    • Writer
  • 字节流,分为输入和输出
    • InputStream
    • OutputStream

随机读写

  • RandomAccessFile:可以按字节随机读取,构造函数式传入文件名称和读写的权限
  • 提供了大量的readxxx writexxx方法,同时可以通过seek()设置读取或者写入点,getFilePointer()获取当前的位置
  • 这个是非流操作

网络编程

  • tcp:链接顺序
    • 创建一个服务器socket
    • 客户端发起socket请求
    • 服务端启动一个线程处理请求
    • 获取io
    • 对io进行读写完成交互
    • 关闭io
    • 关闭socket
  • udp:主要用到的类是DatagramSocket、DatagramPacket

参考:https://blog.youkuaiyun.com/baidu_37107022/article/details/76890019

PrintStream和PrintWriter的区别

注意事项

  • 字节流读取一个文本文件的时候要特别小心,很有可能只读取了字符的一半

NIO

  • NIO采用内存映射文件的方式来处理输入输出,将文件的一段映射到内存中
  • Channel可以和InputStream、OutputStream类比,不过前者面向缓存区,后者面向流
    • 可以将部分数据映射成Buffer
    • 创建Channel:InputStream.getChannel()
    • read()
    • write()
    • map():将部分或者全部数据映射成Buffer,会直接返回一个Buffer
    • RamdomAccessFile返回的Chanel可以是既能读又能写的,一般是使用这个RandomAccessFile
  • Buffer实际就是一个数组,其他程序不能直接和Channel交互,无论读写Channel都要通过Buffer
    • XxxBuffer.allocate(capacity) 设置buffer容量
    • position:下一个可以读取或者写入的位置
    • limit:limit后的数字不能读取写入指针的位置,从而灵活读取:position()
    • 可以灵活的设置Buffer中
    • 切换读写状态
      • slip():输入完数据后需要输出数据时调用。切换模式改变limit position的值
      • clear():为再次装数据做好准备,但是数据并没有清空
    • hasRemaining():判断是否还有数据可读 呆写入
  • Selector:
    • 单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便
    • Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作
    • SelectionKey:包含interest集合、ready集合(检查哪些操作就绪了)、Channel、Selector、附加的对象(可选)
    • selector.wakeup()将堵塞在select()上的线程唤醒

      Selector selector = Selector.open();//创建selector
      channel.configureBlocking(false);
      SelectionKey key = channel.register(selector, SelectionKey.OP_READ);//注册channel到selector上
      while(true) {
      int readyChannels = selector.select();//通过select() selectNow()可以选择就绪的方法,区别主要在是否阻塞,返回有多少通道就绪
      if(readyChannels == 0) continue;
      Set selectedKeys = selector.selectedKeys();//将就绪的通道取回来
      Iterator keyIterator = selectedKeys.iterator();
      while(keyIterator.hasNext()) {
      SelectionKey key = keyIterator.next();
      if(key.isAcceptable()) {
      // a connection was accepted by a ServerSocketChannel.
      } else if (key.isConnectable()) {
      // a connection was established with a remote server.
      } else if (key.isReadable()) {
      // a channel is ready for reading
      } else if (key.isWritable()) {
      // a channel is ready for writing
      }
      keyIterator.remove();
      }
      }

Selector

  • 多路复用的实现
  • 在读取用户请求数据后(即 selectionKey.isReadable() 为 true),会去解析请求头,然后将请求头信息通过 attach 方法放入 selectionKey 中。待通道可写后,再从 selectionKey 中取出请求头,并根据请求头回复客户端不同的消息。
  • 也就是说,通道注册时,并不会立即调用 epoll_ctl,而是先将事件集合 events 存放在 eventsLow
  • 选择过程:
    • 检查已取消键集合 cancelledKeys 是否为空,不为空则将 cancelledKeys 的键从 keys 和 selectedKeys 中移除,将键和通道注销。
    • 调用操作系统的 epoll_ctl 函数将通道感兴趣的事件注册到 epoll 实例中
    • 调用操作系统的 epoll_wait 函数监听事件
    • 再次执行步骤1
    • 更新 selectedKeys 集合,并返回就绪通道数量
  • 注册通道实际上只是先将事件收集起来,等调用 select 方法时,在一起通过 epoll_ctl 函数将事件注册到 epoll 实例中。
    https://yq.aliyun.com/articles/604966?spm=a2c4e.11163080.searchblog.39.17252ec1Cv5LMB

linux

nio2

Path,Paths,Files

  • 对nio的功能进行了封装,简化编程
  • Path接口表示的是一个与平台无关的路径(文件和目录都用Path表示)
  • Paths创建Path
  • Files,之前的File并不能操作文件,这里通过整合就io,简化了流操作。Files可以操作文件,读写文件,判断文件。
    https://www.cnblogs.com/fysola/p/6143939.html

AsynchronousChannel

  • 读完了再通知我
  • 使用回调函数,进行业务处理
  • 实现真正的异步编程
  • 可以通过返回Future的方式来获取数据,非阻塞异步public abstract Future<Integer> read(ByteBuffer dst, long position);
  • 也可以通过回调的方式来获取数据public abstract <A> void read(ByteBuffer dst,
    long position,
    A attachment,
    CompletionHandler<Integer,? super A> handler);

    https://blog.youkuaiyun.com/sinat_32366329/article/details/80564338

NIO与AIO区别

  • NIO是同步非阻塞的,AIO是异步非阻塞的
  • 由于NIO的读写过程依然在应用线程里完成,所以对于那些读写过程时间长的,NIO就不太适合。而AIO的读写过程完成后才被通知,所以AIO能够胜任那些重量级,读写过程长的任务。

charset

  • Charset c=Charset.forName("字符集名称")
  • Charset.newDecoder()获得解码器
  • Charset.newEncoder()获得编码器
  • 可以用编码器和解码器做CharBuffer和ByteBuffer转换

文件锁

  • 阻止并发修改同一个文件
  • Channel.lock()(如果不成功则阻塞)或者Channel.tryLock()(如果不成功返回null),给文件加锁同时返回FileLock
  • Channel.lock(position,size,isShare)
    • 共享锁:允许多个进程读,但是阻止排他锁获取
    • 排他锁:锁定对文件的读写
  • FileLock.release()释放锁

socket channel

  • 创建链接
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com",80));
  • 读取数据
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);

后面有个实例:https://blog.youkuaiyun.com/huangwenyi1010/article/details/75577091?ref=myread

NIO与AIO区别

  • NIO是同步非阻塞的,AIO是异步非阻塞的
  • 由于NIO的读写过程依然在应用线程里完成,所以对于那些读写过程时间长的,NIO就不太适合。而AIO的读写过程完成后才被通知,所以AIO能够胜任那些重量级,读写过程长的任务。

同步 异步 阻塞 非阻塞

消息通信的机制

  • 同步:发出请求在没有得到结果前,不返回
  • 异步:调用发出后直接返回,没有返回结果。被调用者通过通知、回调函数通知调用者。操作系统内核读写

等待调用结果时的状态,请求能否立刻应答

  • 阻塞:等待结果返回期间,线程挂起
  • 非阻塞(非阻塞忙轮询):等待结果返回期间,不阻塞当前的线程。但是需要应用不断查询结果

同步和异步针对应用程序来,关注的是程序中间的协作关系;阻塞与非阻塞更关注的是单个进程的执行状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值