IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> Java--IO流 -> 正文阅读

[开发工具]Java--IO流

IO流



一、File类

1.File的含义和位置

File类对象代表一个文件或者一个文件夹;File类存放在io包下。

2.获取File类的三种方式

public static void test1()
    {
        //1.通过相对路径或者绝对路径直接获取对应的file类
        //File(String filePath)
        // 通过相对路径获取file类 内存层面的对象
        File file1 = new File("first.txt");
        System.out.println(file1);
        // 通过绝对路径获取file类
        // File.separator 根据不同的系统区分
        //路径分隔符 windows:\\ unix:/
        File file2 = new File("D:" + File.separator + "myproject" + File.separator + "my-javabase-demo" + File.separator
                + "javase-demo" + File.separator + " first.txt");
        System.out.println(file2);

        //2.父文件夹的方式跟子文件夹的方式获取file类
        //File(String parentPath,String childPath)
        File file3 = new File("D:\\myproject\\my-javabase-demo", "javase-demo");
        System.out.println(file3);

        //3.根据file对象,还有子文件夹获取对应的file类
        //File(File parentFile,String childPath)
        File file4 = new File(file3, "first.txt");
        System.out.println(file4);
    }

2.1.File类路径注意事项:

相对路径:相较于某个路径下,指明的路径。 idea @test的单元测试指在同一个module下,main方法里面指同一个工程下;
绝对路径:包含盘符在内的文件或文件目录的路径

3.File常见功能


目录结构

3.1.File类的获取功能

3.1.1.常见的File类获取功能

public static void test2()
    {
        /**
         * 通过相对路径跟绝对路径的获取查看区别
         */
        File file1 = new File("first.txt");
        File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\second.txt");

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

        System.out.println("----------");

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

        // getAbsolutePath 获取绝对路径。绝对路径和相对路径获取的file类结果相同
        // getPath 获取路径。相对路径获取的file类:文件名;绝对路径获取的file类:全路径
        // getParent 上级目录(没有为null)。相对路径获取的file类:null;绝对路径获取的file类:全路径
        // getName 获取文件名。相同
        // length 获取文件长度(即:字节数)。相对路径获取的file类:0;绝对路径获取的file类:对应长度
        // lastModified 最后一次的修改时间戳。相对路径获取的file类:0;绝对路径获取的file类:对应时间
    }

3.1.2.File对象获取对应的文件夹列表

public static void test3()
    {
        /**
         * 获取对应的文件夹列表,只能用绝对路径
         */
        File file = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\di");
        //file.list() 获取指定目录下的所有文件或者文件目录的名称数组
        for (String s : Objects.requireNonNull(file.list()))
        {
            System.out.println(s);
        }
        //file.listFiles() 获取指定目录下的所有文件或者文件目录的File数组
        for (File listFile : Objects.requireNonNull(file.listFiles()))
        {
            System.out.println(listFile.getAbsolutePath());
        }
    }

3.2.File类的重命名功能

public static void test4()
    {
        File file1 = new File("first.txt");
        // 相对路径的无法进行 重命名 false
        System.out.println(file1.renameTo(new File("1.txt")));
        File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\second.txt");
        // renameTo 里面的文件路径为外层文件夹下的路径,然后对应的文件会改名字且移动位置
        System.out.println(file2.renameTo(new File("D:\\myproject\\my-javabase-demo\\javase-demo\\three.txt")));
    }

3.3.File类的判断功能

 public static void test5()
    {
        // 相对路径所有的判断功能都是false 需要用 绝对路径判断
        File file1 = new File("first.txt");
        File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\three.txt");

        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());// 判断是否隐藏
    }

3.4.File类的创建功能

public static void test6()
    {
        File file1 = new File("di.txt");
        File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\four.txt");
        File file3 = new File("di");
        File file4 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\four");
        try
        {
            // 创建文件。若文件存在,则不创建,返回false
            // 相对路径创建为大文件夹下面
            System.out.println(file1.createNewFile());
            System.out.println(file2.createNewFile());
            // 创建文件目录。如果上层文件目录不存在,一并创建
            System.out.println(file3.mkdir());
            System.out.println(file4.mkdir());
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

3.5.File类的删除功能

public static void test7()
    {
        // 相对路径无法删除
        File file1 = new File("first.txt");
        System.out.println(file1.delete());

        // 绝对路径删除
        File file2 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\first.txt");
        System.out.println(file2.delete());

        // 文件夹删除如果里面包含文件无法删除
        // 需要删除里面的文件 然后删除对应的文件夹,即空文件夹才可以删除
        File file3 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\di");
        System.out.println(file3.delete());

        if (file3.isDirectory())
        {
            for (File file : file3.listFiles())
            {
                file.delete();
            }
        }
        System.out.println(file3.delete());
    }

4.File类注意事项

当硬盘有一个真实的文件或目录存在时,创建File对象,各个属相会显示赋值;
当硬盘中没有真实的文件或者文件夹对应时,创建对象时,除了指定的目录和路径外,其他的属性取成员变量的默认值。

二、IO流的原理及流的分类

1.Java IO原理

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

2.流的分类

2.1.根据流向分类

  • 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  • 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

2.2.根据数据单位分类

  • 字节流(8 bit)
  • 字符流(16 bit)

2.3.根据流的角色分类

  • 节点流 (直接从数据源或目的地读写数据),直接作用在源文件上面的。
  • 处理流 (不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。作用在已有的流之上)
    在这里插入图片描述

3.字符流

3.1.Reader 读入文件数据

// read()方法的操作
    public static void test1()
    {
        // 1.实例化file类的对象,指明要操纵的文件
        File file = new File("javase-demo\\three.txt");
        FileReader fileReader = null;
        try
        {
            // 2.提供具体的流
            fileReader = new FileReader(file);
            // 3.数据读入
            // read():返回读入的字符,如果达到文件的末尾,返回-1
            // 读入的文件一定要存在,否则FileNotFoundException。
            int data = fileReader.read();
            // 循环的遍历文件里面的字符
            while (data != -1)
            {
                System.out.println((char) data);
                data = fileReader.read();
            }

        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            // 4.关闭流
            try
            {
                if (fileReader != null)
                {
                    fileReader.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
 // read(char[] cArr)
    public static void test2()
    {
        FileReader fileReader = null;
        try
        {
            // 1.File类的实例化
            File file = new File("javase-demo\\three.txt");

            // 2.FileReader流的实例化
            fileReader = new FileReader(file);
            // 3.读入的操作
            char[] cArr = new char[5];
            int len;
            while ((len = fileReader.read(cArr)) != -1)
            {
                // 如果用此方式会导致每次的数据覆盖原本的char数组,如果此次的char数组没有读满,会将上一次读入的也再次读取;
                // for (int i = 0; i < cArr.length; i++)
                // {
                // System.out.println(cArr[i]);
                // }
                // 每次只遍历读取的长度
                // for (int i = 0; i < len; i++)
                // {
                // System.out.print(cArr[i]);
                // }
                // 通过string的截取读取
                System.out.print(new String(cArr, 0, len));
            }

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            // 4.流资源关闭
            if (fileReader != null)
            {
                try
                {
                    fileReader.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }

3.2.Writer 写入数据到文件

public static void test3()
    {
        FileWriter fileWriter = null;
        try
        {
            // 1.File类的实例化,指明写出的文件
            File file = new File("javase-demo\\one.txt");
            // 2.提供FileWriter对象,用于数据的写出
            // File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
            // 如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
            // 如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容
            fileWriter = new FileWriter(file, true);
            // 3.写出的操作
            fileWriter.write("小白,你好\n");
            fileWriter.write("小白,加油\n");
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            // 4.流的关闭
            try
            {
                if (fileWriter != null)
                {
                    fileWriter.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
 public static void test4()
    {
        // 将文件读入并写出,即复制文件
        FileReader fileReader = null;
        FileWriter fileWriter = null;
        try
        {
            // 1.创建File类的对象,指明读入和写出的文件
            File file1 = new File("javase-demo\\one.txt");
            File file2 = new File("javase-demo\\two.txt");
            // 2.提供FileWriter,FileReader对象,用于数据的读入和写出
            fileReader = new FileReader(file1);
            fileWriter = new FileWriter(file2);
            // 3.读取数据和写入数据的操作
            // 方式一:每次一个一个的写出
            // int data;
            // while ((data = fileReader.read()) != -1)
            // {
            // fileWriter.write(data);
            // }
            // 方式二:批量的写出
            char[] cArr = new char[5];
            int len;// 记录每次读入到cbuf数组中的字符的个数
            while ((len = fileReader.read(cArr)) != -1)
            {
                // 每次写出len个字符
                fileWriter.write(cArr, 0, len);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {

            try
            {
                // 4.流资源的关闭
                if (fileReader != null)
                {
                    fileReader.close();
                }
                if (fileWriter != null)
                {
                    fileWriter.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

3.3.注意事项

  • 字符流无法处理图片之类格式的文件
  • 对于文本文件(.txt,.java,.c,.cpp …),使用字符流处理
  • 对于非文本文件(.jpg,.mp3,.doc,.ppt,.xls),使用字节流处理
  • 使用字节流处理文本文件,如果遇到中文等,可能出现乱码。
  • 如果是单纯的复制文件,则字节流和字符流都可以使用。

4.字节流

4.1.使用字节流复制图片文件

   public static void test2()
    {
        // 使用字节流复制图片文件
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try
        {
            // 1.实例化 file
            File fileScr = new File("javase-demo\\img.png");
            File fileDest = new File("javase-demo\\img1.png");
            // 2.创建流
            inputStream = new FileInputStream(fileScr);
            outputStream = new FileOutputStream(fileDest);
            // 3.数据操作
            int data;
            while ((data = inputStream.read()) != -1)
            {
                outputStream.write(data);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            // 4.关闭流资源
            try
            {
                if (inputStream != null)
                    inputStream.close();
                if (outputStream != null)
                    outputStream.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

4.2.文件目录如下

在这里插入图片描述

5.缓冲流

5.1.BufferedInputStream && BufferedOutputStream

public static void test1()
    {
        // 利用缓冲流实现非文本文件的复制
        long start = System.currentTimeMillis();
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try
        {
            // 1.实例化file对象
            File file1 = new File("javase-demo\\img.png");
            File file2 = new File("D:\\img.png");
            // 2.创建流对象
            // 2.1.节点流
            inputStream = new FileInputStream(file1);
            outputStream = new FileOutputStream(file2);
            // 2.2.缓冲流
            bufferedInputStream = new BufferedInputStream(inputStream);
            bufferedOutputStream = new BufferedOutputStream(outputStream);
            // 3.文件操作,复制
            byte[] bytes = new byte[1024];
            int len;
            while ((len = bufferedInputStream.read(bytes)) != -1)
            {
                bufferedOutputStream.write(bytes, 0, len);
                //刷新缓冲区
//                bufferedOutputStream.flush();
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            // 4.关闭流资源,
            // 由于包装了缓冲流,有一个关闭顺序,即先关闭缓冲流(外层),再关闭节点流(内层)
            try
            {
                if (bufferedInputStream != null)
                    bufferedInputStream.close();
                if (bufferedOutputStream != null)
                    bufferedOutputStream.close();
                // 关闭外层流的同时,内层的流也一同关闭,可不用关闭
                if (inputStream != null)
                    inputStream.close();
                if (outputStream != null)
                    outputStream.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

5.2.BufferedReader&& BufferedWriter

public static void test2()
    {
        // 使用BufferedReader和BufferedWriter实现文本文件的复制
        long start = System.currentTimeMillis();
        BufferedWriter bufferedWriter = null;
        BufferedReader bufferedReader = null;
        try
        {
            // 1.实例化file对象
            File file1 = new File("D:\\myproject\\my-javabase-demo\\javase-demo\\text.txt");
            File file2 = new File("D:\\text.txt");
            // 2.创建流对象
            // 2.1.节点流 字符流
            FileReader fileReader = new FileReader(file1);
            FileWriter fileWriter = new FileWriter(file2);
            // 2.2.缓冲流
            bufferedReader = new BufferedReader(fileReader);
            bufferedWriter = new BufferedWriter(fileWriter);
            // 3.文件操作,复制
            // 方式一:使用char[]数组
//            char[] cbuf = new char[1024];
//            int len;
//            while ((len = bufferedReader.read(cbuf)) != -1)
//            {
//                bufferedWriter.write(cbuf, 0, len);
//                // bw.flush();
//            }
            //方式二:使用String
            String data;
            while((data = bufferedReader.readLine()) != null){
                //方法一:
//                bw.write(data + "\n");//data中不包含换行符
                //方法二:
                bufferedWriter.write(data);//data中不包含换行符
                bufferedWriter.newLine();//提供换行的操作

            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                // 4.关闭流
                if (bufferedReader != null)
                    bufferedReader.close();
                if (bufferedWriter != null)
                    bufferedWriter.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

6.转换流(转换流提供了在字节流和字符流之间的转换)

7.其他的流的使用

7.1.标准的输入输出流

 //利用标准输入输出流,从控制台输入 字母转换成大写,
    //输入e 或者 exit 结束
    public static void test1()
    {
        BufferedReader bufferedReader = null;
        try
        {
            InputStreamReader inputStreamReader = new InputStreamReader(System.in);
            bufferedReader = new BufferedReader(inputStreamReader);
            String data;
            while (true)
            {
                System.out.println("输入字符串:");
                data = bufferedReader.readLine();
                if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data))
                {
                    System.out.println("程序结束");
                    break;
                }
                String upperCase = data.toUpperCase();
                System.out.println(upperCase);
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (bufferedReader != null)
                {
                    bufferedReader.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

8.对象流

8.1.对象流的使用

  • ObjectInputStream && OjbectOutputSteam
    用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
  • 序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
  • 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制
  • ObjectInputStream || OjbectOutputSteam 不能序列化static和transient修饰的成员变量

8.2.对象的序列化

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点(序列化)。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象(反序列化)。

8.3.使用序列化跟反序列化读取和写入操作

public static void test1()
    {
        // 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
        // 使用ObjectOutputStream实现
        ObjectOutputStream outputStream = null;
        try
        {
            outputStream = new ObjectOutputStream(new FileOutputStream("javase-demo\\object.txt"));
            outputStream.writeObject(new String("你好吗,小朋友"));
            outputStream.flush();// 刷新操作

            outputStream.writeObject(new Employee("小白", 1));
            outputStream.flush();

            outputStream.writeObject(new Employee("小红", 23, 1001, new Account(5000)));
            outputStream.flush();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (outputStream != null)
                {
                    outputStream.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
public static void test2()
    {
        // 反序列化:将磁盘文件中的对象还原为内存中的一个java对象
        // 使用ObjectInputStream来实现
        ObjectInputStream objectInputStream = null;
        try
        {
            objectInputStream = new ObjectInputStream(new FileInputStream("javase-demo\\object.txt"));
            Object obj = objectInputStream.readObject();
            String str = (String) obj;
            Employee e1 = (Employee) objectInputStream.readObject();
            Employee e2 = (Employee) objectInputStream.readObject();
            System.out.println(str);
            System.out.println(e1);
            System.out.println(e2);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (objectInputStream != null)
                {
                    objectInputStream.close();
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
public class Employee implements Serializable
{
    public static final long serialVersionUID = 475461233534532L;

    private String name;

    private int age;

    private int id;

    private Account acct;

    public Employee(String name, int age, int id)
    {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    public Employee(String name, int age, int id, Account acct)
    {
        this.name = name;
        this.age = age;
        this.id = id;
        this.acct = acct;
    }

    @Override
    public String toString()
    {
        return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + ", acct=" + acct + '}';
    }

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    public Employee(String name, int age)
    {

        this.name = name;
        this.age = age;
    }

    public Employee()
    {

    }
}
public class Account implements Serializable
{
    public static final long serialVersionUID = 4713454534532L;

    private double balance;

    @Override
    public String toString()
    {
        return "Account{" + "balance=" + balance + '}';
    }

    public double getBalance()
    {
        return balance;
    }

    public void setBalance(double balance)
    {
        this.balance = balance;
    }

    public Account(double balance)
    {

        this.balance = balance;
    }
}

9.RandomAccessFile

9.1.RandomAccessFile概述

  • RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
  • RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
  • 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
  • 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果

9.2.不同构造器

  • public RandomAccessFile(File file, String mode)
  • public RandomAccessFile(String name, String mode)
    创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:
  • r: 以只读方式打开
  • rw:打开以便读取和写入
  • rwd:打开以便读取和写入;同步文件内容的更新
  • rws:打开以便读取和写入;同步文件内容和元数据的更新
  • 如果模式为只读r。则不会创建文件,而是会去读取一个已经存在的文件,
    如果读取的文件不存在则会出现异常。 如果模式为rw读写。如果文件不存在则会去创建文件,如果存在则不会创建。

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 12:06:52  更:2022-05-10 12:08:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/14 15:16:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码