Java 的 I/O 大概可以分成四组:
基于字节操作的 I/O :InputStream 和 OutputStream
基于字符操作的 I/O :Writer 和 Reader
基于磁盘操作的 I/O :File
基于网络操作的 I/O :Socket
输入流只能读不能写.
输出流只能写不能读.
!java.io.RandomAccessFile类是可读可写的。
InputStream/OutputStream( 字节流 ) :一次传送一个字节。
IO中以byte[]作为缓冲,从源(可以是文件,内存中的数据等等)中读取数据到byte[]中,写入数据的时候,将byte[]写入到目标。
InputStream类中的read(byte b[], int off, int len)方法(部分):
每次从源中读取一个字节,存储到byte[] b中。最多读取len个字节。缓冲区读满或者到达源末尾后,将缓冲区的数据写入目标。
read()是一个native方法,正常返回0-255,到达源数据的末尾返回-1
InputStream/OutputStream是抽象类,使用的是其子类,子类会重新定义相关方法。为了性能这些子类中的底层实现都是native方法。
Writer/Reader实现原理相似,不同的是将流数据以一个字符的长度为单位处理,并进行编码转换。
NIO特性之一:为所有的原始类型提供(Buffer)缓存支持
拷贝文件测试IO和NIO的读写速度:
文件大小:3.2G
>> IO 读写耗时:114320 速度:30.45 M/s
>> NIO 读写耗时:86009 速度:40.47 M/s
NIO中使用Buffer来作为读写中转,Buffer是一个连续的内存块。
IO以流的方式处理数据,NIO以块的方式处理数据。
NIO中通过channel操作Buffer缓冲区,所以NIO速度比IO要快很多。
文件处理是Java IO系统中的一个子系统。
比如要读取文件,只需要new一个FileInputStream,即可以流的方式读取文件。
public FileInputStream(String name)
public FileInputStream(File file)
这两种方式都可以从文件创建一个输入流。
和其它的一样read()方法都是native的,FileInputStream命名是以InputStream结尾说明他是一个输入流,那么它的工作原理就和其它流一样。
FileInputStream中有一个getChannel(),可以得到一个FileChannel对象。这是NIO中的特性,通过channel读/写数据,提高了性能。
File类:
public String getName() {
int index = path.lastIndexOf(separatorChar);
if (index < prefixLength) return path.substring(prefixLength);
return path.substring(index + 1);
}
得到文件名,其实是获得完整路径中的最后一个/(separatorChar根据系统匹配/或者\),然后截取到文件名。
同样的getParent()也是通过截取字符串来获得父目录。
File类包含了许多对文件的操作:
public boolean isFile() //判断是不是一个文件
public boolean isHidden() //判断是不是隐藏
public long length() //文件长度
public boolean exists() //文件或目录是否存在
public boolean createNewFile() //创建文件
public boolean delete() //删除文件
...
但是,File类并不只是指文件,可以将其表示为目录。
File file=new File( "D:/");
同样的File类中也包含了对目录的操作:
public boolean isDirectory() //判断是不是一个文件夹
public String[] list() //得到文件夹下的文件和目录的名字
public File[] listFiles() //得到文件夹下的文件
public boolean mkdir() //创建目录
public boolean renameTo //重命名
...
示例:
File file=new File("c:/");
String[] files = file.list();
for(String s:files)
{
System.out.println(s);
}
输出:
$RECYCLE.BIN
alipay
bcd.dna.LOG1
bcd.dna.LOG2
Boot
bootmgr
BOOTSECT.BAK
cygwin
Documents and Settings
maxldr.mbr
Program Files
Program Files (x86)
ProgramData
Recovery
RECYCLER
System Volume Information
TCKYU
Users
Windows
可以看到list()将所有文件和文件夹都列了出来,包括隐藏文件和文件夹,顺序和实际文件夹中的显示顺序一致。
NIO特性之二:异步 I/O 支持
在通讯中就是: 提供多路 (non-bloking) 非阻塞式的高伸缩性网络 I/O
阻塞式网络IO:
accept()如果没有连接会一直阻塞
readLine()如果没有读取到数据,也会一直阻塞。
这样的方式,每个和客户端的连接都要用一个单独的线程来处理,每个线程拥有自己的栈空间并且占用一些 CPU 时间,当没有请求的时候就会阻塞。
假如每个客户端一天之和服务器通讯一次,那么这些线程全部都必须存在一天。这样就会浪费系统资源。
非阻塞式网络IO:
由一个专门的线程来处理所有的 IO 事件,并负责分发,采用事件驱动机制,事件到的时候才触发。
TCP/IP是个协议组,可分为三个层次:
网络层:IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
传输层:TCP协议、UDP协议。
应用层:FTP、HTTP、TELNET、SMTP、DNS等协议
!socket只是一种连接模式,不是协议。
TCP是基于连接的协议,必须建立好了连接,才能通讯。
适合传输大量数据,可靠的连接。
UDP不需要建立连接,直接把数据发送过去。因为不需要连接,所以效率高,但是可靠性没有TCP高。
适合速度快的,数据少的。
!ping命令的实现就是基于UDP。
http是一个协议,但是底层还是基于tcp的,
HTTP协议是建立在请求/响应模型上的。客户建立给服务器发送一条请求,服务器收到请求,给客户端返回一个响应。
基于字节操作的 I/O :InputStream 和 OutputStream
基于字符操作的 I/O :Writer 和 Reader
基于磁盘操作的 I/O :File
基于网络操作的 I/O :Socket
输入流只能读不能写.
输出流只能写不能读.
!java.io.RandomAccessFile类是可读可写的。
5.1 IO
InputStream/OutputStream的工作原理:InputStream/OutputStream( 字节流 ) :一次传送一个字节。
IO中以byte[]作为缓冲,从源(可以是文件,内存中的数据等等)中读取数据到byte[]中,写入数据的时候,将byte[]写入到目标。
InputStream类中的read(byte b[], int off, int len)方法(部分):
int i = 1;
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
每次从源中读取一个字节,存储到byte[] b中。最多读取len个字节。缓冲区读满或者到达源末尾后,将缓冲区的数据写入目标。
read()是一个native方法,正常返回0-255,到达源数据的末尾返回-1
InputStream/OutputStream是抽象类,使用的是其子类,子类会重新定义相关方法。为了性能这些子类中的底层实现都是native方法。
Writer/Reader实现原理相似,不同的是将流数据以一个字符的长度为单位处理,并进行编码转换。
5.2 NIO
NIO特性之一:为所有的原始类型提供(Buffer)缓存支持
拷贝文件测试IO和NIO的读写速度:
//IO方式
public void copyFileByIO(File file, File newFile)
{
try
{
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(newFile, true);
byte[] bytes = new byte[1024];
while (fis.read(bytes) != -1)
{
fos.write(bytes);
}
if(fis!=null)
fis.close();
if(fos!=null)
fos.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
//NIO方式
public static void copyFileByNIO(File file, File newFile)
{
try
{
FileChannel fcin = new FileInputStream(file).getChannel();
FileChannel fcout = new FileOutputStream(newFile, true).getChannel();
ByteBuffer bb = ByteBuffer.allocate(1024);
while (fcin.read(bb) != -1)
{
bb.flip();
fcout.write(bb);
bb.clear();
}
if(fcin!=null)
fcin.close();
if(fcout!=null)
fcout.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
文件大小:3.2G
>> IO 读写耗时:114320 速度:30.45 M/s
>> NIO 读写耗时:86009 速度:40.47 M/s
NIO中使用Buffer来作为读写中转,Buffer是一个连续的内存块。
IO以流的方式处理数据,NIO以块的方式处理数据。
NIO中通过channel操作Buffer缓冲区,所以NIO速度比IO要快很多。
5.3 文件
文件处理是Java IO系统中的一个子系统。
比如要读取文件,只需要new一个FileInputStream,即可以流的方式读取文件。
public FileInputStream(String name)
public FileInputStream(File file)
这两种方式都可以从文件创建一个输入流。
和其它的一样read()方法都是native的,FileInputStream命名是以InputStream结尾说明他是一个输入流,那么它的工作原理就和其它流一样。
FileInputStream中有一个getChannel(),可以得到一个FileChannel对象。这是NIO中的特性,通过channel读/写数据,提高了性能。
File类:
public String getName() {
int index = path.lastIndexOf(separatorChar);
if (index < prefixLength) return path.substring(prefixLength);
return path.substring(index + 1);
}
得到文件名,其实是获得完整路径中的最后一个/(separatorChar根据系统匹配/或者\),然后截取到文件名。
同样的getParent()也是通过截取字符串来获得父目录。
File类包含了许多对文件的操作:
public boolean isFile() //判断是不是一个文件
public boolean isHidden() //判断是不是隐藏
public long length() //文件长度
public boolean exists() //文件或目录是否存在
public boolean createNewFile() //创建文件
public boolean delete() //删除文件
...
但是,File类并不只是指文件,可以将其表示为目录。
File file=new File( "D:/");
同样的File类中也包含了对目录的操作:
public boolean isDirectory() //判断是不是一个文件夹
public String[] list() //得到文件夹下的文件和目录的名字
public File[] listFiles() //得到文件夹下的文件
public boolean mkdir() //创建目录
public boolean renameTo //重命名
...
示例:
File file=new File("c:/");
String[] files = file.list();
for(String s:files)
{
System.out.println(s);
}
输出:
$RECYCLE.BIN
alipay
bcd.dna.LOG1
bcd.dna.LOG2
Boot
bootmgr
BOOTSECT.BAK
cygwin
Documents and Settings
maxldr.mbr
Program Files
Program Files (x86)
ProgramData
Recovery
RECYCLER
System Volume Information
TCKYU
Users
Windows
可以看到list()将所有文件和文件夹都列了出来,包括隐藏文件和文件夹,顺序和实际文件夹中的显示顺序一致。
5.4 通讯
NIO特性之二:异步 I/O 支持
在通讯中就是: 提供多路 (non-bloking) 非阻塞式的高伸缩性网络 I/O
阻塞式网络IO:
ServerSocket server=new ServerSocket(9999);
Socket socket=server.accept();//使用accept()阻塞等待请求
BufferedReader is=new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter os=new PrintWriter(client.getOutputStream());
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
while(true)
{
String str=is.readLine();
}
//...
accept()如果没有连接会一直阻塞
readLine()如果没有读取到数据,也会一直阻塞。
这样的方式,每个和客户端的连接都要用一个单独的线程来处理,每个线程拥有自己的栈空间并且占用一些 CPU 时间,当没有请求的时候就会阻塞。
假如每个客户端一天之和服务器通讯一次,那么这些线程全部都必须存在一天。这样就会浪费系统资源。
非阻塞式网络IO:
由一个专门的线程来处理所有的 IO 事件,并负责分发,采用事件驱动机制,事件到的时候才触发。
5.5 关于TCP、UDP、HTTP
TCP/IP是个协议组,可分为三个层次:
网络层:IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
传输层:TCP协议、UDP协议。
应用层:FTP、HTTP、TELNET、SMTP、DNS等协议
!socket只是一种连接模式,不是协议。
TCP是基于连接的协议,必须建立好了连接,才能通讯。
适合传输大量数据,可靠的连接。
UDP不需要建立连接,直接把数据发送过去。因为不需要连接,所以效率高,但是可靠性没有TCP高。
适合速度快的,数据少的。
!ping命令的实现就是基于UDP。
http是一个协议,但是底层还是基于tcp的,
HTTP协议是建立在请求/响应模型上的。客户建立给服务器发送一条请求,服务器收到请求,给客户端返回一个响应。