JAVA30天-高级篇-6-IO流与网络编程

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的使用

    1. 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理(字节流处理不了非ASCII码)(当非ASCII使用操作流时,不查看不另外获取也可用字节流处理)
    1. 对于非文本文件(.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个字节来表示一个字符。
    综合使用InputStreamReaderOutputStreamWriter
     */
    @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();

    }

对象流

序列化和反序列化

  1. 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
  2. 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。
  3. 序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是JavaEE 平台的基础
  4. 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出NotSerializableException异常:
    • Serializable
    • Externalizable
  5. 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
    • private static final long serialVersionUID;
    • serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
    • 如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
  6. Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
实例化的类
 * 类需要满足如下的要求,方可序列化
 * 1.需要实现接口:Serializable
 * 2.当前类提供一个全局常量:serialVersionUID
 * 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
 *   也必须是可序列化的。(默认情况下,基本数据类型可序列化)
 * 4.序列化的类不可以是内部类
 *
 * 补充:ObjectOutputStreamObjectInputStream不能序列化statictransient修饰的成员变量
transient扩展
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。

2transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。

3)被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

对象流概念

  1. 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
  2. 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
  3. 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制
  4. 序列化的类不可以是内部类
    /*
    序列化过程:将内存中的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类,实现了DataInputDataOutput接口
 * 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 ():获取输出流和输入流,开始网络数据的发送和接收。
* 关闭ServerSocketSocket对象:客户端访问结束,关闭通信套接字。

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网络编程

概念

*DatagramSocketDatagramPacket 实现了基于 UDP 协议网络程序。
* UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
* DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

DatagramSocket-发送和接受

* public DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。套接字将被绑定到通配符地址,IP 地址由内核来选择。
* public DatagramSocket(int port,InetAddress laddr)创建数据报套接字,将其绑定到指定的本地地址。本地端口必须在 065535 之间(包括两者)。如果 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();
            }
        }

    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值