javaSE–九、IO流

  • Post author:
  • Post category:java


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. 读取源文件
  2. 将读到的数据写到目标路径
  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();   //关闭流
  }
}

(三)标准输入输出流

  1. System.in和System.out分别代表了系统标准的输入和输出设备
  2. 默认输入设备是键盘,输出设备是显示器
  3. System.in的类型是InputStream
  4. System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream 的子类
  5. 通过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操作



版权声明:本文为weixin_43619912原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。