IO流
File类
File类提供了一个常量:public static final String separator。根据操作系统,动态的提供分隔符。
* 如何创建File类的实例
File(String filePath)
File(String parentPath,String childPath)
File(File parentFile,String childPath)
* 路径
相对路径:相较于某个路径下,指明的路径。
绝对路径:包含盘符在内的文件或文件目录的路径
* 路径分隔符
windows:\\
unix:/
常用方法
* 适用文件
public String getAbsolutePath():获取绝对路径
public String getPath() :获取路径
public String getName() :获取名称
public String getParent():获取上层文件目录路径。若无,返回null
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值
* 如下的两个方法适用于文件目录:
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
public boolean renameTo(File dest):把文件重命名为指定的文件路径(比如:file1.renameTo(file2)为例:要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。)
* 判断
public boolean isDirectory():判断是否是文件目录
public boolean isFile() :判断是否是文件
public boolean exists() :判断是否存在
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏
* 创建硬盘中对应的文件或文件目录
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs() :创建文件目录。如果此文件目录存在,就不创建了。如果上层文件目录不存在,一并创建
public boolean delete():删除文件或者文件夹(删除注意事项:Java中的删除不走回收站。)
I0流原理及流的分类
I/O是Input/Output的缩写, I/O技术是非常实用的技术, 用于处理设备之间的数据传输。 如读/写文件,网络通讯等。
节点流和文件流
new File(“xxxx”); // 对于当前工程或者对于当前module
不能使用字符流来处理图片等字节数据
读取基本使用
/**
* 说明点:
* 1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
* 2. 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
* 3. 读入的文件一定要存在,否则就会报FileNotFoundException。
*/
@Test
public void testFileReader() {
// File file1 = new File("z1.txt"); // 对于当前工程
FileReader fileReader = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\z1.txt");
System.out.println(file.getAbsolutePath());
//2.提供具体的流
fileReader = new FileReader(file);
//3.数据的操作
int read ;
while ((read = fileReader.read()) != -1){
System.out.print((char) read);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//对read()操作升级:使用read的重载方法
//read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
@Test
public void testFileReader1()
{
FileReader fileReader = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\z1.txt");
//2.提供具体的流
fileReader = new FileReader(file);
//3.数据的操作
char[] cBuffer = new char[5];
int len;
while ((len = fileReader.read(cBuffer)) != -1){
//方式一:
// 错误写法:
// for (int i = 0; i < cBuffer.length; i++) {
// System.out.print(cBuffer[i]); // abcdefghijkl12345623
// }
// // 正确写法:
// for (int i = 0; i < len; i++) {
// System.out.print(cBuffer[i]); // abcdefghijkl123456
// }
//方式二:
// 错误写法:
// String s = new String(cBuffer);
// System.out.print(s);
// 正确写法:
String s = new String(cBuffer,0,len);
System.out.print(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//4.流的关闭操作
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
写入基本使用
/*
从内存中写出数据到硬盘的文件里。
说明:
1. 输出操作,对应的File可以不存在的。并不会报异常
2.
File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
File对应的硬盘中的文件如果存在:
如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容
*/
@Test
public void testFileWriter(){
FileWriter fileWriter = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\z_add.txt");
//2.提供具体的流
fileWriter = new FileWriter(file);
//3.数据的操作
fileWriter.write("pujie\n");
fileWriter.write("zhedouluqubudao");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文件复制
public void testFileReaderFileWriter() {
FileReader fileReader = null;
FileWriter fileWriter = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file1 = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\z1.txt");
File file2 = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\z_add.txt");
//2.提供具体的流
fileReader = new FileReader(file1);
fileWriter = new FileWriter(file2);
//3.数据的操作
int read;
while ((read = fileReader.read()) != -1){
fileWriter.write((char)read);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试FileInputStream和FileOutputStream的使用
-
- 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理(字节流处理不了非ASCII码)(当非ASCII使用操作流时,不查看不另外获取也可用字节流处理)
-
- 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
缓冲流
基本使用(字节型为例子)
* 1.缓冲流:
* BufferedInputStream
* BufferedOutputStream
* BufferedReader
* BufferedWriter
*
* 2.作用:提供流的读取、写入的速度
* 提高读写速度的原因:内部提供了一个缓冲区
*
* 3. 处理流,就是“套接”在已有的流的基础上。
@Test
public void BufferedStreamTest() {
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
//1.造文件
File file = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\20180327151337610.png");
File file2 = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\22.png");
//2.造流
//2.1 造节点流
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file2);
//2.2 造缓冲流
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
byte[] buffer = new byte[1024];
int len;
while ((len = bufferedInputStream.read(buffer)) != -1){
bufferedOutputStream.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
try {
if (bufferedInputStream != null)
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bufferedOutputStream != null)
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
加密操作
@Test
public void BufferedStreamTest() {
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
//1.造文件
File file = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\33.png");
File file2 = new File("D:\\apache-maven-3.6.3\\maven_repo\\chen_spring_boot\\src\\test\\java\\io\\44.png");
//2.造流
//2.1 造节点流
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file2);
//2.2 造缓冲流
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
byte[] buffer = new byte[1024];
int len;
while ((len = bufferedInputStream.read(buffer)) != -1){
for (int i = 0; i < len; i++) {
buffer[i] = (byte) (buffer[i] ^ 5);
}
bufferedOutputStream.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
try {
if (bufferedInputStream != null)
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bufferedOutputStream != null)
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
a^n^n=a
转换流
* 1.转换流:属于字符流
* InputStreamReader:是Reader的子类,将输入的字节流变为字符流
* OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流
*
* 2.作用:提供字节流与字符流之间的转换
*
* 3. 解码:字节、字节数组 --->字符数组、字符串
* 编码:字符数组、字符串 ---> 字节、字节数组
*
*
* 4.字符集
*ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。最多两个字节编码所有字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
综合使用InputStreamReader和OutputStreamWriter
*/
@Test
public void test2() throws Exception {
//1.造文件、造流
File file1 = new File("dbcp.txt");
File file2 = new File("dbcp_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
//2.读写过程
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}
//3.关闭资源
isr.close();
osw.close();
}
字符编码
标准输入、输出流
/*
1.标准的输入、输出流
1.1
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
1.2
System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。
1.3练习:
从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,
直至当输入“e”或者“exit”时,退出程序。
方法一:使用Scanner实现,调用next()返回一个字符串
方法二:使用System.in实现。System.in ---> 转换流 ---> BufferedReader的readLine()
*/
public static void main(String[] args) {
BufferedReader br = null;
try {
InputStreamReader isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);
while (true) {
System.out.println("请输入字符串:");
String data = br.readLine();
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println(upperCase);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
readLine(),读取行
打印流
/*
2. 打印流:PrintStream 和PrintWriter
2.1 提供了一系列重载的print() 和 println()
*/
@Test
public void test2() {
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
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(); // 换行
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}
}
数据流
/*
3. 数据流
3.1 DataInputStream 和 DataOutputStream
3.2 作用:用于读取或写出基本数据类型的变量或字符串
练习:将内存中的字符串、基本数据类型的变量写出到文件中。
注意:处理异常的话,仍然应该使用try-catch-finally.
*/
@Test
public void test3() throws IOException {
//1.
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
//2.
dos.writeUTF("刘建辰");
dos.flush();//刷新操作,将内存中的数据写入文件
dos.writeInt(23);
dos.flush();
dos.writeBoolean(true);
dos.flush();
//3.
dos.close();
}
/*
将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。
注意点:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!
*/
@Test
public void test4() throws IOException {
//1.
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
//2.
String name = dis.readUTF();
int age = dis.readInt();
boolean isMale = dis.readBoolean();
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("isMale = " + isMale);
//3.
dis.close();
}
对象流
序列化和反序列化
- 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
- 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。
- 序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是JavaEE 平台的基础
- 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出NotSerializableException异常:
- Serializable
- Externalizable
- 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
- private static final long serialVersionUID;
- serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
- 如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
- Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
实例化的类
* 类需要满足如下的要求,方可序列化
* 1.需要实现接口:Serializable
* 2.当前类提供一个全局常量:serialVersionUID
* 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
* 也必须是可序列化的。(默认情况下,基本数据类型可序列化)
* 4.序列化的类不可以是内部类
*
* 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
transient扩展
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
对象流概念
- 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
- 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
- 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制
- 序列化的类不可以是内部类
/*
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
使用ObjectOutputStream实现
*/
@Test
public void testObjectOutputStream() throws IOException {
// 造流
FileOutputStream fileOutputStream = new FileOutputStream("object.dat");
ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
// 流操作
outputStream.writeObject(new String("zgc是基地啊家"));
outputStream.flush();//刷新操作
outputStream.writeObject(new Person("zgc",18));
// 关闭流
outputStream.close();
}
/*
反序列化:将磁盘文件中的对象或通过网络传输还原为内存中的一个java对象
使用ObjectInputStream来实现
*/
@Test
public void testObjectInputStream() throws IOException, ClassNotFoundException {
// 造流
FileInputStream fileInputStream = new FileInputStream("object.dat");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
// 流操作
Object o = objectInputStream.readObject();
System.out.println((String) o);
Object o1 = objectInputStream.readObject();
System.out.println(o1);
// 关闭流
objectInputStream.close();
}
随机存取文件流
概念
* 我们可以用RandomAccessFile这个类,来实现一个多线程断点下载的功能,
* JDK 1.6上面写的每次write数据时,"rw"模式,数据不会立即写到硬盘中;而"rwd" ,数据会被立即写入硬盘。如果写数据过程发生异常,"rwd"模式中已被write的数据被保存到硬盘,而"rw"则全部丢失。
基本使用
* RandomAccessFile的使用
* 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
* 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
*
* 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
* 如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
*
* 4. 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果
// 输出流与输入流
@Test
public void test1() throws IOException {
// 造流
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("微信图片_20210622200806.jpg"),"r");
RandomAccessFile randomAccessFile2 = new RandomAccessFile(new File("微信图片_20210622200806_2.jpg"),"rw");
// 流的操作
int len;
byte[] bytes = new byte[1024];
while ((len = randomAccessFile1.read(bytes)) != -1){
randomAccessFile2.write(bytes);
}
// 关闭流
randomAccessFile1.close();
randomAccessFile2.close();
}
// 插入(默认插入是从头替换)
@Test
public void test2() throws IOException {
// 造流
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("zgc.txt"),"rw");
// 流的操作
// 调整指针位置
randomAccessFile1.seek(3);
StringBuilder builder = new StringBuilder((int)new File("zgc.txt").length());
int len;
byte[] bytes = new byte[1024];
while ((len = randomAccessFile1.read(bytes)) != -1){
builder.append(new String(bytes,0,len));
};
// 插入
randomAccessFile1.seek(3);
randomAccessFile1.write("新增".getBytes());
// 补回旧的数据
randomAccessFile1.write(builder.toString().getBytes());
// 关闭流
randomAccessFile1.close();
}
NIO.2中Path、Paths、Files类的使用
概念
NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
FileUtils
public class FileUtilsTest {
public static void main(String[] args) throws IOException {
File file = FileUtils.getFile("io_zgc\\微信图片_20210622200806.jpg");
File file_3 = FileUtils.getFile("io_zgc\\微信图片_20210622200806_3.jpg");
FileUtils.copyFile(file,file_3);
}
}
Path接口
Paths则包含了两个返回Path的静态工厂方法。
Files 类
网络编程
网络通信要素概述
通信要素1 : IP和端口号
* InetAddress类没有提供公共的构造器,而是提供了如下几个静态方法来获取InetAddress实例
public static InetAddress getLocalHost()
public static InetAddress getByName(String host)
* InetAddress提供了如下几个常用的方法
public String getHostAddress():返回 IP 地址字符串(以文本表现形式)。
public String getHostName():获取此 IP 地址的主机名
public boolean isReachable(int timeout):测试是否可以达到该地址
通信要素2 :网络协议
TCP 和 UDP
* TCP协议:(类似打手机电话)
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,点对点通信,是可靠的
TCP协议进行通信的两个应用进程:客户端、服务端。
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低
* UDP协议:(类似发手机短信)
将数据、源、目的封装成数据包,不需要建立连接
每个数据报的大小限制在64K内
发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
可以广播发送
发送数据结束时无需释放资源,开销小,速度快
Socket
* 利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实上的标准。
* 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
* 通信的两端都要有Socket,是两台机器间通信的端点。
* 网络通信其实就是Socket间的通信。
* Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
* 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。
* Socket分类:
流套接字(stream socket):使用TCP提供可依赖的字节流服务
数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
TCP网络编程
客户端
* 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。Socket的构造器是:
Socket(String host,int port)throws UnknownHostException,IOException:向服务器(域名是host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。
Socket(InetAddress address,int port)throws IOException:根据InetAddress对象所表示的IP地址以及端口号port发起连接。
* 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输
* 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
* 关闭 Socket:断开客户端到服务器的连接,释放线路
客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接。
服务端
* 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
* 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
* 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收。
* 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
ServerSocket 对象负责等待客户端请求建立套接字连接。也就是说,服务器必须事先建立一个等待客户请求建立套接字连接的ServerSocket对象。
代码_文本
//客户端
@Test
public void client() throws IOException {
// 创建 Socket
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 23334);
// 连接到 Socket 的输入/出流
OutputStream outputStream = socket.getOutputStream();
// 流的操作
outputStream.write("我是客户端发出的".getBytes());
// 关闭流
outputStream.close();
socket.close();
}
//服务端
@Test
public void server() throws IOException {
// 创建 ServerSocket
ServerSocket serverSocket = new ServerSocket(23334);
// 监听请求
Socket socket = serverSocket.accept();
// 连接到 Socket 的输入/出流
InputStream inputStream = socket.getInputStream();
// 流的操作
// 不推荐写法,中文的3字节确定是刚好在1024截止
// int len;
// byte[] bytes = new byte[1024];
// while ((len = inputStream.read(bytes)) != -1){
// System.out.print(new String(bytes,0,len));
// }
// 推荐使用ByteArrayOutputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1){
byteArrayOutputStream.write(bytes,0,len);
}
System.out.println(byteArrayOutputStream.toString());
// 关闭流
inputStream.close();
socket.close();
serverSocket.close();
}
代码_文件
//客户端
@Test
public void client() throws IOException {
// 创建 Socket
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 23334);
// 连接到 Socket 的输入/出流
OutputStream outputStream = socket.getOutputStream();
// 流的操作
FileInputStream fileInputStream = new FileInputStream("微信图片_20210622200806.jpg");
int len;
byte[] bytes = new byte[1024];
while ((len = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,len);
}
// 关闭流
fileInputStream.close();
outputStream.close();
socket.close();
}
//服务端
@Test
public void server() throws IOException {
// 创建 ServerSocket
ServerSocket serverSocket = new ServerSocket(23334);
// // 监听请求
Socket socket = serverSocket.accept();
// 连接到 Socket 的输入/出流
InputStream inputStream = socket.getInputStream();
// 流的操作
FileOutputStream fileOutputStream = new FileOutputStream("微信图片_20210622200806_4.jpg");
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0,len);
}
// 关闭流
fileOutputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
UDP网络编程
概念
* 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。
* UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
* DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
DatagramSocket-发送和接受
* public DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。套接字将被绑定到通配符地址,IP 地址由内核来选择。
* public DatagramSocket(int port,InetAddress laddr)创建数据报套接字,将其绑定到指定的本地地址。本地端口必须在 0 到 65535 之间(包括两者)。如果 IP 地址为 0.0.0.0,套接字将被绑定到通配符地址,IP 地址由内核选择。
* public void close()关闭此数据报套接字。
* public void send(DatagramPacket p)从此套接字发送数据报包。DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。
* public void receive(DatagramPacket p)从此套接字接收数据报包。当此方法返回时,DatagramPacket的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 此方法在接收到数据报前一直阻塞。数据报包对象的 length 字段包含所接收信息的长度。如果信息比包的长度长,该信息将被截短。
* public InetAddress getLocalAddress()获取套接字绑定的本地地址。
* public int getLocalPort()返回此套接字绑定的本地主机上的端口号。
* public InetAddress getInetAddress()返回此套接字连接的地址。如果套接字未连接,则返回 null。
* public int getPort()返回此套接字的端口。如果套接字未连接,则返`在这里插入代码片`回 -1。
DatagramPacket-UDP数据报
* public DatagramPacket(byte[] buf,int length)构造 DatagramPacket,用来接收长度为 length 的数据包。 length 参数必须小于等于 buf.length。
* public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length参数必须小于等于 buf.length。
* public InetAddress getAddress()返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
* public int getPort()返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
* public byte[] getData()返回数据缓冲区。接收到的或将要发送的数据从缓冲区中的偏移量 offset 处开始,持续 length 长度。
* public int getLength()返回将要发送或接收到的数据的长度。
代码
//发送端
@Test
public void sender() throws IOException {
// 创建DatagramSocket
DatagramSocket datagramSocket = new DatagramSocket();
// 封装DatagramPacket
// public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length参数必须小于等于 buf.length。
byte[] bytes= "我是UDP方式发送的".getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 6333);
// DatagramSocket处理DatagramPacket-发送数据
datagramSocket.send(datagramPacket);
// 关闭流
datagramSocket.close();
}
//接收端
@Test
public void receiver() throws IOException {
// 创建DatagramSocket
DatagramSocket datagramSocket = new DatagramSocket(6333);
// 封装DatagramPacket
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
// DatagramSocket处理DatagramPacket-接受数据
datagramSocket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
// 关闭流
datagramSocket.close();
}
URL编程
URL
* public String getProtocol( ) 获取该URL的协议名
* public String getHost( ) 获取该URL的主机名
* public String getPort( ) 获取该URL的端口号
* public String getPath( ) 获取该URL的文件路径
* public String getFile( ) 获取该URL的文件名
* public String getQuery( ) 获取该URL的查询名
针对HTTP协议的URLConnection类
// 通过URLConnection对象获取的输入流和输出流,即可以与现有的CGI
程序进行交互。
* public Object getContent( ) throws IOException
* public int getContentLength( )
* public String getContentType( )
* public long getDate( )
* public long getLastModified( )
* public InputStream getInputStream( )throws IOException
* public OutputSteram getOutputStream( )throws IOException
基本使用
public static void main(String[] args) {
HttpURLConnection urlConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL("https://t7.baidu.com/it/u=4036010509,3445021118&fm=193&f=GIF");
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
is = urlConnection.getInputStream();
fos = new FileOutputStream("io_zgc\\beauty3.jpg");
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fos.write(buffer,0,len);
}
System.out.println("下载完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(urlConnection != null){
urlConnection.disconnect();
}
}
}