您的位置:首页 > 编程语言 > Java开发

java IO 学习

2016-07-18 00:00 417 查看

1. IO 的分类

基于字节操作的I/O接口:InputStream和OutputStream

基于字符操作的I/O接口:Writer和Reader

基于磁盘操作的I/O接口:File

基于网络操作的I/O接口:Socket(不在java.io包下)

2. I/O操作

IO 主要是指输入输出流(InputStream/OutStream)

InputStream类



OutputStream类



3. IO文件复制

InputStream 和 OutStream

public static void main(String[] args) {
try {
// 1. 获取文件流
InputStream is = new FileInputStream(new File("a.txt"));
// 2. 转化成缓冲输入流
BufferedInputStream bis = new BufferedInputStream(is);
// 3. 定义文件输出流
FileOutputStream fos = new FileOutputStream("b.txt");
// 4. 定义每次读取的大小
byte []buffer = new byte[1024];
// 5. 定义当前读取的字节数
int readCount = 0;
// 6. 定义当前读取的长度
int readLen = 0;
// 7. 如果没到文件尾,则一直读
while((readLen = bis.read(buffer)) != -1){
// 8. 通过输出流将每次输出的数据写入b文件中
fos.write(buffer,readCount,readLen-1);
readCount+=readLen;
}
// 9. 关闭流
fos.flush();
is.close();
bis.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}

Reader 和 Writer (按字节读取)

public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader(new File("a.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("c.txt")));
char[] buffer = new char[1024];
int readLen = 0;
int readCount = 0;
while((readLen = br.read(buffer)) != -1){
bw.write(buffer, readCount, readLen-1);
readCount += readLen;

}
br.close();
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}

Reader 和 Writer (按行读取)

public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader(new File("a.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("d.txt")));
String temp = null;
while((temp = br.readLine()) != null){
bw.write(temp);
}
br.close();
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}

数据流

public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream(new File("data.txt"));
FileOutputStream fos = new FileOutputStream(new File("data.txt"));
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
// 注意这里 读入的顺序 读取的顺序也一样
dos.writeUTF("faxingege");
dos.writeDouble(1.2222222);
dos.writeBoolean(false);
dos.flush();
System.out.println(dis.readUTF());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

对象流

public static void main(String[] args) {
HashMap<String, String> staff = new HashMap<String, String>();
staff.put("haha", "hello");
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("data.txt")));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("data.txt")));
oos.writeObject(staff);
oos.flush();
HashMap<String, String> staff1 = (HashMap<String, String>) ois.readObject();
System.out.println(staff1.get("haha"));
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

管道流

public static void main(String[] args) {
try {
// 定义管道流
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
// 链接管道流
pis.connect(pos);
// 定义输出线程
Thread inputThread = new Thread(new Runnable() {
@Override
public void run() {
try {
pos.write(("W:当前写入数据").getBytes());
Thread.sleep(5000);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
inputThread.start();

// 定义输入线程
Thread outputThread = new Thread(new Runnable() {
@Override
public void run() {
byte[] buffer = new byte[1024];
int readLen = 0;
try {
while (true) {
readLen = pis.read(buffer);
String s = new String(buffer, 0, readLen);
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
outputThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}

4. Socket

UDP协议

1. 协议
   UDP是OSI参考模型中一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。UDP协议适用端口分别运行在同一台设备上的多个应用程序。

   UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。
常用的UDP端口号有:

应用协议端口号
DNS53
TFTP69
SNMP161
   UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为UDP协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如DNS、TFTP、SNMP等。

2. 使用
   在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人十分不满意的环境下,UDP协议数据包丢失会比较严重。但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和QQ就是使用的UDP协议。

3. 实现
Server端

public static void main(String[] args) {
try {
// 新建一个UDP的socket
DatagramSocket udpSocket = new DatagramSocket(5555, InetAddress.getLocalHost());
// 定义个接受信息的报文类
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
// 轮询IP端口 ,如果获取信息,则输出
while(true){
udpSocket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData(), 0 , datagramPacket.getLength()));
datagramPacket.setData(new String("服务器已经收到请求").getBytes());
udpSocket.send(datagramPacket);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

Client端

public static void main(String[] args) {
try {
// 新建一个UDP的socket
DatagramSocket udpSocket = new DatagramSocket(5556, InetAddress.getLocalHost());
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = null;
while(true){
System.out.println("请输入发往服务器端的话:");
Scanner scan = new Scanner(System.in);
String ask = scan.nextLine();
System.out.println("您输入了:" + ask);
datagramPacket = new DatagramPacket(ask.getBytes(),ask.getBytes().length,InetAddress.getLocalHost(), 5555);
udpSocket.send(datagramPacket);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

TCP协议

1. 协议
   TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。

   当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文段,最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制。之后TCP把数据包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。
       TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。

   在数据正确性与合法性上,TCP用一个校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和;同时可以使用md5认证对数据进行加密。
在保证可靠性上,采用超时重传和捎带确认机制。

在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传。

在拥塞控制上,采用广受好评的TCP拥塞控制算法(也称AIMD算法)。
该算法主要包括三个主要部分:
1)加性增、乘性减;
2)慢启动;
3)对超时事件做出反应。

2.使用

连接建立

① 客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。

② 服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。

③ 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。



连接断开

(1) 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。

(2) 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。
注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。

(3) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。

(4) 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。

注意:
(1) “通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。

(2) 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。

(3) 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。



3.实现
Server端

public static void main(String[] args) {
try {
// 在5241端口上建立ServerSocket
ServerSocket serverSocket = new ServerSocket(5241);
// 轮询接受网路消息
while(true){
System.out.println("holding on line...");
// 接受TCP请求
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
byte []buffer = new byte[1024];
int readLen = 0;
int readCount = 0;
String result = "";
while((readLen = is.read(buffer)) != -1){
result += new String(buffer, readCount, readLen);
readCount += readLen-1;
}
System.out.println("服务器收到消息: " + result);
}
} catch (IOException e) {
e.printStackTrace();
}
}

client端

public static void main(String[] args) {
try {
while(true){
Socket socket = new Socket(InetAddress.getLocalHost(),5241);
OutputStream os = socket.getOutputStream();
System.out.println("请输入你想对服务器说的话:");
Scanner scan = new Scanner(System.in);
String requestStr = scan.nextLine();
os.write(requestStr.getBytes());
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}


资料部分来源百度百科

代码地址: http://git.oschina.net/ifaxin/IO_Study
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: