特殊
RandomAccessFile
RandomAccessFile
不属于
IO
流,支持对文件的读取和写入随机访问
public class RandomAccessFile implements DataOutput, DataInput, Closeable
1.DataInput
接口中定义了基本数据类型的读操作
,
例如
readInt/readDouble
等
2.DataOutput
接口定义了基本数据类型的写操作
,
例如
writeInt/writeDouble
等
RandomAccessFile
是
Java
输入
/
输出流体系中功能最丰富的文件内容访问类,既可以读取文件内容,也可以向文件输出数据。
RandomAccessFile
构造器
RandomAccessFile
类在创建对象时,除了指定文件本身,还需要指定一个
mode
参数指定
RandomAccessFile
的访问模式,该参数有如下四个值:
1.r
以只读方式打开指定文件。如果试图对该
RandomAccessFile
指定的文件执行写入方法则会抛出
IOException
2.rw
以读取、写入方式打开指定文件。如果该文件不存在,则尝试创建文件
3.rws
以读取、写入方式打开指定文件。相对于
rw
模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备,默认情形下(rw
模式下
),
是使用
buffer
的
,
只有
cache
满的或者使用
RandomAccessFile.close()
关闭流的时候儿才真正的写到文件
4.rwd与
rws
类似,只是仅对文件的内容同步更新到磁盘,而不修改文件的元数据
RandomAccessFile
写方法

RandomAccessFile
读方法

读取文件时如果到文件结尾是抛出异常
EOFException
,所以这里采用的是异常用于判断文件结束
典型应用:多线程下载和断点续传
记录指针的特殊方法
与普通的输入
/
输出流不同的是
: RandomAccessFile
支持跳到文件任意位置读写数据,
RandomAccessFile
对象包含一个记录指针,用以标识当前读写处的位置,当程序创建一个新的
RandomAccessFile
对象时,该对象的文件记录指针对于文件头(也就是
0
处),当读写
n
个字节后,文件记录指针将会向后移动n
个字节。除此之外,
RandomAccessFile
可以自由移动该记录指针
RandomAccessFile包含两个方法来操作文件记录指针:文件指针是按照字节数进行统计,取值范围为[0,file.length()]
long getFilePointer()
:返回文件记录指针的当前位置
void seek(long pos)
:将文件记录指针定位到
pos
位置
skipByte(int step);
相对当前位置跳过
step
个字节
如果文件中间的内容需要进行修改,注意新内容中的字串和原始文件内容的长度应该一致,否则可能会导致修改数据后面的内容无法正常读取
常见方法
void close()
关闭操作
int read(byte[] b)
将内容读取到一个
byte
数组之中
byte readByte()
读取一个字节
int readInt()
从文件中读取整型数据
… readDouble()
等
8
种简单类型
String readLine()
读取一行数据
void writeBytes(String s)
将一个字符串写入到文件之中,按字节的方式处理。
writeChars
void writeInt(int v)
将一个
int
型数据写入文件,长度为
4
位。
…writeDouble
等
8
种类型
void writeBytes(String s)
将一个字符串写入到文件之中,按字节的方式处理。
writeChars
void writeInt(int v)
将一个
int
型数据写入文件,长度为
4
位。
…writeDouble
等
8
种类型
NIO
从
JDK1.4
开始
Java
引入了一系列改进的输入
/
输出处理的新功能,统称为
NIO
,即新
IO
,新增了许多用于处理输入输出的类,新IO
采用内存映射文件的方式处理输入输出,新
IO
将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件,这种方式进行输入输出比传统的输入输出快的多
NIO
基础
Channel
通道和
Buffer
缓冲是
NIO
中的两个核心对象
1.Chanel
是对传统输入输出系统的模拟,通过
map
方法可以将一块数据映射到内存中
2.Buffer
本质是一个数组,发送到
Channel
中的所有对象都必须先放到
Buffer
中,而从
Channel
中读
取的数据必须先放到
Buffer
中
NIO
和多路复用的区别
IO
模型
同步阻塞
IO
(
Blocking IO
):即传统的
IO
模型
同步非阻塞
IO
(
Non-blocking IO
):默认创建的
socket
都是阻塞的,非阻塞
IO
要求
socket
被设置
为
NONBLOCK
。注意这里所说的
NIO
并非
Java
的
NIO
(
New IO
)库
多路复用
IO
(
IO Multiplexing
):即经典的
Reactor
设计模式,有时也称为异步阻塞
IO
,
Java
中的
Selector
和
Linux
中的
epoll
都是这种模型
异步
IO
(
Asynchronous IO
):即经典的
Proactor
设计模式,也称为异步非阻塞
IO
。
java NIO就是采用多路复用IO模式
在多路复用
IO
模型中,会有一个线程(
Java
中的
Selector
)不断去轮询多个
socket
的状态,只有当
socket
真正有读写事件时,才真正调用实际的
IO
读写操作。因为在多路复用
IO
模型中,只需要使用一个线程就可以管理多个socket
,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket
读写事件进行时,才会使用
IO
资源,所以它大大减少了资源占用。
Buffer
的使用
Buffer
是一个抽象类,主要作用是用于装入数据,然后输出数据
1.最常见的子类
ByteBuffer
可以在底层字节数组上进行
get/set
操作
2.其它基本数据类型都有对应的
Buffer
类:
CharBuffer
、
ShortBuffer
、
IntBuffer
、
LongBuffer
、
FloatBuffer
、
DoubleBuffer
静态方法
static XxxBuffer allocate(int capacity)
创建一个容量为
capacity
的
XxxBuffer
对象
Buffer
中有
3
个重要概念:容量
capacity
、界限
limit
和位置
position
1.容量
capacity
表示该
Buffer
的最大数据容量,创建后则不能改变
2.界限
limit
,位于
limit
后的数据既不可被读,也不可被写
3.位置
position
用于指明下一个可以被读出的或者写入缓冲区的位置索引
标记
mark
位置
Buffer
类的常用方法

Channel
类的常用方法
Channel可以直接将文件的部分或者全部直接映射成Buffer
注意:不能直接访问Channel中的数据,包括读取、写入都不行。Channel只能与Buffer进行交互
所有
Channel
不应该通过构造器来直接创建,而是通过传统的节点
InputStream
、
OutputStream
的
getChannel
方法来返回对应的
Channel
常用的是
FileInputStream
、
FileOutputStream
的
getChannel()
返回的
FileChannel
Channel
中最常用的三个方法是
map()
、
read()
和
write()
异常:
java.nio.charset.MalformedInputException
一般是编码转换时由于编码字符集错误导致的,可以修改Charset
中编码字符集名称解决。例如
GBK
、
UTF-8
等
map()
方法将
Channel
对应的部分或全部数据映射成
ByteBuffer
selector
是
Java NIO
核心组件中的一个,用于检查一个或多个
NIO Channel
通道的状态是否处于可读、可写。如此可以实现单线程管理多个channels
也就是可以管理多个网络链接。
使用
Selector
的好处在于:使用更少的线程来就可以来处理通道了,相比使用多个线程,避免了线程上下文切换带来的开销
FileChannel
不能切换为非阻塞模式,更准确的来说是因为
FileChannel
没有继承SelectableChannel
多用于网络应用编程中
基本用法
1. Selector
的创建。通过调用
Selector.open()
方法创建一个
Selector
对象
Selectorselector=Selector.open();
2.
注册
Channel
到
Selector
channel.configureBlocking(false);
SelectionKeykey=channel.register(selector,Selectionkey.OP_READ);
Channel
必须是非阻塞的。
Chatset
字符集
所有文件在底层都是二进制文件,字符文件是系统将底层的二进制序列转换为字符,这里会涉及编码Encoder和解码
Decoder
将明文的字符序列转换为计算机理解的二进制序列称为编码
将二进制序列转换为明文字符串称为解码
Charset
类
availableCharsets()
:
SortedMap<String,Charset>
获取当前
JDK
所支持的所有字符集
字符串别名
GBK
简体中文
ISO-8859-1
拉丁文
UTF-8
是
8
位
UCS
转换格式
Charsetc
=
Charset
.
forName
(
"GBK"
);
Java7
新增
StandardCharsets
类,其中包含了
ISO_8859_1
、
UTF_8
、
UTF-16
等类变量,这些类变量代表了最常见的字符集对应的Charset
对象
newDecoder():CharsetDecoder
获取该编码字符集对应的解码器
decode(ByteBuffer):CharBuffer
方法可以将字节序列
ByteBuffer
转换为
CharBuffer
字符序列
newEncoder():CharsetEncoder
获取该编码字符集对应的编码器
encode(CharBuffer):ByteBuffer
方法可以将字符序列
CharBuffer
转换为
ByteBuffer
字节序列