Java io flow, attribute set Properties, buffer flow, conversion flow, serialization and deserialization, print flow, network programming (TCP communication program, file copy case, file upload case, B/S service case)

I流:

In the io stream, i means input input, o means output output, and stream means data (character, byte, 1 character = 2 bytes = 8 bits); the input and output here are based on memory, and the data is transferred from the memory The process of outputting to the hard disk is called output, and the input of data from the hard disk to the memory is called input, and the input and output here are called io streams; this data input and output has characters and bytes, so it can be divided into Character streams and byte streams.

Byte stream: everything is a byte, all files are stored in units of bytes, one byte = 8 bits, and the read and write of files is in units of bytes. No matter what the stream is, the bottom-level transmission is still binary data; the byte stream is divided into byte output stream OutputStream and byte input stream InputStream.

OutputSteam output stream: OutputSteam is the top-level parent class of all output streams. This class is an abstract class. Its subclasses are known as: ByteArrayOutputStream, a byte output stream that writes data into a byte array, and FileOutputStream, a word that writes data into a file Section output stream, FilterOutputStream byte output stream with filter, ObjectOutputStream object output stream, PipedOutputSream pipeline stream

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;

public class TestOutputStream {
    
    
    // 1.OutputSteam是一个抽象类,此类定义了一些共性的方法和一些子类,如:FileOutputStream将内存中的数据写入到硬盘中的文件中:
    // 2.FileOutputStream有两个构造方法,分别传入一个字符串或File,表示数据写入的目的地,实际就是一个路径。
    // 3.FileOutputStream的作用:1.创建FileOutputStream对象 2.根据构造方法中的路径创建一个空文件 3.把FileOutputStream对象指向创建好的文件
    // 4.内存写入数据到硬盘的原理:java程序-->jvm虚拟机-->os操作系统-->os调写数据的方法-->把数据写入到文件中
    // 5.字节输出流的使用步骤:1.创建一个FileOutputStream对象,构造方法中传入写入数据文件的目的地(文件或路径)2.调用FileOutputStream对象中的write方法将数据写入到文件 3.释放系统资源(流在使用的过程中占用了一部分内存资源,使用完要释放掉,提高程序的效率,不释放也没关系)
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建一个FileOutputStream对象
        FileOutputStream fos = new FileOutputStream("D:\\00.java高级\\练习\\javaDemo\\075.OutputStream流\\hello.txt"); // 这个路径可以是相对路径,这里可能会抛出异常,需要处理
        // 2.将数据写入到文件
        fos.write(97); // write会抛出异常,需要处理,这里97表示小写的a,int类型表示的是字节对应的Ascall码值,97对应的字节写入到硬盘中最终是以二进制存储的,任意的文本编辑器在打开文件时都会去查Ascall码表或系统码表(gbk等),把字节转为字符表示。
        fos.write('g'); // 直接写入一个字节,一个字节等于8个比特位(10101010),一个字节的比特位最大值11111111(十六进制FF、十进制255)
        fos.write('中'); // 汉字在这里乱码了,但是还是可以写入的,

        // 一次写入多个字节:1.支持byte数组 2.支持一部分byte数组写入(byte[] b, int off, int length),b表示byte数组,off表示开始位置,length表示写入数组的长度
        // 如果写的第一个字节是正数(0-127)那么显示的时候会查Ascall表;如果写入的第一个字节是负数,那么第一个字节会和第二个字节组成一个中文,查询系统默认码表(gbk)
        byte[] ls = {
    
    97,12,99,97,12,99};
        fos.write(ls);
        byte[] ls2 = {
    
    -97,-12,99};
        fos.write(ls2);
        byte[] lss = {
    
    97,12,99,97,12,99};
        fos.write(lss,1,2);

        // 写入字符串:利用字符串转byte数组api getByte
        byte[] strls = "你好".getBytes();
        System.out.println(Arrays.toString(strls)); // [-28, -67, -96, -27, -91, -67]
        fos.write(strls);

        // 文件中输出:ag-acac燈cc浣犲ソ,这里看到并没有你好,是因为这里是按utf-8字符编码集,三个字节为一个中文,而gbk中为两个字节为一个中文
        // 3.释放资源:
        fos.close();

        // 4.追加数据:每次执行上面的代码实际都是将源文件覆盖掉的,如果想要在当前文件继续追加数据可以使用两个参数的构造方法FileOutputStream,其中第一个构造方法参数表示目标文件,第二个参数表示是否开启追加:
        FileOutputStream fos2 = new FileOutputStream("D:\\00.java高级\\练习\\javaDemo\\075.OutputStream流\\append.txt", true);
        fos2.write('g');// 每次执行都会追加字符上去
        fos2.write("\r\n".getBytes()); // 换行:win(\r\n)、linux(/n)、mac(/r)
        fos2.write("你好".getBytes());
        fos2.close();
    };
}

InputStream byte input stream: This class is also a subclass of the io stream class. It is also abstract and is the parent class of all byte input streams. There are some subclasses under it: BufferedInputStream, AudioInputStream to read audio, ByteArrayInputStream to read Get byte array, FileInputStream read file, DataInputStream, FilterInputStream with filter, read(), OutputStream, PushbackInputStream, ObjectInputStream read object, PipedInputStream pipeline stream, SequenceInputStream process queue, StringBufferInputStream read string buffer

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;

public class TestFileInputStream {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 1.FileInputStream文件字节流输入流,将硬盘中文件中的数据读取到内存中,其构造方法中参数表示要读取文件的路径或文件
        // 2.构造方法的作用:1.创建一个FileInputStream对象 2.将FileInputStream对象指定构造方法中要读取的文件
        // 3.读取数据原理:java程序-->jvm-->os-->os读取数据的方法-->读取文件
        // 4.字节输入流的使用步骤:1.创建一个FileInputStream对象,构造方法参数指明文件 2.调用FileInputStream的read方法读取文件 3.调用FileInputStream的close方法释放资源

        // 1.创建FileInputStream对象:
        FileInputStream fis = new FileInputStream("D:\\00.java高级\\练习\\javaDemo\\076.InputStream流\\test.txt");
        int num;
        do {
    
    
            num = fis.read(); // 2.读取文件中的一个字节并返回,读取到文件末尾返回-1
            System.out.println(num);
            System.out.println((char)num);

            byte[] ls = new byte[2];
            int num2 = fis.read(ls); // read传入一个字节数组时读取字节数组长度的字节并返回给字节数组
            System.out.println(Arrays.toString(ls)); // [0, 0]
            System.out.println(num2);
            System.out.println((char)num2);
            System.out.println("---------------");
        } while (num != -1);
        // 3.释放资源:
        fis.close();
    };
}

File copy demo:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyFileDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 创建读文件的流:将内存中的数据流输出(读取),写入到文件中
        FileOutputStream fos = new FileOutputStream("D:\\00.java高级\\练习\\javaDemo\\076.InputStream流\\copy_test.mp4");
        // 创建写文件的流:将文件读取到内存缓存区
        FileInputStream fis = new FileInputStream("D:\\00.java高级\\练习\\javaDemo\\076.InputStream流\\test.mp4");
        // 一读一写实现文件拷贝:
        int bts = 0; // 记录每次读取有效字节个数
        // 循环将硬盘中的文件数据写入内存,如果不指定字节数量,每次都会读取一个字节写入一个字节,这样速度很慢,可以读取多个字节写入多个字节
        byte[] size = new byte[1024 * 50]; // 值越大,速度越快
        // while((bts = fis.read()) != -1) {
    
    
        while((bts = fis.read(size)) != -1) {
    
     // 优化读取多个字节
            // 将内存中的流输出到新的文件中:
            // fos.write(bts);
            fos.write(size,0,bts); // 优化写入多个字节
        };
        //释放资源:
        fos.close();
        fis.close();
    };
}

Character stream: When byte stream reads Chinese, there may be a problem of incomplete display of garbled characters, because Chinese occupies multiple bytes of storage. To solve this problem, java provides a character stream class, which reads and writes data in units of characters. Reader class for processing text files. This class is the top-level class of character input streams. This class is also an abstract class. Its subclasses include: BufferedReader cache stream, CharArrayReader character array stream, FilterReader filter stream, InputStreamReader conversion stream, PipedReader pipeline Stream, StringReader read string stream

If a Chinese is GBK encoded, it will occupy 2 bytes, if it is utf-8 encoded, it will occupy 3 bytes.

Character input stream: read the data in the hard disk file into the memory as characters

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class TestReader {
    
    
    // 1.Reader字符输入流:是字符输入流的最顶层父类,定义了一些共性的成员方法,是一个抽象类
    // 2.共性方法:read()读取单个字符并返回、read(char[] cbuf)一次读取多个字符,将字符读取到数组
    // 3.close()关闭该流并释放与之关联的所有资源

    // 4.fileReader继承于InputStreamReader,InputStreamReader又继承于Reader,fileReader文件字符输入流,把硬盘文件中数据以字符的方式读取到内存中
    // 5.构造参数:FileReader()里面可以传入一个文件路径或一个文件实例
    // 6.fileReader构造方法的作用:1.创建一个FileReader对象 2.把FileReader对象指向要读取的文件
    // 7.字符输入流的使用步骤:1.创建FileReader对象,构造方法中绑定要读取的数据源 2.使用FileReader对象中的read方法读取文件 3.释放资源
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建FileReader对象:
        FileReader fs = new FileReader("D:\\00.java高级\\练习\\javaDemo\\077.Reader字符流\\test.txt");
        // 2.使用reader读取字符:

        // 读取单个字符
        //int ln = 0; // 读取字符的长度
        //while((ln = fs.read()) != -1){
    
    
        //    System.out.println(ln);
        //};

        // 读取多个字符:
        int ln2 = 0;
        char[] ls = new char[1024 * 50];
        while((ln2 = fs.read(ls)) != -1){
    
    
            System.out.println(new String(ls,0,ln2));
        };
        // 3.释放资源:
        fs.close();
    };
}

Character output stream: The writer class is a subclass of the io class. It is the top-level parent class of all character output streams. It is an abstract class. Its subclasses are: BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter

import java.io.FileWriter;
import java.io.IOException;

public class TestFileWriter {
    
    
    // 1.FileWriter: 把内存中的字符数据写入到文件中
    // 2.构造方法FileWriter其中可以传递一个文件路径或者文件实例,其作用:1.创建一个FileWriter对象 2.根据构造方法中的文件或文件路径创建文件 3.把FileWriter对象指向创建好的文件
    // 3.使用步骤:1.创建FileWriter对象,构造方法中绑定要写入数据的目的地 2.使用write方法将数据写入到内冲缓存区中(字符转字节的过程)3.使用flush将内存缓存区中的数据刷新到文件中 4.释放资源(会把内存缓存区中的数据刷新到文件中)
     public static void main(String[] args) throws IOException {
    
    
         // 1.创建FileWriter对象:
         FileWriter fw = new FileWriter("D:\\00.java高级\\练习\\javaDemo\\078.Writer字符输出流\\hello.txt", false); // 第二个参数表示是否开启续写,开启后每次执行文件都会进行追加写入,否则会创建新文件覆盖原文件
         // 2.使用FileWriter中的write把数据写入到内存缓冲区(字符转换为字节流的过程)
         fw.write(97); // 此时并没有将数据直接写入到文件中,而是写入内存缓冲区

         // write可直接传递一个字符数组进行写入:
         char[] list = {
    
    'a','b','c'};
         fw.write(list);

         // write可直接写入字符串或字符串一部分:
         fw.write("hello123");
         fw.write("今天又是摸鱼的一天", 2, 3);

         // 换行写:win:\r\n linux:/n mac:/r
         fw.write("\r\n");

         // write可以指定字符数组某一个部分写入:
         fw.write(list,1,2);
         // 3.使用FileWriter中的flush方法,把内存缓冲区中的数据刷新到文件中
         fw.flush(); // 如果调用了close方法,会自动刷新数据到文件中
         fw.close();
     };
     // 4.flush方法和close方法的区别:flush刷新缓冲区,流对象可以继续使用;close先刷新缓冲区,然后通知系统释放资源,流对象不可以再使用了
}

Attribute set Properties:

You can create a collection of key-value pairs, and with a stream, you can store data to a file or read data from a file into the collection.

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class PropertiesTest {
    
    
    // 1.Properties继承于Hashtable,该类表示了一个持久的属性集,该属性可保存在流中或从流中加载,Properties是一个唯一和io流相结合的集合
    // 2.可以使用Properties集合中的方法store,把集合中的临时数据持久化的写入到硬盘中,可以使用load方法将文件中(键值对),读取到集合中
    // 3.属性列表中每个键及其对应值都是一个字符串,Properties集合是一个双链集合,key和value默认都是字符串
    // 4.Properties集合有两个常用方法:setProperty(String key, String value)类似调用Hashtable的put进行存储值、通过getProperty(String key)通过key找到value,类似Map中的get方法;还有一个遍历属性key的方法stringPropertyNames,它返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法

    public static void main(String[] args) throws IOException {
    
    
        // 1.创建一个Properties集合:
        Properties ps = new Properties();
        // 2.往集合中添加属性及值:
        ps.setProperty("name", "小迪");
        ps.setProperty("age", "18");
        // ps.put(12,12); // 支持put方法,但是不推荐
        // 3.遍历集合:
        Set<String> set = ps.stringPropertyNames();
        for (String key: set) {
    
    
            // 拿到key
            System.out.println(key);
            // 拿到值:
            System.out.println(ps.getProperty(key));
        };
        // 4.store方法将数据写入到硬盘中,传递的如果是字节流,那么就不能写入中文,如果传递的是字符流,才可以写中文进去,store还可以传入注释(注释不能使用中文,不然会乱码),用来说明保存文件是做什么用的
        // 创建字节或字符输出流对象:
        FileWriter fw = new FileWriter("D:\\00.java高级\\练习\\javaDemo\\079.PropertiesTest\\test.txt");
        // 将Properties集合中的数据存储到文件中:
        ps.store(fw,"save data test"); // store可以把数据持久化到硬盘中,第一个参数为流对象,参数二为说明; 数据以key=value的形式保存在了文件中
        // 释放资源:
        fw.close();

        // 6.load方法可以将文件中的键值对读取到集合中:参数如果传递了字节输入流,那么就不能读取中文键值对;如果传递了字符输入流,就可以读取中文:
        // 使用步骤:1.创建Properties集合对象 2.调用集合对象的方法load将文件中的值读取到集合中 3.遍历集合对象查看值
        // 注意事项:存储数据的文件中键与值之间可以使用=或其它符合连接、存储键值对的文件中可以#开头为注释,注释不会被读取到集合中、键和值默认就是字符串形式,无需再加引号:
        Properties ps2 = new Properties();
        ps2.load(new FileReader("D:\\00.java高级\\练习\\javaDemo\\079.PropertiesTest\\test.txt"));
        Set<String> lskey = ps2.stringPropertyNames();
        for (String key: lskey) {
    
    
            System.out.println(key + "---" + ps.getProperty(key));
        };
    };

}

buffered stream:

Buffered streams can convert encodings, serialized streams that can store objects persistently, etc. Buffered streams are all created on top of basic streams, and are processed at one time after storing multiple basic streams in an array. Buffer streams are also called high-efficiency streams, which are enhancements to the four basic FileXXX streams, which are:

Byte buffer stream : BufferedInputStream, BufferedOutputStream

Character buffer stream: BufferedReader, BufferedWriter

The previous basic streams are very slow when reading and writing, and buffered streams are much faster than basic streams.

Byte-buffered output streams and byte-buffered input streams:

import java.io.*;

public class BufferedOutInputStreamTest {
    
    
    // 字节缓冲输出流部分:
    // 1.BufferedOutputStream基础于OutputStream,构造方法:BufferedOutputStream(),里面可以传递OutputStream来创建一个缓冲流输出流,以将数据写入到指定的底层输出流;另一种方式是在第一个基础上面在传递第二个参数指定缓冲区大小
    // 2.使用步骤:1.创建FileOutputStream对象,构造方法中指定要输出的目的地 2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率 3.使用BufferedOutputStream对象中的write将数据写入到指定的缓冲区中 4.使用flush把内部缓冲区中的数据刷新到文件中 5.close释放资源
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建基本的输出流,构造方法中指定要输出的目的地:
        FileOutputStream fi = new FileOutputStream("D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test.txt");
        // 2.创建一个缓冲流对象:里面传递基本输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(fi);
        // 3.调用缓冲流对象的write写数据:write中传递字节数组
        bos.write("一些数据被写入到内部缓冲区中:".getBytes()); // 此时只是创建了文件,但是数据是还没有刷新到文件里面
        // 4.刷新数据到文件中:
        bos.flush();
        // 5.释放资源:
        bos.close();

        // 字节缓冲输入流部分:
        // 1.BufferedInputStream继承于InputStream,构造方法可以传递一个参数输入流,也可以指定第二个参数指定缓冲区大小
        // 2.使用步骤哦:1.使用FileInputStream创建一个基本字节输入流,构造方法中绑定要读取的数据源 2.使用BufferedInputStream创建对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
        // 3.使用BufferedInputStream对象中的read方法读取文件
        // 4.释放资源
        // 1.创建基本输入流:绑定要输入的文件源:
        FileInputStream fis = new FileInputStream("D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test.txt");
        // 2.创建BufferedInputStream对象,构造方法中传递基本流对象:
        BufferedInputStream bis = new BufferedInputStream(fis);
        // 3.使用read方法读取文件:
        int ln = 0;

        //while((ln = bis.read()) != -1){
    
    
        //    System.out.println(ln);
        //};

        // 优化为每次读取一部分字节:
        byte[] list = new byte[1024 * 50];
        while((ln = bis.read(list)) != -1){
    
    
            System.out.println(new String(list,0,ln));
        };
        // 释放资源:
        bis.close();
    };
}

Character-buffered output streams and character-buffered input streams:

import java.io.*;

public class BufferedWriterDemo {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 字符缓冲输出流部分:
        // 1.BufferedWriter继承于Writer类,它为字符缓冲流
        // 2.构造方法:BufferedWriter里面可以传递一个默认大小的输出缓冲字符输出流,也可以接收第二个参数来指定大小输出缓冲区,提高FileWriter的写入效率
        // 3.BufferedWriter特有方法:newLine(),写入一个分隔符,会根据不同的操作系统获取不同的航分割符
        // 4.使用步骤:
        // 1.创建字符缓冲输出流对象,构造方法中传递字符输出流
        // 2.调用字符缓冲输出流的方法write,把数据写入到内存缓冲区中
        // 3.调用字符缓冲输出流中的flush方法将数据刷新到文件中
        // 4.释放资源

        // 1.创建BufferedWriter对象,里面接收一个FileWriter实例
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test2.txt", true));
        // 2.往文件中写入内容:循环写入数据,并测试newLine方法进行换行:
        for (int i = 0; i < 5; i++){
    
    
            bw.write("写入字符串:"+i);
            bw.newLine();
        };
        // 3.刷新数据到文件中:
        bw.flush();
        // 4.释放资源:
        bw.close();

        // 字符缓冲输入流部分:
        // 1.BufferedReader继承于Reader方法
        // 2.构造方法:BufferedReader用于创建一个使用默认大小输入缓冲区的缓冲字符输入流,可以接收第二个参数来指定缓冲区的大小
        // 3.使用步骤: 1.创建字符缓冲输入流对象,构造方法中传递字符输入流 2.使用字符缓冲区输入流对象的read或readLine读取文本 3.释放资源

        // 1.创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test3.txt"));
        // 2.读取文本:
        //int st = br.read(); // read只能读取单个字符的值,使用readLine可以读取每行字符串:
        //System.out.println(st);
        String sl = br.readLine(); // readLine每次只能读取一行内容,如果没有内容过来就会返回null
        System.out.println(sl);
        String newStr;
        while((newStr = br.readLine()) != null){
    
    
            System.out.println(newStr);
        };
        // 3.释放资源:
        br.close();
    };
}

Transform stream:

Character Encoding:

According to a certain rule, storing characters in the computer is called encoding, otherwise, parsing and displaying the binary numbers in the computer according to certain rules is called decoding; character encoding is a set of corresponding rules between natural language characters and binary; Encoding table: Correspondence rules between words and computer binary in daily life

Character set: A character set is also called a code table. It is a collection of all characters supported by a system, including national plus characters, punctuation marks, graphic symbols, numbers, etc.; common character sets include: Ascall character set, GBK character set, Unicode character set .

When the encoding used by a file is inconsistent with the encoding used to read the file, garbled characters will occur when it is read at this time. To solve the problem of garbled characters, you can use the conversion stream.

InputStreamReader and OutputStreamWriter are bridges for converting streams:

OutputStreamWriter is a bridge from character flow to byte stream. You can specify the character encoding to encode the characters to be written into bytes, which is to convert the understandable into unintelligible, which is the process of encoding.

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class OutputStreamWriterDemo {
    
    
    // 1.OutputStreamWriter的构造方法第一个参数是一个文件输出流,也可以传递第二个参数用来指定字符编码,将字符编码后以字节的形式存储在文件
    // 2.使用步骤:1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码表名称 2.调用write方法将字符转换为字节存储到缓冲区中(进行编码)3.调用flush方法,把缓冲区中的字节刷新到文件中 4.释放资源
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建一个OutputStreamWriter对象:
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\00.java高级\\练习\\javaDemo\\081.OutputStreamWriter\\test.txt"),"gbk"); // 第二个参数指定编码格式后将以此编码格式对文件编码存储
        // 2.写数据:
        osw.write("你好123");
        // 3.刷新文件:
        osw.flush();
        // 4.释放资源:
        osw.close();
    };
}

InputStreamReader: After reading the character file, you can specify the encoding format for decoding, and the process of converting unintelligible characters into understandable bytes.

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class InputStreamReaderDemo {
    
    
    // 1.InputStreamReader传递第一个参数为字节输入流,也可以传递第二个参数指定编码集
    // 2.使用步骤:1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码名称(这里编码格式要和文件的一致,否则会乱码) 2.使用InputStreamReader的read方法读取文件 3.释放资源
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建InputStreamReader对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\00.java高级\\练习\\javaDemo\\081.OutputStreamWriter\\test.txt"), "gbk"); // 文件是gbk,读取的时候也要用gbk,否则会乱码
        // 2.读取文件:
        int ln = 0;
        while((ln = isr.read()) != -1){
    
    
            System.out.println((char)ln);
        };
        // 3.释放资源
        isr.close();
    };
}

Serialization and deserialization:

Object serialization stream: store objects as byte streams

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamTest {
    
    
    // 对象序列化:
    // 1.ObjectOutputStream继承于OutputStream,其作用是将对象以流的方式写入到文件中保存
    // 2.构造方法:构造方法接收一个字节输出流
    // 3.特有方法:writeObject(Object obj),将对象写入到ObjectOutputStream,需要特别注意:这里传入的对象需要实现序列化和反序列化接口Serializable,只需要实现做标记,其它不用做,否则会抛异常
    // 4.使用步骤:1.创建ObjectOutputStream对象,构造方法中传递字节输出流 2.使用其方法writeObject方法把对象写入到文件中 3.释放资源
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建ObjectOutputStream对象,构造方法中传递输出流:
        ObjectOutputStream ojos = new ObjectOutputStream(new FileOutputStream("D:\\00.java高级\\练习\\javaDemo\\082.对象序列化\\test.txt"));
        // 2.使用writeObject写入一个对象:
        ojos.writeObject(new Person("韩梅梅", 25)); // 这里是以字节的方式存储的,直接打开查看是乱码的
        // 3.释放资源:
        ojos.close();
    };
}

Object deserialization stream: read out the object stored in the file as a stream.

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectInputStreamTest {
    
    
    // 1.ObjectInputStream继承于InputStream,其作用是对象的反序列化,把文件中储存的对象以流的方式读取出来
    // 2.构造方法:接收一个指定的InputStream字节输入流:
    // 3.使用步骤:1.创建objectInputStream对象,构造方法中传递字节输入流 2.使用其特有方法readObject读取对象文件 3.释放资源 4.使用读取出来的对象打印
    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        // 1.创建ObjectInputStream对象,里面传递文件输入流
        ObjectInputStream ojis = new ObjectInputStream(new FileInputStream("D:\\00.java高级\\练习\\javaDemo\\082.对象序列化\\test.txt"));
        // 2.使用其特有方法readObject读取文件流
        Object ob = ojis.readObject();
        // 3.释放资源:
        ojis.close();
        // 4.查看读取到的对象:
        System.out.println(ob);
        // ob是Object类型,将转Person类型:
        Person p = (Person)ob;
        System.out.println(p.getNames()); // 韩梅梅
    };
}

Tip: Static properties cannot be serialized. Even if serialized, its value is still the default value. The value passed when creating the object will not be assigned successfully. In addition to the static properties modified by static, there is also a keyword : The member variables modified by the transient keyword cannot be serialized. At this time, if you do not want the member variables to be serialized, you can use this keyword, but it has no static meaning.

When serializing and deserializing objects, add in the object file: private static final long serialVersionUID = a value; it can effectively prevent serialization conflicts and errors

print stream

PrintStream is a print stream, its characteristics: only responsible for data output, not responsible for data reading, will never throw IOException

import java.io.FileNotFoundException;
import java.io.PrintStream;

public class PrintStreamDemo {
    
    
    // 1.PrintStream为打印流,继承于OutputStream,为其它输出流添加了功能,使它们能够方便地打印各种数据值表示形式
    // 2.特有方法print和println
    // 3.构造方法:参数可以是指定输出的目的地是一个文件或字节输出流或一个文件路径
    public static void main(String[] args) throws FileNotFoundException {
    
    
        // 1.创建一个打印流对象:
        PrintStream ps = new PrintStream("D:\\00.java高级\\练习\\javaDemo\\083.printStream打印流\\error.txt");
        // 2.写入打印信息:
        ps.write('a');
        ps.write(98);
        ps.println("你好哈"); // println或print打印任意数据类型,且不会自动转换为字节,如打印97并不会显示a;而write是会自动转换为字节的,而且不支持字符串打印

        // 3.System.setOut(打印流对象);可以将以下print的东西打印到输出文件中,特别提醒:setOut方法前面的不会不打印到文件中,而是继续在控制台打印
        System.setOut(ps);
        System.out.println("123sdfs");
        // 4.释放资源:
        ps.close();
    };
}

network programming:

Software structure:

c/s structure: The full name is client/server structure, which refers to the client and server structure. Common programs include: qq, network disk, etc.

b/s structure: The full name is browser/server structure, which refers to the browser and server structure. Common browsers include Google, Firefox, etc., which are accessed through URLs.

Both architectures require a network, and network programming is a program that realizes communication between two computers under a certain protocol.

Network communication protocol: Multiple computers can be connected through a computer network. Computers in the same network need to follow certain rules when connecting and communicating. These rules are called network protocols. The speed, transmission steps, etc. have been uniformly stipulated, and both parties in communication must follow the agreement at the same time to complete the data exchange.

TCP/ip protocol: also known as Transmission Control Protocol/Internet Internet Protocol Transmission Control Protocol/Internet Protocol, is the most basic and widely used protocol on the Internet. It contains a series of protocols for processing data communication, using 4 layers A layered model, each layer calls the protocol provided by its next layer to fulfill its own needs.

Please add a picture description

Protocol classification: The communication protocol is relatively complicated. The classes and interfaces contained in the java.net package provide low-level communication details. We can directly use these classes and interfaces to focus on the development of network programs without considering communication details. The java.net package provides support for two common network protocols:

UDP: User Datagram Protocol, UDP is a connectionless communication protocol, the data sender and receiver do not need to establish a logical connection, simply put: when a computer sends data to another computer, the sender will not After confirming the existence of the receiving end, the data will be sent out. Similarly, when the receiving end receives data, it will not feedback to the sending end whether it has received the data. Its characteristics: low cost, high communication efficiency, commonly used for voice, audio, video and ordinary data Transmission, such as video conferencing, uses the UDP protocol, because in this case, even if one or two packets are occasionally lost, it will not have a great impact on the receiving result. The disadvantage: the data sent at a time cannot exceed 64kb, and it cannot be sent beyond this range.

TCP: Transmission Control Protocol, which is a connection-oriented communication protocol, that is, before transmitting data, a logical connection is established between the sending end and the receiving end, and then the data is transmitted. Its characteristics: data can be transmitted between two computers without error Transmission, to ensure the security of data transmission, has a wide range of applications, such as file downloads, web browsing, etc. Each connection between the client and the server is a connection request sent by the client. The establishment of each connection requires 3 handshakes, and the data exchange is performed after the 3 handshakes:

Please add a picture description

Three elements of network programming:

Protocol: Computer network communication must follow network rules

ip address: refers to the Internet Protocol Address lnternet Protocol Address, commonly known as ip, the unique number of computer equipment; ip can be divided into IPv4 and IPv6, IPv4 is a 32-bit binary number usually divided into 4 bytes, expressed as abcd, Ipv6 is In order to expand the address space, a 128-bit address length is used, and each group of 16 bytes is divided into 8 groups of hexadecimal numbers, expressed as: ABCD: EFe1: 2345: 6789: ABCD: EF01: 2345: 6789, which solves the problem The problem of insufficient network address resources is solved.

View the local network configuration command: terminal input: ipconfig

Port: The port is the computer's number for each program. The port number consists of 2 bytes, and the value range is 0~65535. This number is not bound to a certain program, but can be specified. If the backend starts a certain server, and the specified port number is: 3000, then the frontend can find this service by adding the port 3000 to the ip.

TCP communication program:

TCP communication can realize data interaction between two computers, and the two ends of the communication must be strictly divided into client and server.

Steps in the communication between the two ends: 1. The server program needs to be started first, and waits for the connection of the client. 2. The client actively connects to the server, and the communication is only possible after the connection is successful. The server cannot actively connect to the client.

Two classes are provided in java for implementing TCP communication programs:

1. Client: The java.net.Socket class user creates a client Socket object, sends a connection request to the server, the server responds to the request, and the two establish a connection to start communication.

2. Server: The java.net.ServerSocket class is used to create a server object, which is equivalent to opening a service and waiting for the connection from the client.

Server side code:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer  {
    
    
    // TCP通信服务端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据需要使用ServerSocket类,此类实现服务器套接字
    // 1.构造方法:ServerSocket(int port),此类创建特定端口的服务器套接字
    // 2.服务器必需明确是哪个客户端请求的服务器,所以可以使用accept方法获取到请求的客户端对象Socket
    // 3.使用步骤:1.创建服务器ServerSocket对象和系统要指定的端口号 2.使用ServerSocket对象的accept方法获取客户端Socket对象 3.使用Socket对象中的方法getInputStream获取InputStream对象 4.使用网络字节输入流InputStream对象的read方法,读取客户端发送的数据 5.使用Socket对象中的方法getOutputStream获取网络字节输出流OutputStream对象 6.使用网络字节输出流OutputStream对象中的write方法给客户端写数据 7.释放资源(Socket,ServerSocket)
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建服务器端ServerSocket对象,并指定端口:
        ServerSocket servers = new ServerSocket(3000);
        // 2.获取请求服务器端的客户端Socket对象:
        Socket client = servers.accept();
        // 3.使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象:
        InputStream iso = client.getInputStream();
        // 4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据:
        byte[] bts = new byte[1024];
        int ln = iso.read(bts);
        String msg = new String(bts,0,ln);
        System.out.println("服务器接收到数据:" + msg);
        // 5.使用Socket对象中的getOutputStream方法获取网络字节输出流OutputStream对象
        OutputStream ois = client.getOutputStream();
        // 6.服务器回复客户端:
        ois.write("你好,客户端,我是服务器A".getBytes());
        // 7.释放流:
        client.close();
        servers.close();
    };
}

Client code:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TcpClient {
    
    
    // TCP客户端实现:客户端实现使用Socket类,此类实现客户端套接字(套接字是两台机器间通信的端点,套接字包含了ip和端口的网络单位)
    // 1.构造方法:Socket(String host, int port),参数一 为服务器的ip或主机名,参数二为端口号
    // 2.成员方法:1.OutputStream getOutputStream()返回此套接字的输出流 2.InputStream getInputStream()返回此套接字的输入流 3.close()关闭此套接字
    // 3.实现步骤:1.创建一个客户端实例对象Socket,构造方法中传递ip和端口 2.使用Socket对象中的getOutputStream()方法获取网络字节输出流OutputStream对象 3.使用网络字节输出流OutputStream对象中的write方法给服务器发送数据 4.使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象 5.使用网络字节输入流InputStream对象中的read方法读取服务器回显的数据 6.释放资源(Socket)
    // 4.提示:1.客户端和服务端进行交互时,必须使用Socket提供的网络流,不能使用自己创建的流对象 2.当我们创建客户端Socket对象时,此时就会去请求服务端和服务器经过3次握手建立连接,这时服务器如果没有启动就会抛出异常,如果服务器启动,那么就可以正常进行交互。
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建Socket客户端对象:里面传递ip和端口号:
        Socket client = new Socket("127.0.0.1", 3000);
        // 2.使用Socket实例对象的getOutputStream得到一个字节输出流:
        OutputStream ots = client.getOutputStream();
        // 3.调用输出流的write方法向服务器写数据:
        ots.write("你好服务器,我是客户端001".getBytes());
        // 4.使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象:
        InputStream iso = client.getInputStream();
        // 5.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据:
        byte[] bts = new byte[1024];
        int ln = iso.read(bts);
        String msg = new String(bts,0,ln);
        System.out.println("客户端接收到数据:" + msg);
        // 6.释放资源:
        client.close();
    };
}

File upload case (picture):

Server code:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class TcpServer {
    
    
    // 服务端实现步骤:
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建服务器ServerSocket对象,指定端口和ip:
        ServerSocket server = new ServerSocket(3000);
        // 优化:循环一直监听是否有客户端访问,有访问就执行,起监听作用:
        while(true){
    
    
            // 2.使用ServerSocket中的accept方法获取客户端Socket对象:
            Socket client = server.accept();

            // 优化:当有多个客户端上传文件时,使用多线程:
            new Thread(new Runnable(){
    
    
                @Override
                public void run() {
    
    
                    try {
    
    
                        // 3.使用Socket中的getInputStream获取网络字节输入流InputStream对象
                        InputStream inStream = client.getInputStream();
                        // 4.判断服务器中是否有需要存储文件的文件夹,如果没有需要创建文件夹:
                        File files = new File("D:\\00.java高级\\练习\\javaDemo\\085.tcp实现文件上传\\uploads");
                        if (!files.exists()) {
    
    
                            files.mkdir();
                        }
                        // 5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要存储文件的目的地:
                        String strTemp = "\\files" + System.currentTimeMillis() + new Random(999999999).nextInt() + ".png";
                        FileOutputStream outStream = new FileOutputStream(files  + strTemp);
                        // 6.使用网络字节输入流InputStream对象中的read读取客户端上传的文件:
                        int len = 0;
                        byte[] bytes = new byte[1024 * 1];
                        while((len = inStream.read(bytes)) != -1){
    
    
                            // 7.使用本地字节输出流FileOutputStream对象中的write将文件写入到服务器硬盘中:
                            outStream.write(bytes,0,len);
                        };
                        // 8.使用Socket对象中的getOutputStream获取到网络字节输出流OutputStream对象
                        OutputStream outStreamToClient = client.getOutputStream();
                        // 9.使用Socket获取的OutputStream对象回写数据给客户端:
                        outStreamToClient.write("文件上传成功!".getBytes());
                        // 10.释放资源
                        outStream.close();
                        client.close();
                    } catch (IOException e) {
    
    
                        System.out.println("异常:" + e);
                    }
                }
            }).start();
        }
        // 服务器一直处于监听客户端进来,这里也没必要关闭:
//        server.close();
    };
}

Client code:

import java.io.*;
import java.net.Socket;

public class TcpClient {
    
    
    // 客户端实现步骤:
    // 1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源:
    // 2.创建一个客户端Socket对象,构造方法中绑定服务器ip地址和端口号
    // 3.使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
    // 4.使用本地字节输入流FileInputStream对象中的read,读取本地文件
    // 5.使用网络字节输出流OutputStream对象中的write,把读取到的文件上传到服务器
    // 6.使用Socket中的方法getInputStream获取网络字节输入流InputStream对象
    // 7.使用网络字节输入流中InputStream对象的read读取服务器回写的数据
    // 8.释放资源(FileInputStream,Socket)
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源:
        FileInputStream pickFile = new FileInputStream("D:\\00.java高级\\练习\\javaDemo\\085.tcp实现文件上传\\test.png");
        // 2.创建一个客户端Socket对象,构造方法中绑定服务器ip地址和端口号
        Socket client = new Socket("127.0.0.1",3000);
        // 3.使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
        OutputStream outStream = client.getOutputStream();
        // 4.使用本地字节输入流FileInputStream对象中的read,读取本地文件
        int len = 0;
        byte[] bytes = new byte[1024 * 1];
        while((len = pickFile.read(bytes)) != -1){
    
    
            // 5.使用网络字节输出流OutputStream对象中的write,把读取到的文件上传到服务器
            outStream.write(bytes, 0, len);
        };
        // 为防止服务器和客户端相互等待进入卡死状态,这里文件上传完后客户端终止继续写入数据
        client.shutdownOutput();
        // 6.使用Socket中的方法getInputStream获取网络字节输入流InputStream对象
        InputStream inStream = client.getInputStream();
        while((len = inStream.read(bytes)) != -1){
    
    
            // 7.使用网络字节输入流中InputStream对象的read读取服务器回写的数据,然后打印:
            System.out.println(new String(bytes,0,len));
        };
        // 8.释放资源(FileInputStream,Socket)
        pickFile.close();
        client.close();
    };
}

B/S service case:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class WebServer {
    
    
    public static void main(String[] args) throws IOException {
    
    
        // 1.创建一个SocketServer对象,并指定一个端口:
        ServerSocket server = new ServerSocket(3000);
        while(true){
    
    
            new Thread(new Runnable(){
    
    
                @Override
                public void run(){
    
    
                    // 2.使用SocketServer对象的accept方法获取客户端请求对象:
                    try {
    
    
                        Socket client = server.accept();
                        // 3.使用Socket中的getInputStream方法获取Socket对象中的InputStream对象:
                        InputStream inStream = client.getInputStream();
                        // 3.使用InputStream对象中的read方法读取客户端请求信息:
                        //byte[] bytes = new byte[1024];
                        //int len = 0;
                        //while((len = inStream.read(bytes)) != -1){
    
    
                        //    System.out.println(new String(bytes,0,len));
                        //    // 浏览器输入localhost:3000后这里打印信息:
                        //    // GET / HTTP/1.1             // 注意: 这里实际是可以拿到访问路径的,如果在浏览器输入:http://localhost:3000/webhtml/index.html,可以看到打印信息:GET /webhtml/index.html HTTP/1.1, 不难看出GET后第一个斜杠开始到空格即是访问路径
                        //    // Host: localhost:3000
                        //    // Connection: keep-alive
                        //    // sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
                        //    // 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/107.0.0.0 Safari/537.36
                        //    // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
                        //    // Sec-Fetch-Site: none
                        //    // Sec-Fetch-Mode: navigate
                        //    // Sec-Fetch-User: ?1
                        //    // Sec-Fetch-Dest: document
                        //    // Accept-Encoding: gzip, deflate, br
                        //    // Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
                        //};

                        // 优化改造:从请求打印可以看出,我们只有第一行内容暂时对于我们有效,我们可以只读第一行内容,因此上面部分注释,看下面:
                        // 将InputStream字节输入流转换为字符缓冲输入流:
                        BufferedReader binStream = new BufferedReader(new InputStreamReader(inStream));
                        // 使用readLine读取一行:
                        String url = binStream.readLine();
                        System.out.println(url); // GET /webhtml/index.html HTTP/1.1 ,可以看到第一行请求路径已经拿到了,此时我们继续处理拿到对我们有用的部分:/webhtml/index.html
                        String[] urlList = url.split(" "); // 使用split以空格进行切割,得到一个字符串数组,拿到索引为1的字符串:
                        System.out.println(urlList[1]); // /webhtml/index.html , 去掉字符串前面的第一个斜杠:
                        String webUrl = urlList[1].substring(1); // 使用substring从1位置开始截取字符串:
                        System.out.println(webUrl); // webhtml/index.html
                        // 4.创建本地字节输入流,构造方法中绑定html文件路径:
                        FileInputStream finStrem = new FileInputStream(webUrl);
                        // 5.使用Socket对象中的getOutputStream方法获取OutputStream网络字节输出流:
                        OutputStream outStream = client.getOutputStream();
                        // 6.使用OutputStream中的write方法写数据给客户端:
                        // 写入固定给浏览器识别的信息:
                        outStream.write("HTTP/1.1 200 0K\r\n".getBytes());
                        outStream.write("Content-Type:text/html\r\n".getBytes());
                        outStream.write("\r\n".getBytes());
                        // 读取html文件并回写给客户端,因为这里文件可能太大,一般都是循环读完为止:
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while((len = finStrem.read(bytes)) != -1){
    
    
                            outStream.write(bytes,0,len);
                        };
                        // 7.释放资源:
                        finStrem.close();
                        client.close();
                    } catch (IOException e) {
    
    
                        throw new RuntimeException(e);
                    }
                };
            }).start();
            // server.close(); // 一直监听,所以不用关闭
        }
        // 提示: 这里考虑到多个客户访问及web项目中自发请求的问题,这里做了循环监听及多线程处理:只需要将Socke获取客服端部分及读取文件以及回写放到多线程中,并以循环的方式不断监听即可
    };
}

Tips: The pictures and other materials in this article come from the Internet. If there is any infringement, please send an email to the mailbox: [email protected] to contact the author to delete it.
Author: sea of ​​bitterness

おすすめ

転載: blog.csdn.net/weixin_46758988/article/details/132125233