1.i/o
InputStream
和InputStreamReader
是Java I/O类库中的两个关键类,用于处理字节流。它们的主要区别在于它们处理数据的方式。
InputStream:
InputStream
是用于读取字节流的抽象类。它是所有字节输入流类的父类。InputStream
的子类可以从不同的数据源读取字节,例如文件、网络连接、内存等。- 它提供了基本的字节读取方法,如
read()
,用于读取单个字节,以及read(byte[] b)
,用于读取一组字节。
InputStream inputStream = new FileInputStream("example.txt");
int data = inputStream.read(); // 读取单个字节
byte[] buffer = new byte[1024];
int bytesRead = inputStream.read(buffer); // 读取一组字节
InputStreamReader:
InputStreamReader
是Reader
类的子类,它是用于读取字符流的桥梁,将字节流转换为字符流。- 它接受一个
InputStream
作为参数,将字节流转换为字符流,并提供了字符读取方法,如read()
和read(char[] cbuf)
。 InputStreamReader
处理字符的方式是根据指定的字符编码将字节转换为字符。
InputStream inputStream = new FileInputStream("example.txt");
Reader reader = new InputStreamReader(inputStream, "UTF-8");
int charData = reader.read(); // 读取单个字符
char[] charBuffer = new char[1024];
int charsRead = reader.read(charBuffer); // 读取一组字符
BufferedReader:
BufferedReader
是Reader
类的装饰器,用于缓冲字符输入。它提供了缓冲功能,可以一次读取多个字符,以提高读取性能。BufferedReader
通常用于包装其他Reader
,例如FileReader
或InputStreamReader
,以提供缓冲的字符读取。
InputStream inputStream = new FileInputStream("example.txt");
Reader reader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(reader);
OutputStreamWriter :
OutputStreamWriter
是Java I/O类库中的一个类,用于将字符流转换为字节流。它是Writer
类的子类,允许你按字符而不是字节写入数据到输出流中,并且可以指定字符编码。
主要特点:
-
字符到字节的转换:
OutputStreamWriter
将字符数据转换为字节数据,然后将字节写入底层的输出流。 -
字符编码: 你可以在创建
OutputStreamWriter
时指定字符编码。这是非常重要的,特别是在处理文本数据时,因为它影响了字符到字节的映射。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;public class OutputStreamWriterExample {public static void main(String[] args) {try {// 创建一个字节输出流FileOutputStream fileOutputStream = new FileOutputStream("output.txt");// 创建OutputStreamWriter并指定字符编码Writer writer = new OutputStreamWriter(fileOutputStream, "UTF-8");// 写入字符数据writer.write("Hello, OutputStreamWriter!");// 关闭流writer.close();} catch (IOException e) {e.printStackTrace();}}
}
2.从网页连接socket服务器和I/O
之前我们都是通过自己写的client类连接server的,现在我们通过浏览器来连接server。
连接时,在浏览器里输入http://localhost:8080。
当我们从浏览器访问自己写的服务器时,浏览器(也就是客户端)会向服务器发送请求,我们可以通过socket的输入流来接受并打印这些请求的内容:
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));String line;//如果读到的字符串不为空,就打印。为空,则跳出循环while(!((line=bufferedReader.readLine()).isEmpty())){System.out.println(line);}
line里的内容就是请求的内容:
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,zh-TW;q=0.5
然后我们还可以向客户端返回数据:
OutputStreamWriter writer=new OutputStreamWriter(socket1.getOutputStream());
writer.write("HTTP/1.1 200 Accepted\r\n");//在响应头写完后一定要再换行才能写我们的响应体(在浏览器上展示的部分)writer.write("\r\n");//响应的内容writer.write("lyjnb");writer.flush();socket1.close();
其中,
"HTTP/1.1 200 Accepted\r\n" 是 HTTP 协议中的响应头。 "HTTP/1.1" 表示使用的是 HTTP 1.1 版本。 "200" 是响应状态码,表示请求被成功处理。 "Accepted" 是状态码的描述,表示请求已被接受。 最后的 "\r\n" 是回车和换行符,表示行结束符,HTTP 协议要求在头部信息的每一行末尾使用这个组合。
最后我们得到的效果:
package socket3_browser_to_socket;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String args[]){try(ServerSocket socket=new ServerSocket(8080)){System.out.println("waiting for client...");Socket socket1=socket.accept();System.out.println("already connected, ip address:"+socket1.getInetAddress().getHostAddress());InputStream inputStream=socket1.getInputStream();System.out.println("data received:");//BufferedReader是Reader类的装饰器,用于缓冲字符输入。它提供了缓冲功能,可以一次读取多个字符,以提高读取性能。//InputStreamReader是Reader类的子类,它是用于读取字符流的桥梁,将字节流转换为字符流。//InputStream是用于读取字节流的抽象类。它是所有字节输入流类的父类。BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));String line;//如果读到的字符串不为空,就打印。为空,则跳出循环while(!((line=bufferedReader.readLine()).isEmpty())){System.out.println(line);}OutputStreamWriter writer=new OutputStreamWriter(socket1.getOutputStream());//"HTTP/1.1 200 Accepted\r\n" 是 HTTP 协议中的响应头。//"HTTP/1.1" 表示使用的是 HTTP 1.1 版本。//"200" 是响应状态码,表示请求被成功处理。//"Accepted" 是状态码的描述,表示请求已被接受。//最后的 "\r\n" 是回车和换行符,表示行结束符,HTTP 协议要求在头部信息的每一行末尾使用这个组合。writer.write("HTTP/1.1 200 Accepted\r\n");//在响应头写完后一定要再换行才能写我们的响应体(在浏览器上展示的部分)writer.write("\r\n");//响应的内容writer.write("lyjnb");writer.flush();socket1.close();}catch (Exception e){e.printStackTrace();}}
}