IO原理及流的分类
文件流 FileInputStream / FileOutputStream / FileReader / FileWriter
缓冲流 BufferedInputStream / BufferedOutputStream / BufferedReader / BufferedWriter
转换流 InputStreamReader / OutputStreamWriter
标准输入/输出流 打印流(了解) PrintStream / PrintWriter
数据流(了解) DataInputStream / DataOutputStream
对象流 ----涉及序列化、反序列化 ObjectInputStream / ObjectOutputStream
随机存取文件流 RandomAccessFile
一、File类
java.io.File的对象用于描述一个目录或文件。
通过File中的方法可以获取该文件相关的属性(文件名,路径,是否文件,是否目录,是否可读,文件大小)。
1.File类的构造方法
构 造 方 法 | 说 明 |
File(String pathname) | 指定文件(或目录)名和路径创建文件对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。 |
public File(String parent,String child) | 以parent为父路径,child为子路径创建File对象。 |
//在当前目录下创建一个与aaa.txt文件名相关联的文件对象
File f1 = new File("aaa.txt");
//指明详细的路径以及文件名,请注意双斜线
File f2 = new File(“D:\\Java\\Hello.java”);//转义字符
File f2 = new File("D:/Java/Hello.java");
2.File类中的常用方法
方 法 原 型 | 说 明 |
boolean exists() | 判断文件是否存在,存在返回true,否则返回false |
boolean isFile() | 判断是否为文件,是文件返回true,否则返回false |
boolean isDirectory() | 判断是否为目录,是目录返回true,否则返回false |
String getName() | 获得文件的名称 |
String getAbsolutePath() | 获得文件的绝对路径 |
long length() | 获得文件的长度(字节数) |
boolean createNewFile() throws IOException | 创建新文件,创建成功返回true,否则返回false,有可能抛出IOException异常,必须捕捉 |
boolean delete() | 删除文件,删除成功返回true,否则返回false |
File[] listFiles() | 返回文件夹内的子文件与子文件夹的数组 |
File类中的delete方法可以用于删除目录或文件
文件可以通过delete方法直接删除
但是delete方法只能够删除空的目录,如果目录不为空个,则删除失败
二、IO
1.Java IO原理
IO流用来处理设备之间的数据传输。
Java程序中,对于数据的输入/输出操作以”流(stream)” 的方式进行。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
输入流:将磁盘或文件中的数据(外部数据)输入到内存(程序)中去,输入流
输出流:将内存(程序)中的数据显示到磁盘,控制台,显示器,投影,称为输出流。
输出和输出是分了方向的。
2.流的分类结构
三、流的分类
按照数据单位划分:字节流(8 bit)和字符流(16 bit)
按照流向划分:输入流和输出流
字节流具有输入和输出的操作(输入流和输出流)
字符流同样也具有输入和输出的操作(输入流和输出流)
(抽象基类) | 字节流 | 字符流 |
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
四、流的类型
(一)字节流
1.FileInputStream类读文件-字节输入流
- FileInputStream类称为文件输入流,继承于InputStream类,是进行文件读操作的最基本类(从硬盘读取到内存)
- 它的作用是将文件中的数据输入到内存中,我们可以利用它来读文件;
- 由于它属于字节流,因此在读取Unicode字符(如中文)的文件时可能会出现问题
构 造 方 法 | 说 明 |
FileInputStream(File file) throws FileNotFoundException | 使用File对象创建文件输入流对象,如果文件打开失败,将抛出异常 |
FileInputStream(String name) throws FileNotFoundException | 使用文件名或路径创建文件输入流对象,如果文件打开失败,将抛出异常 |
方 法 原 型 | 说 明 |
int read() throws IOException | 读取文件中的数据,一次读取一个字节,读取的数据作为返回值返回,如果读到文件末尾则返回-1,有可能抛异常,必须捕捉 |
int read(byte[] b) throws IOException | 读取文件中的数据,将读到的数据存放到byte型数组中,并返回读取的字节的数量,未读到数据返回-1,有可能抛异常,必须捕捉 |
void close() throws IOException | 关闭流对象,有可能抛异常,必须捕捉 注:close会调用内存释放,否则可能导致读写失败 |
public class FileInputStreamDemo1 {
public static void main(String[] args) {
try {
File file = new File("test.txt"); //创建文件对象
//使用文件对象创建文件输入流对象,相当于打开文件
FileInputStream fis = new FileInputStream(file);
for (int i = 0; i < file.length(); i++) {
char ch = (char)(fis.read()); //循环读取字符
System.out.print(ch);
}
System.out.println();
fis.close(); //关闭流
} catch (FileNotFoundException fnfe) {
System.out.println("文件打开失败。");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
public class FileInputStreamDemo2 {
public static void main(String[] args) {
try {
File file = new File("test.txt"); //创建文件对象
FileInputStream fis = new FileInputStream(file);
//根据文件的字节长度创建字节数组
byte[] buf = new byte[(int)(file.length())];
fis.read(buf); //读取文件中的数据存放到字节数组中
String str = new String(buf); //利用字节数组创建字符串
System.out.println(str); //打印字符串
fis.close(); //关闭流
} catch (FileNotFoundException fnfe) {
System.out.println("文件打开失败。");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
2.FileOutputStream类写文件-字节输出流
- FileOutputStream类称为文件输出流,继承于OutputStream类,是进行文件写操作的最基本类;
- 它的作用是将内存中的数据输出到文件中,我们可以利用它来写文件。
构 造 方 法 | 说 明 |
FileOutputStream(File file) throws FileNotFoundException | 使用File对象创建文件输出流对象,如果文件打开失败,将抛出异常 |
FileOutputStream(File file, boolean append) throws FileNotFoundException | 使用File对象创建文件输出流对象,并由参数append指定是否追加文件内容,true为追加,false为不追加,异常情况同上 |
FileOutputStream(String name) throws FileNotFoundException | 直接使用文件名或路径创建文件输出流对象,异常情况同上 |
FileOutputStream(String name, boolean append) throws FileNotFoundException | 直接使用文件名或路径创建文件输出流对象,并由参数append指定是否追加,异常情况同上 |
方 法 原 型 | 说 明 |
void write(int b) throws IOException | 往文件中写数据,一次写一个字节,有可能抛异常,必须捕捉 |
void write(byte[] b) throws IOException | 往文件中写数据,将byte数组中的数据全部写入到文件中,有可能抛异常,必须捕捉 |
void close() throws IOException | 关闭流对象,有可能抛异常,必须捕捉 |
public class FileOutputStreamDemo1{
//在函数内部不进行异常处理,将异常抛出函数外部
public static void main(String[] args) throws IOException{
String str = "Hello world!";
File file = new File("test.txt"); //创建文件对象
//通过文件对象创建文件输出流对象
//附加第二个参数true,指定进行文件追加,默认为不追加
FileOutputStream fos = new FileOutputStream(file, true);
//逐个将字符写入到文件中
for (int i = 0; i < str.length(); i++){
fos.write(str.charAt(i));
}
fos.close(); //关闭流
}
}
public class FileOutputStreamDemo1{
//在函数内部不进行异常处理,将异常抛出函数外部
public static void main(String[] args) throws IOException{
String str = "Hello world!";
File file = new File("test.txt"); //创建文件对象
//通过文件对象创建文件输出流对象
//附加第二个参数true,指定进行文件追加,默认为不追加
FileOutputStream fos = new FileOutputStream(file, true);
//逐个将字符写入到文件中
for (int i = 0; i < str.length(); i++){
fos.write(str.charAt(i));
}
fos.close(); //关闭流
}
}
3.字节流特点
- 字节输入流和字节输出流对中文操作时是不友好的。会导致乱码的产生。
- 字节输入流和字节输出流通常不适合用于对(中文)文本进行操作。
- 字节输入流和字节输出流通常用于对媒体文件进行操作。(图片,音频,视频)
通过字节输入流和字节输出流实现文件的剪切操作。
- 读取源文件
- 将读到的数据写到目标路径
- 删除源文件
(二)字符流
1.FileWriter类-字符输出流
- FileWriter类称为文件写入流,以字符流的形式对文件进行写操作
构 造 方 法 | 说 明 |
FileWriter(File file) throws IOException | 使用File对象创建文件写入流对象,如果文件打开失败,将抛出异常,必须捕捉 |
FileWriter(File file, boolean append) throws IOException | 使用File对象创建文件写入流对象,并由参数append指定是否追加,异常情况同上 |
FileWriter(String name) throws IOException | 直接使用文件名或路径创建文件写入流对象,异常情况同上 |
FileWriter(String name, boolean append) throws IOException | 直接使用文件名或路径创建文件写入流对象,并由参数append指定是否追加,异常情况同上 |
2.BufferedWriter类-字符缓冲输出流
- BufferedWriter类可以为FileWriter类提供缓冲
构 造 方 法 | 说 明 |
BufferedWriter(Writer out) | 将字符写入流对象包装成缓冲写入流对象 |
方 法 原 型 | 说 明 |
void write(String str) throws IOException | 将一行字符串写入到缓冲写入流中,有可能抛异常,必须捕捉 |
void newLine() throws IOException | 将一个回车换行符写入到文件中,从而达到换行的效果,有可能抛异常,必须捕捉 |
/**
FileWriter配合BufferedWriter写文件
*/
public class WriterDemo{
public static void main(String[] args) throws IOException{
File file = new File("test.txt");
//通过文件对象创建文件输出字符流对象
FileWriter fw = new FileWriter(file);
//将文件输出字符流包装成缓冲流
BufferedWriter bw = new BufferedWriter(fw);
bw.write("大家好!");
bw.write("我正在学习Java。");
bw.newLine(); //换个新行
bw.write("请多多指教。");
bw.newLine(); //换新行
bw.write("Luckybug@21cn.com");
bw.close(); //关闭流
fw.close(); //关闭流
}
}
3.FileReader类-字符输入流
- FileReader类称为文件读取流,允许以字符流的形式对文件进行读操作
构 造 方 法 | 说 明 |
FileReader(File file) throws FileNotFoundException | 使用File对象创建文件读取流对象,如果文件打开失败,将抛出异常 |
FileReader(String name) throws FileNotFoundException | 使用文件名或路径创建文件读取流对象,如果文件打开失败,将抛出异常 |
该类将从文件中逐个地读取字符,效率比较低下,因此一般将该类对象包装到缓冲流中进行操作
4.BufferedReader类-字符输入缓冲流
- BufferedReader类主要为字符流提供缓冲,以提高效率
构 造 方 法 | 说 明 |
BufferedReader(Reader in) | 将字符读取流对象包装成缓冲读取流对象 |
方 法 原 型 | 说 明 |
String readLine() throws IOException | 从缓冲读取流中读取一行字符,以字符串的形式返回,有可能抛异常,必须捕捉 |
void close() throws IOException | 关闭流对象,有可能抛异常,必须捕捉 |
/**
FileReader配合BufferedReader读文件
*/
public class ReaderDemo{
public static void main(String[] args) throws IOException{
File file = new File("test.txt");
//通过文件对象创建文件读取流对象
FileReader fr = new FileReader(file);
//将文件读取流包装成缓冲读取流
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine()) != null){ //逐行读取数据
System.out.println(str);
}
br.close(); //关闭流
fr.close(); //关闭流
}
}
(三)标准输入输出流
- System.in和System.out分别代表了系统标准的输入和输出设备
- 默认输入设备是键盘,输出设备是显示器
- System.in的类型是InputStream
- System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream 的子类
- 通过System类的setIn,setOut方法对默认设备进行改变。
- public static void setIn(InputStream in)
- public static void setOut(PrintStream out)
(四)转换流
- 转换流提供了在字节流和字符流之间的转换
- Java API提供了两个转换流: InputStreamReader 和 OutputStreamWriter
- 字节流中的数据都是字符时,转成字符流操作更高效
1.InputStreamReader
用于将字节流中读取到的字节按指定字符集解码成字符。需要和InputStream“套接”。
构造方法
public InputStreamReader(InputStream in) ---将InputStream对象转换成Reader对象
public InputSreamReader(InputStream in,String charsetName)
如:
Reader isr = new InputStreamReader(System.in,”ISO5334_1”);//ISO5334_1指定字符集
2.OutputStreamWriter
用于将要写入到字节流中的字符按指定字符集编码成字节。需要和OutputStream“套接”。
构造方法
public OutputStreamWriter(OutputStream out)
public OutputSreamWriter(OutputStream out,String charsetName)
3.解码&编码
//获取标准输入流
InputStream in = System.in;
//将字节流转换为字符流
InputStreamReader isr = new InputStreamReader(in);
//将字符流装饰
BufferedReader br = new BufferedReader(isr);
String string =null;
while ((string=br.readLine())!=null) {
if ("over".equals(string)) {
break;
}
System.out.println(string.toUpperCase());
}
public void testMyInput() throws Exception{
FileInputStream fis = new FileInputStream("dbcp.txt");
FileOutputStream fos = new FileOutputStream("dbcp5.txt");
InputStreamReader isr = new InputStreamReader(fis,"GBK");
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
BufferedReader br = new BufferedReader(isr);
BufferedWriter bw = new BufferedWriter(osw);
String str = null;
while((str = br.readLine()) != null){
bw.write(str);
bw.newLine();
bw.flush();
} bw.close(); br.close();}
4.从控制台输入并写入到文件示例-标准流
/*本例从控制台接受输入,然后写入到文件中,直到用户输入"!!!"为止*/
File file = new File("input.txt"); //创建文件对象
if (!file.exists()){ //判断该文件是否存在,如果不存在则创建新文件
file.createNewFile();
}
FileWriter fr = new FileWriter(file); //针对文件对象创建文件写入流对象
BufferedWriter bw = new BufferedWriter(fr); //为文件写入流建立缓冲流
//将控制台输入对象转化成字符流,并建立缓冲流
BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));
String str = bin.readLine(); //接受从控制台输入的一行字符串
while (!(str.equals("!!!"))) //如果输入"!!!"则代表输入结束
bw.write(str); //将从控制台输入的字符串写入到文件中
bw.newLine(); //换新行
str = bin.readLine(); //再从控制台接受输入
}
//关闭所有已经打开的流
bw.close();fr.close();bin.close();
(五)数据流
基本数据类型的读/写------DataInputStream类和DataOutputStream类,将各种类型的数据写入文件或是从文件中读取。
1.DataInputStream类
DataInputStream类可以输入任何类型的数据,但它不可以单独使用,需要要配合其它字节输入流一起使用;
构 造 方 法 | 说 明 |
DataInputStream(InputStream in) | 利用其它的字节输入流创建数据输入流对象 |
//将文件输入流包装成数据输入流,以便从文件中读取各种类型的数据
FileInputStream fis = new FileInputStream("data.dat");
DataInputStream dis = new DataInputStream(fis);
方 法 原 型 | 说 明 |
final boolean readBoolean() throws IOException | 从数据输入流中读取一个boolean型数据 |
final char readChar() throws IOException | 从数据输入流中读取一个char型数据 |
final int readInt() throws IOException | 从数据输入流中读取一个int型数据 |
final long readLong() throws IOException | 从数据输入流中读取一个long型数据 |
final float readFloat() throws IOException | 从数据输入流中读取一个float型数据 |
final double readDouble() throws IOException | 从数据输入流中读取一个double型数据 |
final String readUTF() throws IOException | 从数据输入流中读取一个String型数据 |
FileInputStream in = null;
DataInputStream date = null;
File f = new File("a.dat");
try {
in=new FileInputStream(f);
date=new DataInputStream(in);
System.out.println(date.readBoolean());
System.out.println(date.readUTF());
System.out.println(date.readChar());
System.out.println(date.readInt());
} catch (Exception e) {
e.printStackTrace();
}
2.DataOutputStream类
DataOutputStream类可以输出任何类型的数据,同样也需要配合其他字节输出流一起使用;
构 造 方 法 | 说 明 |
DataOutputStream(OutputStream out) | 利用其它的字节输出流创建数据输出流对象 |
//将文件输出流包装成数据输出流,以便往文件中写入各种类型的数据
FileOutputStream fos = new FileOutputStream("data.dat");
DataOutputStream dos = new DataOutputStream(fos);
方 法 原 型 | 说 明 |
final void writeBoolean(boolean v) throws IOException | 往数据输出流中写入一个boolean型数据 |
final void writeChar(char v) throws IOException | 往数据输出流中写入一个char型数据 |
final void writeInt(int v) throws IOException | 往数据输出流中写入一个int型数据 |
final void writeLong(long v) throws IOException | 往数据输出流中写入一个long型数据 |
final void writeFloat(float v) throws IOException | 往数据输出流中写入一个float型数据 |
final void writeDouble(double v) throws IOException | 往数据输出流中写入一个double型数据 |
final void writeUTF(String v) throws IOException | 往数据输出流中写入一个String型数据 |
File file = new File("a.dat");
FileOutputStream out = null;
DataOutputStream date = null;
try {
out = new FileOutputStream(file);
date = new DataOutputStream(out);
date.writeBoolean(true);
date.writeUTF("我是中文");
date.writeChar('d');
date.writeInt(1);
System.out.println("保存成功");
} catch (Exception e) {
e.printStackTrace();
}
(六)处理流之四:打印流(了解)
在整个IO包中,打印流是输出信息最方便的类。
PrintStream(字节打印流)和PrintWriter(字符打印流)
- 提供了一系列重载的print和println方法,用于多种数据类型的输出
- PrintStream和PrintWriter的输出不会抛出异常
- PrintStream和PrintWriter有自动flush功能
- System.out返回的是PrintStream的实例
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}//创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
PrintStream ps = new PrintStream(fos,true);
if (ps != null) { // 把标准输出流(控制台输出)改成文件
System.setOut(ps);
}
for (int i = 0; i <= 255; i++) { //输出ASCII字符
System.out.print((char)i);
if (i % 50 == 0) { //每50个数据一行
System.out.println(); // 换行
}
}
ps.close();
(七)对象流
Java的对象序列化(Object Serialization)
将那些实现了 Serializable接口的对象转换成一个字节序列,并可以在以后将这个字节序列完全恢复为原来的对象。
这一过程甚至可通过网络进行。这意味着序列化机制能自动弥补不同操作系统之间的差异。
只要对象实现了 Serializable接口(该接口仅是一个标记接口,不包括任何方法),对象的序列化处理就会非常简单。当序列化的概念被加入到语言中时,许多标准库类都发生了改变,以便能够使之序列化——其中包括所有原始数据类型的包装器、所有容器类以及许多其他的东西。甚至 Class 对象也可以被序列化。
为了序列化一个对象,首先要创建某些 OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。这时,只需调用 writeObject()即可将对象序列化,并将其发送给 OutputStream。要将一个序列重组为一个对象,需要将一个 InputStream封装在 ObjectInputStream内,然后调用 readObject()。和往常一样,我们最后获得的是指向一个向上转型为 Object 的句柄,所以必须向下转型,以便能够直接对其进行设置。
public static void write() {
List<User> list = new ArrayList<User>();
list.add(new User(1, "aa"));
list.add(new User(2, "bb"));
list.add(new User(3, "cc"));
User u = new User(4, “wyl", list);
File file = new File("user.dat");
FileOutputStream out = null;
ObjectOutputStream obj = null;
try {
out=new FileOutputStream(file);
obj=new ObjectOutputStream(out)
obj.writeObject(u);
System.out.println("保存成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (obj != null)
obj.clos ();
if (out != null)
out.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
public static void read() {
User user=null;
File file=new File("user.dat");
FileInputStream in=null;
ObjectInputStream obj=null;
try {
in=new FileInputStream(file);
obj=new ObjectInputStream(in);
user=(User) obj.readObject();
user.print();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (obj != null)
obj.close();
if (in != null)
in.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
(八)RandomAccessFile 类---随机流
RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件
- 支持只访问文件的部分内容
- 可以向已存在的文件后追加内容
RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。RandomAccessFile 类对象可以自由移动记录指针:
- long getFilePointer():获取文件记录指针的当前位置
- void seek(long pos):将文件记录指针定位到 pos 位置
构造器
public RandomAccessFile(File file, String mode)
public RandomAccessFile(String name, String mode)
创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:
- r: 以只读方式打开
- rw:打开以便读取和写入
- rwd:打开以便读取和写入;同步文件内容的更新
- rws:打开以便读取和写入;同步文件内容和元数据的更新
/**
读取文件内容
*/
RandomAccessFile raf = new RandomAccessFile(“test.txt”, “rw”);
raf.seek(5);
byte [] b = new byte[1024];
int off = 0;
int len = 5;
raf.read(b, off, len);
String str = new String(b, 0, len);
System.out.println(str);
raf.close();
/**
写入文件内容
*/
RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
raf.seek(5);
//先读出来
String temp = raf.readLine();
raf.seek(5);
raf.write("xyz".getBytes());
raf.write(temp.getBytes());
raf.close();
五、字符编码
编码表的由来
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
常见的编码表
- ASCII:美国标准信息交换码。 用一个字节的7位可以表示。
- ISO8859-1:拉丁码表。欧洲码表 用一个字节的8位表示。
- GB2312:中国的中文编码表。
- GBK:中国的中文编码表升级,融合了更多的中文文字符号。
- Unicode:国际标准码,融合了多种文字。 所有文字都用两个字节来表示,Java语言使用的就是unicode
- UTF-8:最多用三个字节来表示一个字符。
编码:字符串 —> 字节数组
解码:字节数组 —> 字符串
转换流的编码应用
- 可以将字符按指定编码格式存储。
- 可以对文本数据按指定编码格式来解读。
- 指定编码表的动作由构造器完成。
六、Properties类
- 该类是位于util包里的一个工具类,与IO的结合能十分有效地读写文件,特别在准确快速读取方面效率十分高!
- 该类结合了util包里的HashMap的存储方法,使用了键值对方式
构 造 方 法 | 说 明 |
Properties() | 创建一个Properties对象 |
public static void write() {
Properties pro = new Properties();
pro.setProperty("name", “wyl");
pro.setProperty("pwd", "123");
File file = new File("demo.properties");
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
// 第二个参数是文件描述,一般写null
pro.store(out, null);
System.out.println("保存成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
public static void read() {
Properties pro=new Properties();
FileInputStream in=null;
File file=new File("demo.properties");
try {
in=new FileInputStream(file);
pro.load(in);
System.out.println(pro.getProperty("name"));
System.out.println(pro.getProperty("pwd"));
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (in != null)
in.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
七、IO流的继承体系
八、nio
- 知识点1:nio与io的区别
- 知识点2: Buffer
- 知识点3: Channel
- 知识点4:事件及nio的非阻塞读取
1.nio与io的区别
NIO和IO之间最大的区别是:
IO是面向流的,NIO是面向块(缓冲区)的
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性
2.Buffer
- Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的
- 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存
3.Channel
Java NIO的通道类似流,但又有些不同:
- 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的
- 通道可以异步地读写
- 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入
- 利用NIO进行文件拷贝的示例
4.事件及nio的非阻塞读取
- Java NIO的事件选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道
- 由于有了事件选择器,因此NIO可以以非阻塞的方式读取数据
- NIO的这些特性在网络通讯方面非常有用,我们将在网络章节利用示例为大家具体介绍非阻塞的网络IO操作