java IO相关

Java流操作有关的类或接口:



Java流类图结构:


流的概念和作用

流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

IO流的分类

  • 根据处理数据类型的不同分为:字符流和字节流
  • 根据数据流向不同分为:输入流和输出流

字符流和字节流

字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

输入流和输出流

对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。 

Java IO流对象

1.输入字节流InputStreamIO 中输入字节流的继承图可见上图,可以看出:

  1. InputStream 是所有的输入字节流的父类,它是一个抽象类。
  2. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
  3. ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

2.输出字节流OutputStream

IO 中输出字节流的继承图可见上图,可以看出:

  1. OutputStream 是所有的输出字节流的父类,它是一个抽象类。
  2. ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
  3. ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。

3.字符输入流Reader

在上面的继承关系图中可以看出:

  1. Reader 是所有的输入字符流的父类,它是一个抽象类。
  2. CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
  3. BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
  4. FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
  5. InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。

4.字符输出流Writer

在上面的关系图中可以看出:

  1. Writer 是所有的输出字符流的父类,它是一个抽象类。
  2. CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
  3. BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
  4. PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
  5. OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。

         通用的写法:

          1.字节流

           

            File file=new File(filename);
            FileInputStream fis = new FileInputStream(file);
      
             //File.separator / 能够实现跨平台
            FileOutputStream fos = new FileOutputStream("C:"+File.separator+"Users/caifenghua/Desktop/1235667.txt");  
        
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = fis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);//0表示从buffer数组的0位置读len个字节
            }
            fos.close();
            fis.close();

         2.字符流 
       
      FileReader fileread=new FileReader(new File(filename));
      BufferedReader in =new BufferedReader(fileread);
      
      FileWriter filewrite =new FileWriter("C:"+File.separator+"Users"+File.separator+"caifenghua/Desktop/12356.txt");
      BufferedWriter out =new BufferedWriter(filewrite);
//      PrintWriter printout=new PrintWriter(out);//换行
      String temp;
      while((temp=in.readLine()) !=null){
          out.write(temp+"\r");//换行
      }
      in.close();
      out.close();

参考案例:

【案例1】创建一个新文件

1
2
3
4
5
6
7
8
9
10
11
import java.io.*;
class hello{
     public static void main(String[] args) {
         File f= new File( "D:\\hello.txt" );
         try {
             f.createNewFile();
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
}

【运行结果】:

程序运行之后,在d盘下会有一个名字为hello.txt的文件。

【案例2】File类的两个常量

1
2
3
4
5
6
7
import java.io.*;
class hello{
     public static void main(String[] args) {
         System.out.println(File.separator);
         System.out.println(File.pathSeparator);
     }
}

【运行结果】:

\

;

此处多说几句:有些同学可能认为,我直接在windows下使用\进行分割不行吗?当然是可以的。但是在linux下就不是\了。所以,要想使得我们的代码跨平台,更加健壮,所以,大家都采用这两个常量吧,其实也多写不了几行。呵呵、

现在我们使用File类中的常量改写上面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         try {
             f.createNewFile();
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
}

你看,没有多写多少吧,呵呵。所以建议使用File类中的常量。

 

删除一个文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
  * 删除一个文件
  * */
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         if (f.exists()){
             f.delete();
         } else {
             System.out.println( "文件不存在" );
         }
         
     }
}

创建一个文件夹

1
2
3
4
5
6
7
8
9
10
11
/**
  * 创建一个文件夹
  * */
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator+ "hello" ;
         File f= new File(fileName);
         f.mkdir();
     }
}

【运行结果】:

D盘下多了一个hello文件夹

 

列出指定目录的全部文件(包括隐藏文件):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
  * 使用list列出指定目录的全部文件
  * */
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator;
         File f= new File(fileName);
         String[] str=f.list();
         for ( int i = 0 ; i < str.length; i++) {
             System.out.println(str[i]);
         }
     }
}

【运行结果】:

$RECYCLE.BIN

360

360Downloads

360Rec

360SoftMove

Config.Msi

da

Downloads

DriversBackup

eclipse

java web整合开发和项目实战

Lenovo

MSOCache

Program

Program Files

python

RECYGLER.{8F92DA15-A229-A4D5-B5CE-5280C8B89C19}

System Volume Information

Tomcat6

var

vod_cache_data

新建文件夹

(你的运行结果应该和这个不一样的,呵呵)

但是使用list返回的是String数组,。而且列出的不是完整路径,如果想列出完整路径的话,需要使用listFiles.他返回的是File的数组

列出指定目录的全部文件(包括隐藏文件):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  * 使用listFiles列出指定目录的全部文件
  * listFiles输出的是完整路径
  * */
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator;
         File f= new File(fileName);
         File[] str=f.listFiles();
         for ( int i = 0 ; i < str.length; i++) {
             System.out.println(str[i]);
         }
     }
}

【运行结果】:

D:\$RECYCLE.BIN

D:\360

D:\360Downloads

D:\360Rec

D:\360SoftMove

D:\Config.Msi

D:\da

D:\Downloads

D:\DriversBackup

D:\eclipse

D:\java web整合开发和项目实战

D:\Lenovo

D:\MSOCache

D:\Program

D:\Program Files

D:\python

D:\RECYGLER.{8F92DA15-A229-A4D5-B5CE-5280C8B89C19}

D:\System Volume Information

D:\Tomcat6

D:\var

D:\vod_cache_data

D:\新建文件夹

通过比较可以指定,使用listFiles更加方便、

 

判断一个指定的路径是否为目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  * 使用isDirectory判断一个指定的路径是否为目录
  * */
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator;
         File f= new File(fileName);
         if (f.isDirectory()){
             System.out.println( "YES" );
         } else {
             System.out.println( "NO" );
         }
     }
}

【运行结果】:YES

 

搜索指定目录的全部内容

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
/**
  * 列出指定目录的全部内容
  * */
import java.io.*;
class hello{
     public static void main(String[] args) {
         String fileName= "D:" +File.separator;
         File f= new File(fileName);
         print(f);
     }
     public static void print(File f){
         if (f!= null ){
             if (f.isDirectory()){
                 File[] fileArray=f.listFiles();
                 if (fileArray!= null ){
                     for ( int i = 0 ; i < fileArray.length; i++) {
                         //递归调用
                         print(fileArray[i]);
                     }
                 }
             }
             else {
                 System.out.println(f);
             }
         }
     }
}

【运行结果】:

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\framepages\web4welcome_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\help_005fhome_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\help_005fhome_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\home_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\home_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\index_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\index_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\login_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\login_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\modify_005fuser_005finfo_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\modify_005fuser_005finfo_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\register_005fnotify_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\register_005fnotify_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\sign_005fup_jsp.class

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\sign_005fup_jsp.java

D:\Tomcat6\work\Catalina\localhost\nevel\org\apache\jsp\transit_jsp.class

……

 

使用RandomAccessFile写入文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
  * 使用RandomAccessFile写入文件
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         RandomAccessFile demo= new RandomAccessFile(f, "rw" );
         demo.writeBytes( "asdsad" );
         demo.writeInt( 12 );
         demo.writeBoolean( true );
         demo.writeChar( 'A' );
         demo.writeFloat( 1 .21f);
         demo.writeDouble( 12.123 );
         demo.close();  
     }
}

如果你此时打开hellotxt查看的话,会发现那是乱码。

 

字节流

【向文件中写入字符串】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
  * 字节流
  * 向文件中写入字符串
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         OutputStream out = new FileOutputStream(f);
         String str= "你好" ;
         byte [] b=str.getBytes();
         out.write(b);
         out.close();
     }
}

查看hello.txt会看到“你好”

当然也可以一个字节一个字节的写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
  * 字节流
  * 向文件中一个字节一个字节的写入字符串
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         OutputStream out = new FileOutputStream(f);
         String str= "你好" ;
         byte [] b=str.getBytes();
         for ( int i = 0 ; i < b.length; i++) {
             out.write(b[i]);
         }
         out.close();
     }
}

结果还是:“你好”

 

向文件中追加新内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
  * 字节流
  * 向文件中追加新内容:
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         OutputStream out = new FileOutputStream(f, true );
         String str= "Rollen" ;
         //String str="\r\nRollen";  可以换行
         byte [] b=str.getBytes();
         for ( int i = 0 ; i < b.length; i++) {
             out.write(b[i]);
         }
         out.close();
     }
}

【运行结果】:

你好Rollen

 

【读取文件内容】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
  * 字节流
  * 读文件内容
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         InputStream in= new FileInputStream(f);
         byte [] b= new byte [ 1024 ];
         in.read(b);
         in.close();
         System.out.println( new String(b));
     }
}

【运行结果】

你好Rollen

Rollen_

但是这个例子读取出来会有大量的空格,我们可以利用in.read(b);的返回值来设计程序。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
  * 字节流
  * 读文件内容
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         InputStream in= new FileInputStream(f);
         byte [] b= new byte [ 1024 ];
         int len=in.read(b);
         in.close();
         System.out.println( "读入长度为:" +len);
         System.out.println( new String(b, 0 ,len));
     }
}

【运行结果】:

读入长度为:18

你好Rollen

Rollen

 

读者观察上面的例子可以看出,我们预先申请了一个指定大小的空间,但是有时候这个空间可能太小,有时候可能太大,我们需要准确的大小,这样节省空间,那么我们可以这样干:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
  * 字节流
  * 读文件内容,节省空间
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         InputStream in= new FileInputStream(f);
         byte [] b= new byte [( int )f.length()];
         in.read(b);
         System.out.println( "文件长度为:" +f.length());
         in.close();
         System.out.println( new String(b));
     }
}

文件长度为:18

你好Rollen

Rollen

 

将上面的例子改为一个一个读:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
  * 字节流
  * 读文件内容,节省空间
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         InputStream in= new FileInputStream(f);
         byte [] b= new byte [( int )f.length()];
         for ( int i = 0 ; i < b.length; i++) {
             b[i]=( byte )in.read();
         }
         in.close();
         System.out.println( new String(b));
     }
}

输出的结果和上面的一样。

 

细心的读者可能会发现,上面的几个例子都是在知道文件的内容多大,然后才展开的,有时候我们不知道文件有多大,这种情况下,我们需要判断是否独到文件的末尾。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
  * 字节流
  *读文件
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         InputStream in= new FileInputStream(f);
         byte [] b= new byte [ 1024 ];
         int count = 0 ;
         int temp= 0 ;
         while ((temp=in.read())!=(- 1 )){
             b[count++]=( byte )temp;
         }
         in.close();
         System.out.println( new String(b));
     }
}

【运行结果】

你好Rollen

Rollen_

提醒一下,当独到文件末尾的时候会返回-1.正常情况下是不会返回-1

 

字符流

【向文件中写入数据】

现在我们使用字符流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  * 字符流
  * 写入数据
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         Writer out = new FileWriter(f);
         String str= "hello" ;
         out.write(str);
         out.close();
     }
}

当你打开hellotxt的时候,会看到hello

其实这个例子上之前的例子没什么区别,只是你可以直接输入字符串,而不需要你将字符串转化为字节数组。

当你如果想问文件中追加内容的时候,可以使用将上面的声明out的哪一行换为:

Writer out =new FileWriter(f,true);

这样,当你运行程序的时候,会发现文件内容变为:

hellohello如果想在文件中换行的话,需要使用“\r\n

比如将str变为String str="\r\nhello";

这样文件追加的str的内容就会换行了。

 

从文件中读内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
  * 字符流
  * 从文件中读出内容
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         char [] ch= new char [ 100 ];
         Reader read= new FileReader(f);
         int count=read.read(ch);
         read.close();
         System.out.println( "读入的长度为:" +count);
         System.out.println( "内容为" + new String(ch, 0 ,count));
     }
}

【运行结果】:

读入的长度为:17

内容为hellohello

hello

 

当然最好采用循环读取的方式,因为我们有时候不知道文件到底有多大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
  * 字符流
  * 从文件中读出内容
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "D:" +File.separator+ "hello.txt" ;
         File f= new File(fileName);
         char [] ch= new char [ 100 ];
         Reader read= new FileReader(f);
         int temp= 0 ;
         int count= 0 ;
         while ((temp=read.read())!=(- 1 )){
             ch[count++]=( char )temp;
         }
         read.close();
         System.out.println( "内容为" + new String(ch, 0 ,count));
     }
}

运行结果:

内容为hellohello

hello

 

关于字节流和字符流的区别

实际上字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的,但是字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件的。

读者可以试着将上面的字节流和字符流的程序的最后一行关闭文件的代码注释掉,然后运行程序看看。你就会发现使用字节流的话,文件中已经存在内容,但是使用字符流的时候,文件中还是没有内容的,这个时候就要刷新缓冲区。

使用字节流好还是字符流好呢?

答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。

文件的复制

其实DOS下就有一个文件复制功能,比如我们想把d盘下面的hello.txt文件复制到d盘下面的rollen.txt文件中,那么我们就可以使用下面的命令:

copy d:\hello.txt d:\rollen.txt

运行之后你会在d盘中看见hello.txt.,并且两个文件的内容是一样的,(这是屁话)

 

下面我们使用程序来复制文件吧。

基本思路还是从一个文件中读入内容,边读边写入另一个文件,就是这么简单。、

首先编写下面的代码:

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
/**
  * 文件的复制
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         if (args.length!= 2 ){
             System.out.println( "命令行参数输入有误,请检查" );
             System.exit( 1 );
         }
         File file1= new File(args[ 0 ]);
         File file2= new File(args[ 1 ]);
         
         if (!file1.exists()){
             System.out.println( "被复制的文件不存在" );
             System.exit( 1 );
         }
         InputStream input= new FileInputStream(file1);
         OutputStream output= new FileOutputStream(file2);
         if ((input!= null )&&(output!= null )){
             int temp= 0 ;
             while ((temp=input.read())!=(- 1 )){
                 output.write(temp);
             }
         }
         input.close();
         output.close();
     }
}

然后在命令行下面

javac hello.java

java hello d:\hello.txt d:\rollen.txt

现在你就会在d盘看到rollentxt了,

OutputStreramWriter 和InputStreamReader类

整个IO类中除了字节流和字符流还包括字节和字符转换流。

OutputStreamWriter 将输出的字节流转换为字符流。是字节流通向字符流的桥梁

InputStreamReader 将输入的字节流转换为字符流。是字节流通向字符流的桥梁

但是不管如何操作,最后都是以字节的形式保存在文件中的。

 

将字节输出流转化为字符输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
  * 将字节输出流转化为字符输出流
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "d:" +File.separator+ "hello.txt" ;
         File file= new File(fileName);
         Writer out= new OutputStreamWriter( new FileOutputStream(file));
         out.write( "hello" );
         out.close();
     }
}

运行结果:文件中内容为:hello

将字节输入流变为字符输入流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  * 将字节输入流变为字符输入流
  * */
import java.io.*;
class hello{
     public static void main(String[] args) throws IOException {
         String fileName= "d:" +File.separator+ "hello.txt" ;
         File file= new File(fileName);
         Reader read= new InputStreamReader( new FileInputStream(file));
         char [] b= new char [ 100 ];
         int len=read.read(b);
         System.out.println( new String(b, 0 ,len));
         read.close();
     }
}

【运行结果】:hello

前面列举的输出输入都是以文件进行的,现在我们以内容为输出输入目的地,使用内存操作流

ByteArrayInputStream 主要将内容写入内容

ByteArrayOutputStream  主要将内容从内存输出


参考:http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html
http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html


二,关于NIO

http://www.importnew.com/19816.html

http://ifeve.com/java-nio-all/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值