诗意码者

专注技术和有点不正经的事


  • 首页

  • 关于

  • 标签

  • 归档

  • 分类

  • 日程表

  • paper

  • 搜索

Java之NIO

发表于 2020-01-19 | 分类于 java |
字数统计: | 阅读时长 ≈
NIO和IO的区别
  • IO是面向的流的编程,是阻塞的

  • NIO是面向缓存区的编程,是非阻塞的,通道(channel)负责连接IO的两端,缓冲器(buffer)负责存储数据

缓冲区

缓存区的实质就是数组,不同的类型的数组,存储不同类型的数据(boolean 类型除外)

ByteBuffer CharBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer

通过allocate(缓冲区大小)分配缓冲区

存取数据

put() 将数据存入缓冲区

get() 获取缓冲区的数据

缓冲区中的四个核心概念

capacity:容量,表示缓冲区中的最大的存储数据的容量。一旦声明不能改变

limit:限制,当前缓冲区实际的数据量(limit后得数据不能被读写)

position:位置,表当前缓冲正在操作数据的位置

mark:标记,记录当前position的位置,可以通过reset() 恢复mark记录的position

关系:0 <= mark<= position <= limit <= capacity

直接缓存区和非直接缓存区的区别
  • 非直接缓存区:通过allocate() 方法分配缓冲区,将缓存区建立在JVM的内存中
  • 直接缓冲区:通过allocateDirect() 方法分配直接缓冲区 将缓存区直接开辟在物理内存中
缓冲区的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 获取非直接缓存区
ByteBuffer buf = ByteBuffer.allocate(1024);
// 获取直接缓存区
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
//在缓冲区放入数据
String str = "abcdefg";
buf.put(str.getBytes());
//切换读取数据模式 flip快速切换
buf.flip();
//存入数据的byte数组
byte[] dst = new byte[buf.limit()];
//从缓冲区获取数据
buf.get(dst);
//重新可以读取刚才的数据 重置position=0 rewind倒带
buf.rewind();
//清空缓冲区,但是缓冲区的数据依然存在,但是出于“被遗忘”的状态
buf.clear();
//判断缓冲区是否还有剩余的数据
if(buf.hasRemaining()){
//获取缓冲区还可操作的数据量
buf.remaining();
}
通道

通道(channel):用于源节点和目标节点的链接,Java NIO 负责缓冲区中数据的传输。Channel本身不存储数据,需要配合缓冲区进行传输数据

通道在java.nio.channels.Channel接口

FileChannel (本地文件)

SocketChannel(网络TCP)

ServerSocketChannel(网络TCP)

DatagramChannel(UDP数据报)

获取通道
  1. 通过getChannel方法获取,以下类可以获取

    本地IO: FileInputStream/FileOutputStream/RandomAccessFile

    网络IO: Socket /ServerSocket/DatagramSocket

  2. JDK1.7 在NIO.2 针对各通道提供的静态方法open()

  3. JDK1.7 在NIO.2 的Files工具类中的newByteChannel()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
FileInputStream fis = null;
FileOutputStream fos = null;
FileChannel inChannel = null;
FileChannel outChannel = null;
try
{
//FileInputStream FileOutputStream 获取通道
fis = new FileInputStream(new File("1.jpg"));
fos = new FileOutputStream((new File("2.jpg")));
//获取FileChannel
inChannel = fis.getChannel();
outChannel = fos.getChannel();
//准备缓冲区(非直接缓冲区)
ByteBuffer buf = ByteBuffer.allocate(1024);
//通道读取数据到缓冲区(写入缓冲区)
while(inChannel.read(buf) != -1)
{
buf.flip();//转换到读的模式
outChannel.write(buf);//将缓存的数据写入通道
buf.clear();//清空缓冲区为下一次读入准备
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if(outChannel!=null){
try
{
outChannel.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}

if(inChannel!=null){
try
{
inChannel.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}

if(fos!=null){
try
{
fos.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
if(fis!=null){
try
{
fis.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
//用Open方式获取通道
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
//通过直接内存映射方式获取缓冲区
MappedByteBuffer inbuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
MappedByteBuffer outbuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
//直接对缓冲区进行读写
byte[] bytes = new byte[inbuf.limit()];
inbuf.get(bytes);
outbuf.put(bytes);
inChannel.close();
outChannel.close();
通道之间的数据传输

transferFrom() transferTo()

1
2
3
4
5
6
7
8
9
//用Open方式获取通道
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
//通道直接的数据传输
inChannel.transferTo(0,inChannel.size(),outChannel);
//等价于
outChannel.transferFrom(inChannel,0,inChannel.size());
inChannel.close();
outChannel.close();
分散(Scatter)与聚集(Gather)
  • 分散读取(Scattering Reads) 将通道中的数据分散到多个缓冲区

  • 聚集写入(Gathering Writes) 将多个缓冲区中的数据聚集到通道中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    RandomAccessFile raf = new RandomAccessFile("1.txt","rw");
    FileChannel channel1 = raf.getChannel();

    ByteBuffer buf1 = ByteBuffer.allocate(500);
    ByteBuffer buf2 = ByteBuffer.allocate(500);
    ByteBuffer[] byteBuffers = {buf1,buf2};
    //分散读取
    channel1.read(byteBuffers);
    for(ByteBuffer buf : byteBuffers)
    {
    buf.flip();
    }
    /** System.out.println(new String(byteBuffers[0].array(),0,byteBuffers[0].limit()));
    System.out.println("--------------------------------------------------------");
    System.out.println(new String(byteBuffers[1].array(),0,byteBuffers[0].limit()));*/

    //聚集写入
    RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
    FileChannel channel2 = raf2.getChannel();
    channel2.write(byteBuffers);
编码与解码
1
2
3
4
5
6
7
8
9
10
11
12
Charset cset = Charset.forName("GBK");
//字符到字节数组 编码
CharsetEncoder encoder = cset.newEncoder();
//字节数组到字符 解码
CharsetDecoder decoder = cset.newDecoder();
CharBuffer cbuf = CharBuffer.allocate(1024);
cbuf.put("张家口检索");
cbuf.flip();
ByteBuffer buf = encoder.encode(cbuf);
//buf.flip();
CharBuffer cbuf1 = decoder.decode(buf);
System.out.println(cbuf1.toString());

我的第二篇

发表于 2020-01-17 |
字数统计: | 阅读时长 ≈

MarkDown小计

发表于 2020-01-17 | 分类于 小知识 |
字数统计: | 阅读时长 ≈

1.标题

1
2
3
4
5
6
#一级标题
##二级标题
###三级标题
####四级标题
#####五级标题
######六级标题

一级标题

二级标题

三级标题

四级标题

五级标题
六级标题

2.代码块

1
​

代码块
​```

1
2
3
4
5
6
7
8
9

```java
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}

3.字体

1
2
3
4
**这是加粗的文字**
*这是倾斜的文字*
***这是斜体加粗的文字***
~~这是加删除线的文字~~

这是加粗

这是斜体

这是加粗斜体

这是加删除线

4.引用

1
2
3
>123
>>123
>>>123

123

123

123

5.分割线

1
2
3
4
//分割线
---
//分割线
***


6.图片插入

1
2
//在线插入和本地插入
![图片标识](图片路径(url/本地相对地址))
我的图片

7.超链接

1
2
//超链接
[我的GitHub(标识)](超链接地址)

我的GitHub

8.列表

1
2
3
4
5
6
7
8
//无序列表
- 列表1
- 列表2
- 列表3
//有序列表
1.列表1
2.列表2
3.列表3
  • 列表1
  • 列表2
  • 列表3
  1. 列表1

  2. 列表2

  3. 列表3

9.表格

1
2
3
4
5
6
7
8
9
10
11
表头|表头|表头
---|:--:|---:
内容|内容|内容
内容|内容|内容

第二行分割表头和内容。
- 有一个就行,为了对齐,多加了几个
文字默认居左
-两边加:表示文字居中
-右边加:表示文字居右
注:原生的语法两边都要用 | 包起来。此处省略
姓名 年级排名 班级排名
张三 1 1
李四 2 2
王五 3 3

Hello World

发表于 2020-01-17 |
字数统计: | 阅读时长 ≈

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

<i class="fa fa-angle-left"></i>123
苏小南

苏小南

慢慢写

24 日志
3 分类
5 标签
GitHub E-Mail QQ weibo
Links
  • 度娘
© 2015 — 2021 苏小南 | Site words total count:
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
本站访问人数 人次 本站总访问量 次