泛型、IO流 和 网络编程

文章目录

😹 作者: gh-xiaohe
😻 gh-xiaohe的博客
😽 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!

在这里插入图片描述

🚏 泛型

    泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换

🚀 泛型的概念

    所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。

🚬 为什么要使用泛型

问题一:类型不安全

问题二:强转时,可能出现ClassCastException

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sdj08qTw-1664007082542)(泛型和IO流.assets/image-20220924153614007.png)]

🚄 在集合中使用泛型

  • 总结:
  • ① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
  • ② 在实例化集合类时,可以指明具体的泛型类型
  • ③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
    • 比如:add(E e) —>实例化以后:add(Integer e)
  • ④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要使用到基本数据类型的位置,拿包装类替换
  • ⑤ 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型

未使用泛型

	//在集合中使用泛型之前的情况:
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        //需求:存放学生的成绩
        list.add(78);
        list.add(76);
        list.add(89);
        list.add(88);
        //问题一:类型不安全
//        list.add("Tom");

        for(Object score : list){
            //问题二:强转时,可能出现ClassCastException
            int stuScore = (Integer) score;
//            int stuScore = (int) score;也可这样

            System.out.println(stuScore);
        }
    }

在集合中使用泛型的情况:以ArrayList为例

    //在集合中使用泛型的情况:以ArrayList为例
    @Test
    public void test2(){
    	//问什么不能写int:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
       ArrayList<Integer> list =  new ArrayList<Integer>();

        list.add(78);
        list.add(87);
        list.add(99);
        list.add(65);
        //编译时,就会进行类型检查,保证数据的安全
//        list.add("Tom");

        //方式一:
//        for(Integer score : list){
//            //避免了强转操作
//            int stuScore = score;
//
//            System.out.println(stuScore);
//
//        }
        //方式二:
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            int stuScore = iterator.next();
            System.out.println(stuScore);
        }

    }

在集合中使用泛型的情况:以HashMap为例

@Test
    public void test3(){
//        Map<String,Integer> map = new HashMap<String,Integer>();
        //jdk7新特性:类型推断
        Map<String,Integer> map = new HashMap<>();

        map.put("Tom",87);
        map.put("Jerry",87);
        map.put("Jack",67);

//        map.put(123,"ABC");
        //泛型的嵌套
        Set<Map.Entry<String,Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();

        while(iterator.hasNext()){
            Map.Entry<String, Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + "----" + value);
        
        }

    }

🚒 自定义泛型结构

如何自定义泛型结构:泛型类、泛型接口;泛型方法。

在这里插入图片描述

🚬 泛型类

在这里插入图片描述

public class Order<T> {

    String orderName;
    int orderId;

    //类的内部结构就可以使用类的泛型
    T orderT;

    public Order(){
        
    }

    public Order(String orderName,int orderId,T orderT){
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }
    
    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }
}
@Test
public void test1(){
    //如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
    //要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
    Order order = new _Order();
    order.setOrderT(123);
    order.setOrderT("ABC");

    //建议:实例化时指明类的泛型
    Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");

    order1.setOrderT("AA:hello");

}
🚭 自定义泛型的子类1

    由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。

SubOrder1:不是泛型类

public class SubOrder1 extends Order<Integer> { // SubOrder1:不是泛型类

}

    @Test 
    public void test2(){
        SubOrder1 sub1 = new SubOrder1();
        //由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
        sub1.setOrderT(1122);

        SubOrder2<String> sub2 = new SubOrder2<>();
        sub2.setOrderT("order2...");
    }
🚭 自定义泛型的子类2

SubOrder2: 仍然是泛型类

public class SubOrder2<T> extends Order<T> { // SubOrder2<T>:仍然是泛型类

}

	@Test
    public void test2(){
        SubOrder2<String> sub2 = new SubOrder2<>();
        sub2.setOrderT("order2...");
    }

🚬 泛型接口

//1.接口中静态成员也不能使用泛型
//2.泛型接口的类型,在继承接口或者实现接口时确定
interface IUsb<U,R>{
    int n = 10;
    //U name;       //name类型默认为 public static final,所以不能使用

    //普通方法中可以使用接口泛型
    R get(U u);

    void hi(R r);
    void run(R r1,R r2,U u1,U u2);

    //在JDK 8中,可以在接口中,使用默认方法
    default R method(U u){
        return null;
    }
}


//实现接口时,指定泛型类型
class BB implements IUsb<Integer,Float>{

    @Override
    public Float get(Integer integer) {
        return null;
    }

    @Override
    public void hi(Float aFloat) {

    }

    @Override
    public void run(Float r1, Float r2, Integer u1, Integer u2) {

    }
}

//继承接口时,指定泛型类型
interface IA extends IUsb<String,Double>{

}

class AA implements IA{
    @Override
    public Double get(String s) {
        return null;
    }

    @Override
    public void hi(Double aDouble) {

    }

    @Override
    public void run(Double r1, Double r2, String u1, String u2) {

    }
}

🚬 泛型方法

    方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。 在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型

泛型方法的格式:

  • [ 访问权限] < 泛型> 型 返回类型 名 方法名([ 泛型标识 称 参数名称]) 抛出的异常
  • 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定

错误写法:

  • public static List copyFromArrayToList(E[] arr){ 编译器会认为有一个类叫E,而不是泛型
public class Order<T> {

// public static List<E> copyFromArrayToList(E[] arr){
// 错误写法:编译器会认为有一个类叫E,而不是泛型
    public static <E>  List<E> copyFromArrayToList(E[] arr){

        ArrayList<E> list = new ArrayList<>();

        for(E e : arr){
            list.add(e);
        }
        return list;

    }

}


    //测试泛型方法
    @Test
    public void test4(){
        Order<String> order = new Order<>();
        Integer[] arr = new Integer[]{1,2,3,4};
        //泛型方法在调用时,指明泛型参数的类型。
        List<Integer> list = order.copyFromArrayToList(arr);

        System.out.println(list);
    }

🚬 实际开发中使用泛型DAO

DAO:data(base) access object DAO:可以理解为操作数据库的通用操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iZUmIqla-1664024257092)(泛型和IO流.assets/image-20220924170511373.png)]

DAO

public class DAO<T> {//表的共性操作的DAO

    //添加一条记录
    public void add(T t){

    }

    //删除一条记录
    public boolean remove(int index){

        return false;
    }

    //修改一条记录
    public void update(int index,T t){

    }

    //查询一条记录
    public T getIndex(int index){

        return null;
    }

    //查询多条记录
    public List<T> getForList(int index){

        return null;
    }

    //泛型方法
    //举例:获取表中一共有多少条记录?获取最大的员工入职时间?
    public <E> E getValue(){

        return null;
    }

}

Customer 和 CustomerDAO 测试

public class Customer { //此类对应数据库中的customers表


}

public class CustomerDAO extends DAO<Customer>{//只能操作某一个表的DAO

}

public class Student {
}

public class StudentDAO extends DAO<Student> {//只能操作某一个表的DAO
}


    @Test
    public void test1(){
        CustomerDAO dao1 = new CustomerDAO();

        dao1.add(new Customer());
        List<Customer> list = dao1.getForList(10);//查询多条记录


        StudentDAO dao2 = new StudentDAO();
        Student student = dao2.getIndex(1);//查询一条记录
    }

🚤 泛型在继承上的体现

虽然类A是类B的父类,但是G 和G二者不具备子父类关系,二者是并列关系。

   @Test
   public void test1(){

       // 类层面的展示
       Object obj = null;
       String str = null;

       obj = str; // 子类赋给父类的引用 多态

       // 数组层面
       Object[] arr1 = null;
       String[] arr2 = null;

       arr1 = arr2;        

   }

   @Test
   public void test1(){

       //此时的list1和list2的类型不具有子父类关系
       List<Object> list1 = null;
       List<String> list2 = null;
       
       //编译不通过 
       list1 = list2;  // 错误
       
       // 类似于   错误
       Date date = new Date();
       String str = null;
       
		str = date; // 错误
       /*
       反证法:
       假设list1 = list2;
       list1.add(123);导致混入非String的数据。出错。 所以是错误的
        */

   }

补充:类A是类B的父类,A 是 B 的父类

   @Test
   public void test2(){

       AbstractList<String> list1 = null;
       List<String> list2 = null; //  List interface(接口)
       ArrayList<String> list3 = null; // 继承 AbstractList

       list1 = list3;
       list2 = list3;

       List<String> list4 = new ArrayList<>();

   }

🚗 通配符的使用

通配符:?

  • 类A是类B的父类,G和G是没有关系的,二者共同的父类是:G<?>
    @Test
    public void test3(){
        List<Object> list1 = null;
        List<String> list2 = null;

        List<?> list = null; // 相当于  List<?> 作为 List<Object>、List<String> 的通用父类

        list = list1;
        list = list2;
        //编译通过
        print(list1);
        print(list2);
    }

    public void print(List<?> list){
        Iterator<?> iterator = list.iterator();
        while(iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }

使用通配符结构时

  • 添加(写入):对于List<?>就不能向其内部添加数据,只能添加null(无意义)

  • 获取(读取):允许读取数据,读取的数据类型为Object。

    @Test
    public void test3(){
        
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");
        
        List<?> list = null; 

        list = list3;
        //添加(写入):对于List<?>就不能向其内部添加数据。
		//list.add(capture of ? e);
//        list.add("DD"); 错误
//        list.add('?'); 错误
        //除了添加null之外。
        list.add(null);

        //获取(读取):允许读取数据,读取的数据类型为Object。
        Object o = list.get(0);
        System.out.println(o); // AA

    }

🚬 有限制条件的通配符的使用

  • ? extends A: 理解为小于等于
    • G<? extends A> 可以作为G和G的父类,其中B是A的子类
  • ? super A: 理解为大于等于
    • G<? super A> 可以作为G和G的父类,其中B是A的父类
    @Test
    public void test4(){

        List<? extends Person> list1 = null;
        List<? super Person> list2 = null;

        List<Student> list3 = new ArrayList<Student>();
        List<Person> list4 = new ArrayList<Person>();
        List<Object> list5 = new ArrayList<Object>();

        list1 = list3;
        list1 = list4;
//        list1 = list5;

//        list2 = list3;
        list2 = list4;
        list2 = list5;

        System.out.println("---------------------");
        
        //读取数据:
        list1 = list3;
        Person p = list1.get(0);
        //编译不通过
        //Student s = list1.get(0);

        list2 = list4;
        Object obj = list2.get(0);
        编译不通过
//        Person obj = list2.get(0);

        //写入数据:
        //编译不通过
//        list1.add(new Student()); 子类可以赋给父类 父类不可以赋给子类
//        list1.add(new Person());
//        list1.add(new Object());

        //编译通过
        list2.add(new Person()); //  Person 和 Person的子类能存放 多态
        list2.add(new Student());

}

🚏 IO流

🚀 File类的使用

🚬 File 类的使用

  • java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关
  • File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
  • 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。
  • File对象可以作为参数传递给流的构造器
  • 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"

🚬 如何创建File类的实例

  • 调用:构造器
    • File(String filePath)以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
      • 绝对路径:是一个固定的路径,从盘符开始
      • 相对路径:是相对于某个位置开始
    • File(String parentPath,String childPath)以parent为父路径,child为子路径创建File对象.
    • File(File parentFile,String childPath)根据一个父File对象和子文件路径创建File对象
    • File(URI uri)通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。

内存层面的对象,不需要硬盘中有这个文件

@Test
public void test1() {

    // 内存层面的对象,不需要硬盘中有这个文件
    //构造器1
    File file1 = new File("hello1.txt");//相对于当前module
    File file2 = new File("G:\\java存储文件\\_2java高级编程\\hello1.txt");

    System.out.println(file1);
    System.out.println(file2);

    //构造器2: 上一层目录 文件(或者文件目录)
    File file3 = new File("G:\\java\\java存储文件", "_2java高级编程");
    System.out.println(file3);

    //构造器3:
    File file4 = new File(file3, "hi.txt");
    System.out.println(file4);

}

🚬 路径分隔符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzYIuJeO-1664111911601)(泛型和IO流.assets/image-20220925104613079.png)]

🚬 File类的常用方法

🚭 File 类的获取功能
  • File 类的获取功能
    • 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数组
    @Test
    public void test2() {
        System.out.println();
        File file1 = new File("hello1.txt");//相对路径
        File file2 = new File("G:\\java存储文件\\_2java高级编程\\hi.txt");//绝对路径

        System.out.println(file1.getAbsolutePath());
        System.out.println(file1.getPath());
        System.out.println(file1.getName());
        System.out.println(file1.getParent());
        System.out.println(file1.length());
        System.out.println(new Date(file1.lastModified()));

        System.out.println();

        System.out.println(file2.getAbsolutePath());
        System.out.println(file2.getPath());
        System.out.println(file2.getName());
        System.out.println(file2.getParent());
        System.out.println(file2.length());
        System.out.println(file2.lastModified());
    }

    @Test
    public void test3() {
        File file = new File("G:\\java存储文件\\_2java高级编程\\_6IO流与网略编程"); //路径真实存在

        String[] list = file.list();
        for (String s : list) {
            System.out.println(s); // 目录下的所有文件名称
        }

        System.out.println();

        File[] files = file.listFiles();
        for (File f : files) {
            System.out.println(f); // 目录下的所有文件目录
        }

    }

在这里插入图片描述

🚭 File 类的重命名功能
  • File 类的重命名功能
    • public boolean renameTo(File dest):把文件重命名为指定的文件路径
    • 比如:file1.renameTo(file2)为例:
    • 要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。 如果第一次保存成功了,再点击运行就回是false
    @Test
    public void test4() {
        File file1 = new File("hello1.txt");
        File file2 = new File("E:\\java\\java存储文件\\_2java高级编程\\_6IO流\\_1File类的使用\\hi.txt");

        boolean renameTo = file2.renameTo(file1);
        System.out.println(renameTo);

    }
🚭 File 类的判断功能
  • File 类的判断功能
    • public boolean isDirectory():判断是否是文件目录
    • public boolean isFile():判断是否是文件
    • public boolean exists():判断是否存在
    • public boolean canRead():判断是否可读
    • public boolean canWrite():判断是否可写
    • public boolean isHidden():判断是否隐藏
    @Test
    public void test5() {
        File file1 = new File("hello1.txt"); // 文件存在

        System.out.println(file1.isDirectory());
        System.out.println(file1.isFile());
        System.out.println(file1.exists());
        System.out.println(file1.canRead());
        System.out.println(file1.canWrite());
        System.out.println(file1.isHidden());

        System.out.println();

        File file2 = new File("d:\\io"); // 文件不存在
        System.out.println(file2.isDirectory());
        System.out.println(file2.isFile());
        System.out.println(file2.exists());
        System.out.println(file2.canRead());
        System.out.println(file2.canWrite());
        System.out.println(file2.isHidden());

    }
🚭 File 类的创建功能
  • File 类的创建功能
    • public boolean createNewFile():创建文件。若文件存在,则不创建,返回false
    • public boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。此文件目录的上层目录不存在,也不创建。
    • public boolean mkdirs():创建文件目录。如果上层文件目录不存在,一并创建
  • 注意事项:如果你创建文件或者 文件 目录没有 写 盘符路径,那么,默认在项目路径下。
🚭 File 类的删除功能
  • File 类的删除功能
  • public boolean delete():删除文件或者文件夹
  • 删除注意事项:
    • Java中的删除不走回收站。
    • 要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
    @Test
    public void test6() throws IOException {
        //文件的创建
        File file1 = new File("hi.txt");
        if (!file1.exists()) {
            //文件的创建
            file1.createNewFile();
            System.out.println("创建成功");
        } else {//文件存在
            file1.delete();
            System.out.println("删除成功");
        }
    }

    @Test
    public void test7() {
        //文件目录的创建
        File file1 = new File("d:\\io\\io1\\io3");

        boolean mkdir = file1.mkdir();
        if (mkdir) {
            System.out.println("创建成功1");
        }

        // 文件目录上级 不存在 直接创建
        File file2 = new File("d:\\io\\io1\\io4");

        boolean mkdir1 = file2.mkdirs();
        if (mkdir1) {
            System.out.println("创建成功2");
        }
        //(文件目录的删除)要想删除成功,io4文件目录下不能有子目录或文件
        File file3 = new File("D:\\io\\io1\\io4");
        file3 = new File("D:\\io\\io1");
        System.out.println(file3.delete());
    }
🚭 File 类三个文件过滤器方法
  • File 类文件过滤
    • public String[] list(FilenameFilter filter):返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。
    • public File[] listFiles(FileFilter filter):返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录。
    • public File[] listFiles(FilenameFilter filter):返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录。
      • FilenameFilter 测试指定的文件是否应该包含在文件列表中。
      • 形参 :dir-找到文件的目录。名称–文件的名称。 存在ture

判断指定目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称

    @Test
    public void test1() {
        File srcFile = new File("E:\\java\\io");

        String[] fileNames = srcFile.list();
        for (String fileName : fileNames) {
            if (fileName.endsWith(".jpg")) {
                System.out.println(fileName);
            }
        }
    }

    @Test
    public void test2() {
        File srcFile = new File("E:\\java\\io");

        File[] listFiles = srcFile.listFiles();
        for (File file : listFiles) {
            if (file.getName().endsWith(".jpg")) {
                System.out.println(file.getAbsolutePath());
            }
        }
    }

    /*
     * File类提供了三个文件过滤器方法
     * public String[] list(FilenameFilter filter)
     * public File[] listFiles(FileFilter filter)
     * public File[] listFiles(FilenameFilter filter)
     */
    @Test
    public void test3() {
        File srcFile = new File("E:\\java\\io");

        File[] subFiles = srcFile.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {

                return name.endsWith(".jpg");
            }
        });

        for (File file : subFiles) {
            System.out.println(file.getAbsolutePath());
        }
    }

    @Test
    public void test4(){
        File srcFile1 = new File("E:\\java\\io");
        FilenameFilter name = new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".jpg");
            }
        };
        File[] files = srcFile1.listFiles(name);
        for (File file : files){
            System.out.println(file.getAbsolutePath());
        }

    }

🚬 练习:遍历指定目录所有文件名称,包括子文件目录中的文件。

拓展1:并计算指定目录占用空间的大小

拓展2:删除指定文件目录及其下的所有文件

递归

public class ListFilesTest {

    public static void main(String[] args) {
        // 递归:文件目录
        /** 打印出指定目录所有文件名称,包括子文件目录中的文件 */

        // 1.创建目录对象
        File dir = new File("E:\\java\\io");

        // 2.打印目录的子文件
        printSubFile(dir);
        System.out.println();

        printSubFile(dir);
        System.out.println();

        listSubFiles(dir);
        System.out.println();

        listAllSubFiles(dir);
        System.out.println();
        //拓展1
        System.out.println(getDirectorySize(dir));
        System.out.println();
        //拓展2
//        deleteDirectory(dir);
    }

    public static void printSubFile(File dir) {
        // 打印目录的子文件
        File[] subfiles = dir.listFiles();

        for (File f : subfiles) {
            if (f.isDirectory()) {// 文件目录
                printSubFile(f);
            } else {// 文件
                System.out.println(f.getAbsolutePath());
            }

        }
    }

    // 方式二:循环实现
    // 列出file目录的下级内容,仅列出一级的话
    // 使用File类的String[] list()比较简单
    public static void listSubFiles(File file) {
        if (file.isDirectory()) {
            String[] all = file.list();
            for (String s : all) {
                System.out.println(s);
            }
        } else {
            System.out.println(file + "是文件!");
        }
    }

    // 列出file目录的下级,如果它的下级还是目录,接着列出下级的下级,依次类推
    // 建议使用File类的File[] listFiles()
    public static void listAllSubFiles(File file) {
        if (file.isFile()) {
            System.out.println(file);
        } else {
            File[] all = file.listFiles();
            // 如果all[i]是文件,直接打印
            // 如果all[i]是目录,接着再获取它的下一级
            for (File f : all) {
                listAllSubFiles(f);// 递归调用:自己调用自己就叫递归
            }
        }
    }

    // 拓展1:求指定目录所在空间的大小
    // 求任意一个目录的总大小
    public static long getDirectorySize(File file) {
        // file是文件,那么直接返回file.length()
        // file是目录,把它的下一级的所有大小加起来就是它的总大小
        long size = 0;
        if (file.isFile()) {
            size += file.length();
        } else {
            File[] all = file.listFiles();// 获取file的下一级
            // 累加all[i]的大小
            for (File f : all) {
                size += getDirectorySize(f);// f的大小;
            }
        }
        return size;
    }

    // 拓展2:删除指定的目录
    public static void deleteDirectory(File file) {
        // 如果file是文件,直接delete
        // 如果file是目录,先把它的下一级干掉,然后删除自己
        if (file.isDirectory()) {
            File[] all = file.listFiles();
            // 循环删除的是file的下一级
            for (File f : all) {// f代表file的每一个下级
                deleteDirectory(f);
            }
        }
        // 删除自己
        file.delete();
    }

}

🚄 IO流原理及流的分类

在这里插入图片描述

🚬 Java IO 原理

  • I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。。如读/写文件,网络通讯等.
  • Java程序中,对于数据的输入/输出操作以 “流(stream)” 的方式进行。
  • java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

🚬 流的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpvbAhnQ-1664172329795)(泛型和IO流.assets/image-20220926134301371.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dkOfgaDA-1664172329796)(泛型和IO流.assets/image-20220926134736171.png)]

🚬 IO流体系

在这里插入图片描述

🚬 节点流(或文件流) 标准的规范,掌握

🚭 字符流
🪂 读取操作FileReader

在这里插入图片描述

说明点:读数据

  • 1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
  • 2. 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
  • 3. 读入的文件一定要存在,否则就会报FileNotFoundException(系统找不到指定的文件)。
public class FileReaderWriterTest {

    public static void main(String[] args) {
        File file = new File("hello1.txt");// 相较于当前工程
        System.out.println(file.getAbsolutePath()); // G:\java存储文件\_2java高级编程\hello1.txt
		
        // 此时又想表示 在当然Module 下的hello.txt文件
        File file1 = new File("_6IO流\\hello.txt");
        System.out.println(file1.getAbsolutePath()); // G:\java存储文件\_2java高级编程\_6IO流\hello.txt
    }
    
    @Test
    public void testFileReader() throws Exception {
            // 1、File类的实例化,指明操作的文件
            File file = new File("hello1.txt"); // 相较于当前Module
            // 2、提供具体的流
            FileReader fr = new FileReader(file); // 字符流 -> 输入

            // 3、数据的读取
            // read(): 返回读入的一个。如果达到文件末尾,返回-1
            int data = fr.read(); // 读取方法
            while (data != -1) {
                System.out.print((char) data);//要是a就是97所以char (读取了一个)
                data = fr.read();
            }
            // 4、流的手动关闭操作
            fr.close();
        }

}

Read() 重载方法的优化

  • read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1 提高了效率
    @Test
    public void testFileReader() throws Exception {
        // 1、File类的实例化,指明操作的文件
        File file = new File("hello1.txt"); // 相较于当前Module
        // 2、提供具体的流
        FileReader fr = new FileReader(file); // 字符流 -> 输入

        // 3、数据的读取
        char[] cbuf = new char[5];
        // read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
        int len;
        // len =fr.read(cbuf) // 读入的个数
        while ((len =fr.read(cbuf)) != -1) {
            for (int i = 0; i < len; i++) { // 每次读进去几个,就遍历几个
                /*
                for (int i = 0; i < cbuf.length; i++) {
                    System.out.print(cbuf[i]); // helloworld123ld
                    // 原因:在执行第三次的时候,只有前3个字符被覆盖了,第二次执行的时的world的前三个字符,后面的ld字符没有覆盖,跟着输出。
                }
                */
                System.out.print(cbuf[i]);
            }
        }
        // 4、流的手动关闭操作
        fr.close();
    }
🪂 写出操作FileWriter

在这里插入图片描述

  • 说明点:写出数据,文件可以不存在
  • 1、输出操作,对应的File可以不存在的,会自动创建此文件。并不会报异常
  • 2、File对应的硬盘中的文件如果存在:
    • 如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
    • 如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容
    @Test
    public void testFileWriter() throws IOException {
         
            //1.提供File类的对象,指明写出到的文件
            File file = new File("hello1.txt");

            //2.提供FileWriter的对象,用于数据的写出
            FileWriter fw = new FileWriter(file);// 覆盖文件,此时FileWriter(file,true)追加文件

            //3.写出的操作
            fw.write("I have a dream!\n");
            fw.write("you need to have a dream!");

            //4.流资源的关闭
            if (fw != null) {
                fw.close();
            }
    }

读入和写出的整体操作 --> 复制操作

 @Test
    public void testFileReaderFileWriter123123() throws IOException {

            //1.创建File类的对象,指明读入和写出的文件
            File srcFile = new File("hello1.txt");
            File destFile = new File("hello2.txt");

            //不能使用字符流来处理图片等字节数据
//            File srcFile = new File("爱情与友情.jpg");
//            File destFile = new File("爱情与友情1.jpg");


            //2.创建输入流和输出流的对象
            FileReader fr = new FileReader(srcFile);
            FileWriter fw = new FileWriter(destFile);


            //3.数据的读入和写出操作
            char[] cbuf = new char[5];
            int len; // 记录每次读入到cbuf数组中的字符的个数

            while ((len = fr.read(cbuf)) != -1) {
                //每次写出len个字符
                fw.write(cbuf, 0, len);
            }

            //4.关闭流资源
            if(fw != null) {
                fw.close();
            }
            if(fr != null){
                fr.close();
            }
        }
🚭 字节流

1、对于文本文件(.txt,.java,.c,.cpp),使用字符流处理

2、对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理

  • 如果文本文件只是想复制一下,用字节流也是可以的,但是不能在内存层面读,可能会有乱码
  • 非文本还是不能用字符的
🪂 读取操作FileInputStream
🪂 写出操作FileOutputStream

使用字节流FileInputStream处理文本文件,可能出现乱码。(字符编码不一致)

// 实现对图片的复制操作
@Test
public void testFileInputOutputStream() throws IOException {

        File srcFile = new File("迪丽热巴.jpg");
        File destFile = new File("迪丽热巴1.jpg");

        FileInputStream fis  = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        //复制的过程
        byte[] buffer = new byte[5];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

        fos.close();
        fis.close();
}
🪂 通用方法:指定路径下文件的复制操作FileInputStream
//指定路径下文件的复制
public void copyFile(String srcPath,String destPath){
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);

        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        //复制的过程
        byte[] buffer = new byte[1024];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fos != null){
            //
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}


-------------------------- 测试 -------------------------------------

    @Test
    public void testCopyFile(){

        long start = System.currentTimeMillis();

        String srcPath = "C:\\Users\\Administrator\\Desktop\\01-视频.avi";
        String destPath = "C:\\Users\\Administrator\\Desktop\\02-视频.avi";

        copyFile(srcPath,destPath);


        long end = System.currentTimeMillis();

        System.out.println("复制操作花费的时间为:" + (end - start));//618

    }

🚬 处理流之一:缓冲流 掌握

在这里插入图片描述

作用:

  • 提高流的读取、写入的速度
  • 提高读写速度的原因:内部提供了一个缓冲区
    • bos.flush() 刷新缓冲区

处理流,就是“套接”在已有的流的基础上。

关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略

🚭 字节流

实现非文本文件的复制

BufferedInputStream、BufferedInputStream

    @Test
    public void BufferedStreamTest() throws Exception {

        //1.造文件
        File srcFile = new File("爱情与友情.jpg");
        File destFile = new File("爱情与友情3.jpg");

        //2.造流
        //2.1 造节点流
        FileInputStream fis = new FileInputStream((srcFile));
        FileOutputStream fos = new FileOutputStream(destFile);
        //2.2 造缓冲流
        BufferedInputStream bis  = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        //3.复制的细节:读取、写入
        byte[] buffer = new byte[10];
        int len;
        while ((len = bis.read(buffer)) != -1) {
            bos.write(buffer, 0, len);

//            bos.flush();//刷新缓冲区

        }

        //4.资源关闭
        //要求:先关闭外层的流,再关闭内层的流
        bos.close();
        bis.close();
        
        //说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
        // fos.close();
        // fis.close();
    }
🚭 字符流

BufferedReader、BufferedWriter

    @Test
    public void testBufferedReaderBufferedWriter() throws IOException {

        //创建文件和相应的流 (匿名的方式)
        BufferedReader br = new BufferedReader(new FileReader(new File("dbcp.txt")));
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));

        //读写操作
        //BufferedReader(多了一种处理方案)方式一:使用char[]数组
        char[] cbuf = new char[1024];
        int len;
        while((len = br.read(cbuf)) != -1){
            bw.write(cbuf,0,len);
//            bw.flush(); // 8192 个字节 1024 的8倍  1kb = 1024
        }

        //BufferedReader(多了一种处理方案)式二:使用String
        String data;
        while ((data = br.readLine()) != null) { // readLine 一次读取一行
            //方法一:
//            bw.write(data + "\n");//data中不包含换行符
            //方法二:
            bw.write(data);//data中不包含换行符
            bw.newLine();//提供换行的操作

        }

        //关闭资源
        bw.close();
        br.close();

    }
🚭 练习:1、实现图片的加密和解密

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kIKaQRmD-1664245104012)(泛型和IO流.assets/image-20220927100530247.png)]

	// 加密操作
	@Test
    public void test123() throws IOException {

		// FileInputStream fis = new FileInputStream(new File("爱情与友情.jpg"));
        FileInputStream fis  = new FileInputStream("爱情与友情.jpg"); //FileInputStream有一个构造器可以直接处理文件
        FileOutputStream fos  = new FileOutputStream("爱情与友情secret.jpg");

            byte[] buffer = new byte[20];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                //字节数组进行修改
                // 错误的:增强for循环是把原来的数据赋给一个新的变量,修改新的变量,原来的数据没有修改
                // for(byte b : buffer){
                //     b = (byte) (b ^ 5);
                // }
                //正确方式
                for (int i = 0; i < len; i++) {
                    buffer[i] = (byte) (buffer[i] ^ 5);
                }


                fos.write(buffer, 0, len);
            }

        fos.close();
        fis.close();

    }

    //图片的解密
    @Test
    public void test() throws IOException {


        FileInputStream fis = new FileInputStream("爱情与友情secret.jpg");
        FileOutputStream fos = new FileOutputStream("爱情与友情4.jpg");

        byte[] buffer = new byte[20];
        int len;
        while ((len = fis.read(buffer)) != -1) {
            //字节数组进行修改
            //错误的
            //            for(byte b : buffer){
            //                b = (byte) (b ^ 5);
            //            }
            //正确的
            for (int i = 0; i < len; i++) {
                buffer[i] = (byte) (buffer[i] ^ 5);
            }

            fos.write(buffer, 0, len);
        }

        fos.close();
        fis.close();
    }
🚭 练习:2、获取文本上每个字符出现的次数

提示:遍历文本的每一个字符;字符及出现的次数保存在Map中;将Map中数据写入文件

思路:

  • 1、遍历文本每一个字符
  • 2、字符出现的次数存在Map中
Map<Character,Integer> map = new HashMap<Character,Integer>();
map.put('a',18);
map.put('你',2);
@Test
    public void testWordCount123123() throws Exception {

        //1.创建Map集合
        Map<Character, Integer> map = new HashMap<Character, Integer>(); // 字符 个数

        //2.遍历每一个字符,每一个字符出现的次数放到map中
        FileReader fr = new FileReader("hello1.txt");
        int c = 0;
        while ((c = fr.read()) != -1) {
            //int 还原 char
            char ch = (char) c;
            // 判断char是否在map中第一次出现
            if (map.get(ch) == null) {
                map.put(ch, 1);
            } else {
                map.put(ch, map.get(ch) + 1);
            }
        }

        //3.把map中数据存在文件count.txt
        //3.1 创建Writer
        BufferedWriter bw = new BufferedWriter(new FileWriter("wordcount.txt"));

        //3.2 遍历map,再写入数据
        Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
        for (Map.Entry<Character, Integer> entry : entrySet) {
            switch (entry.getKey()) {
                case ' ':
                    bw.write("空格=" + entry.getValue());
                    break;
                case '\t'://\t表示tab 键字符
                    bw.write("tab键=" + entry.getValue());
                    break;
                case '\r'://
                    bw.write("回车=" + entry.getValue());
                    break;
                case '\n'://
                    bw.write("换行=" + entry.getValue());
                    break;
                default: // abc 123 (普通字符)
                    bw.write(entry.getKey() + "=" + entry.getValue());
                    break;
            }
            bw.newLine();//换行
        }
        //4.关流
        fr.close();
        bw.close();
    }

🚬 处理流之二:转换流属于字符流 掌握

在这里插入图片描述

属于字符流:InputStreamReader、OutputStreamWriter

    @Test
    public void test1() throws IOException {

        FileInputStream fis = new FileInputStream("dbcp.txt");
//        InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
        //参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
        InputStreamReader isr = new InputStreamReader(fis,"UTF-8");

        char[] cbuf = new char[20];
        int len;
        while((len = isr.read(cbuf)) != -1){
            String str = new String(cbuf,0,len);
            System.out.print(str);
        }

        isr.close();

    }

综合使用InputStreamReader和OutputStreamWriter,UTF-8读写出去使用GBK

    @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();
    }
🚭 字符集

在这里插入图片描述

🚬 处理流之三:对象流 掌握

在这里插入图片描述

🚭 对象序列化要求 --> JSON
  • Person需要满足如下的要求,方可序列化
    • 1、需要实现接口:Serializable
    • 2、当前类提供一个全局常量:serialVersionUID
    • 3、除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
  • 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
public class Person implements Serializable{

    public static final long serialVersionUID = 475463534532L;

    private String name;
    private int age;
    private int id;	
    
    .....

}
🚭 序列化

在这里插入图片描述

序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去,使用ObjectOutputStream实现

  • 文件不是程序要自己打开查看的
@Test
public void testObjectOutputStream() throws IOException {

    //1.
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
    //2.
    oos.writeObject(new String("我爱北京天安门"));
    oos.flush();//刷新操作

    oos.writeObject(new Person("王铭", 23));
    oos.flush();

    oos.writeObject(new Person("张学良", 23, 1001, new Account(5000)));
    oos.flush();
    //3.
    oos.close();

}
🚭 反序列化

反序列化:将磁盘文件中的对象还原为内存中的一个java对象,使用ObjectInputStream来实现

  • 文件不是程序要自己打开查看的
    @Test
    public void testObjectInputStream() throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.dat"));

        Object obj = ois.readObject();
        String str = (String) obj;

        Person p = (Person) ois.readObject();
        Person p1 = (Person) ois.readObject();

        System.out.println(str);
        System.out.println(p);
        System.out.println(p1);
        
        ois.close();

    }

🚬 处理流之四:标准输入、输出流 了解

在这里插入图片描述

    练习:从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入“e”或者“exit”时,退出程序。

  • 方法一:使用Scanner实现,调用next()返回一个字符串

  • 方法二:使用System.in实现。System.in —> 转换流 —> BufferedReader的readLine()

    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader 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);

        }

        br.close();
    }

🚬 处理流之五:打印流 了解

在这里插入图片描述

需求:输出的数据不想只是在控制台看一下,想给其保存起来,可以使用打印流

    @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();
            }
        }

    }

🚬 处理流之六:数据流 了解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CYB0bG8w-1664286911946)(泛型和IO流.assets/image-20220927155709808.png)]

操作基本数据类型和String,把内存中的基本数据类型或者字符串写入到文件中,记录下来,同时也可以把写出去的文件对应到内存中,对应到基本数据类型和String

将内存中的字符串、基本数据类型的变量写出到文件中。

  • 注意:此时的data.txt不是让程序员点击查看的,想要查看需要使用流
    @Test
    public void test3() throws IOException {

        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

        dos.writeUTF("刘建辰");
        dos.flush();//刷新操作,将内存中的数据写入文件
        dos.writeInt(23);
        dos.flush();
        dos.writeBoolean(true);
        dos.flush();

        dos.close();

    }

将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。

  • 注意:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!
    @Test
    public void test4() throws IOException {

        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

        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);

        dis.close();

    }

🚬 随机存取文件流 了解

在这里插入图片描述

RandomAccessFile既可以作为一个输入流,又可以作为一个输出流

    @Test
    public void test12() throws IOException {


       //1.
       RandomAccessFile raf1  = new RandomAccessFile(new File("爱情与友情.jpg"),"r");
       RandomAccessFile raf2  = new RandomAccessFile(new File("爱情与友情1.jpg"),"rw");
       //2.
       byte[] buffer = new byte[1024];
       int len;
       while((len = raf1.read(buffer)) != -1){
           raf2.write(buffer,0,len);
       }

       raf1.close();
       raf2.close();

    }

如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。

如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)

  • 如果源文件长度大于新文件长度,源文件之后覆盖和新文件长度相同的长度,后面的内容不变
    @Test
    public void test2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        raf1.write("xyz".getBytes());//

        raf1.close();

    }

使用RandomAccessFile实现数据的插入效果(插入效率差)

    @Test
    public void test3() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");

        raf1.seek(3);//将指针调到角标为3的位置
        //保存指针3后面的所有数据到StringBuilder中
        StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            builder.append(new String(buffer,0,len)) ;
        }
        //调回指针,写入“xyz”
        raf1.seek(3);
        raf1.write("xyz".getBytes());

        //将StringBuilder中的数据写入到文件中
        raf1.write(builder.toString().getBytes());

        raf1.close();

        //思考:将StringBuilder替换为ByteArrayOutputStream
    }

🚒 NIO.2中Path、 Paths、Files类的使用 了解

🚬 NIO 概述

在这里插入图片描述

🚬 NIO. 2

在这里插入图片描述

🚭 Path 接口

在这里插入图片描述

🚭 Paths 接口
🚭 Files 类

在这里插入图片描述
在这里插入图片描述

🚏 网络编程

🚀 网络编程概述

在这里插入图片描述

🚄 网络通信要素概述

在这里插入图片描述

🚬 通信要素1:IP和端口号

🚭 IP

在这里插入图片描述

    public static void main(String[] args) {

        try {
            //File file = new File("hello.txt");
            InetAddress inet1 = InetAddress.getByName("192.168.10.14");

            System.out.println(inet1);

            InetAddress inet2 = InetAddress.getByName("www.atguigu.com");
            System.out.println(inet2);

            InetAddress inet3 = InetAddress.getByName("127.0.0.1");
            System.out.println(inet3);

            //获取本地ip
            InetAddress inet4 = InetAddress.getLocalHost();
            System.out.println(inet4);

            //getHostName()
            System.out.println(inet2.getHostName());
            //getHostAddress()
            System.out.println(inet2.getHostAddress());

        } catch (UnknownHostException e) {
            e.printStackTrace();
        }

    }
🚭 端口号

在这里插入图片描述

🚬 通信要素2:网络协议

在这里插入图片描述
在这里插入图片描述

🚭 TCP/IP簇

在这里插入图片描述

🚭 TCP和UDP

在这里插入图片描述

🚒 TCP网络编程

🚬 TCP三次挥手

在这里插入图片描述

🚬 TCP四次握手

在这里插入图片描述

🚬 Socket

在这里插入图片描述

🚬 实现TCP的网络编程

在这里插入图片描述

  • 客户端
    • 1、创建Socket对象,指明服务器端的ip和端口号
    • 2、获取一个输出流,用于输出数据
    • 3、写出数据的操作
    • 4、资源的关闭
  • 服务端
    • 1、创建服务器端的ServerSocket,指明自己的端口号
    • 2、调用accept()表示接收来自于客户端的socket
    • 3、获取输入流
    • 4、读取输入流中的数据
    • 5、关闭资源
🚭 例子1:客户端发送信息给服务端,服务端将数据显示在控制台上

使用try-catch-finally,先有服务器,后有客户端

    //服务端
    @Test
    public void server1() throws IOException {

        //1.创建服务器端的ServerSocket,指明自己的端口号
        ServerSocket ss = new ServerSocket(8899);
        //2.调用accept()表示接收来自于客户端的socket
        Socket socket = ss.accept();
        //3.获取输入流
        InputStream is = socket.getInputStream();

        //不建议这样写,可能会有乱码
//        byte[] buffer = new byte[1024];
//        int len;
//        while((len = is.read(buffer)) != -1){
//            String str = new String(buffer,0,len);
//            System.out.print(str);
//        }
        //4.读取输入流中的数据
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[5];
        int len;
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer, 0, len); // 取出数据
        }

        System.out.println(baos.toString());
        //                                           获取他的IP       的地址
        System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据");

        //5.关闭资源
        baos.close();
        is.close();
        socket.close();
        ss.close();

    }
    
    // 客户端
    @Test
    public void client1() throws IOException {

        //1.创建Socket对象,指明服务器端的ip和端口号
        InetAddress inet = InetAddress.getByName("127.0.0.1");
        Socket socket = new Socket(inet, 8899);
        //2.获取一个输出流,用于输出数据
        OutputStream os = socket.getOutputStream();
        //3.写出数据的操作
        os.write("你好,我是客户端mm".getBytes());

        //4.资源的关闭
        os.close();
        socket.close();

    }
🚭 例题2:客户端发送文件给服务端,服务端将文件保存在本地。
    @Test
    public void client() throws IOException {
        //1.
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
        //2.
        OutputStream os = socket.getOutputStream();
        //3.
        FileInputStream fis = new FileInputStream(new File("王羽杉.jpg"));
        //4.
        byte[] buffer = new byte[1024];
        int len;
        while((len = fis.read(buffer)) != -1){
            os.write(buffer,0,len);
        }
        //5.
        fis.close();
        os.close();
        socket.close();
    }

    @Test
    public void server() throws IOException {
        //1.
        ServerSocket ss = new ServerSocket(9090);
        //2.
        Socket socket = ss.accept();
        //3.
        InputStream is = socket.getInputStream();
        //4.
        FileOutputStream fos = new FileOutputStream(new File("王羽杉1.jpg"));
        //5.
        byte[] buffer = new byte[1024];
        int len;
        while((len = is.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }
        //6.
        fos.close();
        is.close();
        socket.close();
        ss.close();

    }
🚭 例题3:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。并关闭相应的连接。
    @Test
    public void client() throws IOException {
        //1.
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
        //2.
        OutputStream os = socket.getOutputStream();
        //3.
        FileInputStream fis = new FileInputStream(new File("王羽杉.jpg"));
        //4.
        byte[] buffer = new byte[1024];
        int len;
        while((len = fis.read(buffer)) != -1){
            os.write(buffer,0,len);
        }
        
        //客户传完图片之后 关闭数据的输出
        socket.shutdownOutput(); // 服务端就得到明确的指示 客户端不在发送数据

        //5.接收来自于服务器端的数据,并显示到控制台上
        InputStream is = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] bufferr = new byte[20];
        int len1;
        while((len1 = is.read(buffer)) != -1){ 
            baos.write(buffer,0,len1);
        }


        System.out.println(baos.toString());

        //6.
        fis.close();
        os.close();
        socket.close();
        baos.close();
    }

    @Test
    public void server() throws IOException {
        //1.
        ServerSocket ss = new ServerSocket(9090);
        //2.
        Socket socket = ss.accept();
        //3.
        InputStream is = socket.getInputStream();
        //4.
        FileOutputStream fos = new FileOutputStream(new File("王羽杉2.jpg"));
        //5.
        byte[] buffer = new byte[1024];
        int len;
        while((len = is.read(buffer)) != -1){// read 阻塞式的方法:没有明确告诉,方法就不会退出循环  socket.shutdownOutput();关闭数据的输出
            fos.write(buffer,0,len);
        }

        System.out.println("图片传输完成");

        //6.服务器端给予客户端反馈
        OutputStream os = socket.getOutputStream();
        os.write("你好,美女,照片我已收到,非常漂亮!".getBytes());

        //7.
        fos.close();
        is.close();
        socket.close();
        ss.close();
        os.close();

    }

🚔 UDP网络编程

在这里插入图片描述

🚬 DatagramSocket 和 DatagramPacket常用方法

在这里插入图片描述
在这里插入图片描述

🚬 UDP协议的步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gg23Iiwv-1664460692896)(泛型和IO流.assets/image-20220929215454841.png)]

    //发送端
    @Test
    public void sender() throws IOException {

        DatagramSocket socket = new DatagramSocket();

        String str = "我是UDP方式发送的导弹";
        byte[] data = str.getBytes();
//        InetAddress inet = InetAddress.getByName();//对方的ip地址
        InetAddress inet = InetAddress.getLocalHost();//此时是个自己发送
        // 封装数据包
        DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);

        socket.send(packet); // 发送

        socket.close();

    }
    //接收端
    @Test
    public void receiver() throws IOException {

        DatagramSocket socket = new DatagramSocket(9090);

        byte[] buffer = new byte[100];
        DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);

        socket.receive(packet); // 接收数据

        System.out.println(new String(packet.getData(),0,packet.getLength()));

        socket.close();
    }

🛴 URL编程

在这里插入图片描述

🚬 常用方法

    public static void main(String[] args) {

        try {

            URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom");

//            public String getProtocol(  )     获取该URL的协议名
            System.out.println(url.getProtocol());
//            public String getHost(  )           获取该URL的主机名
            System.out.println(url.getHost());
//            public String getPort(  )            获取该URL的端口号
            System.out.println(url.getPort());
//            public String getPath(  )           获取该URL的文件路径
            System.out.println(url.getPath());
//            public String getFile(  )             获取该URL的文件名
            System.out.println(url.getFile());
//            public String getQuery(   )        获取该URL的查询名
            System.out.println(url.getQuery());

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

    }

🚬 文件下载

public static void main(String[] args) {

        HttpURLConnection urlConnection = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            URL url = new URL("http://localhost:8080/examples/beauty.jpg");

            urlConnection = (HttpURLConnection) url.openConnection();

            urlConnection.connect();

            is = urlConnection.getInputStream();
            fos = new FileOutputStream("day10\\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();
            }
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gh-xiaohe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值