小学数学练习-Java入门小试牛刀

简介: 小学数学练习

小学数学练习

1.1【问题描述】

编写一个帮助小学生练习数学的程序,帮助小学生练习 100 以内的四种数学运算:加、减、乘、除。

1.2【基本要求】

a) 程序应先询问用户的 ID 号(ID 号包括两个大写字母和 4 位数字),例如:
请输入用户 ID 号:AB1234
程序应对输入的 ID 号验证,符合 ID 号要求的格式, 然后程序提示三种选择:
(1)开始测试
(2)检查分数
(3)退出
b) 测试:该程序将给出 10 道数学题,例如:
12 * 3 =36
48 + 32 =80

56 / 28 =2

注意:
i)学生将依次回答每一个问题(在等于号后面给出答案) ,然后给出下一道题。
ii)试题应包含四种数学运算:加、减、乘、除, 它们是随机产生的。 相邻的问题应该是不同的操作,
每个操作必须至少出现一次。 报告中应给出实现方法或算法。
iii)为每道题随机生成数字, 但必须确保参与运算的数字和结果都小于 100 且大于零的整数, 除法时
还要注意两个整数要能整除。 报告中应给出实现方法或算法。
iv)十道题做完后,记录学生完成这十道题所用的时间。
v)给每个学生一个分数。将该学生的 ID、成绩和使用时间保存到一个名为 record.txt 的文件中。
vi)在屏幕上输出以下信息:(3 列信息, 第 1 列是 b) 中的测试题, 蓝色部分)
问题 | 正确答案 | 你的答案
c) 成绩检查:从文件“record.txt” 中列出该学生的所有历史成绩(其他学生的不显示)。例如:
你以前的记录是:
AB1234 80 150 秒
AB1234 50 182 秒
AB1234 90 98 秒

1.3【模块划分】

// 主类
public class One{}
// 用户类
class User{}
// 功能类
class Fun{}

// 封装主类
public class One {

    public static void main(String[] args) {
        // 初始化界面
        Fun fun = new Fun();
        // 加载一位新的用户
        User user = new User(fun.start());
        // 用户进入界面
        fun.index(user);
    }
}

/**
 * 封装用户类
 */
class User{
    /**
     * 用户ID
      */
    private String id;
    /**
     * 用户成绩
     */
    private int scores = 0;
    /**
     * 用户所用时间
     */
    private int time = 0;

    /**
     * 用户做题数据
     */
    private String data = "";

    /**
     * 初始化用户
      */
    public User(String id){
        this.id = id;
    }

    // 一堆堆get,set方法
    .......
    
    // 添加数据的方法
    public void addData(String data){
        this.data = this.data.concat(data);
    }
}


class Fun{

    /**
     * 用户输入ID号模块
     */
    public String start(){}
    /**
     * 首页
     */
    public void index(User user){}

    /**
     * 保存成绩
     */
    public void recordUser(User user) {}

    /**
     * 检查用户
     */
    public void checkUser(User user){}

    /**
     * 随机出题
     */
    public void test(User user){}


    /**
     * 加法
     */
    public void add(User user){}

    /**
     * 减法
     */
    public void delete(User user){}

    /**
     * 乘法
     */
    public void multi(User user){}

    /**
     * 除法
     */
    public void div(User user){}

    /**
     * 校验用户名
     */
    public boolean verify(String id){}

/**
     * 用户输入ID号模块
     */
    public String start(){
        System.out.print("请输入用户 ID 号");
        Scanner sc = new Scanner(System.in);
        String id = sc.next();
         while (!verify(id)){
             System.out.println("ID 号包括两个大写字母和 4 位数字,请重新输入用户ID");
             id = sc.next();
         }
         return id;
    }
  /**
     * 校验用户名
     */
    public boolean verify(String id){
    // 正则表达式
        String format = "[A-Z]{2}[0-9]{4}";
        return id.matches(format);
    }

/**
     * 加法
     */
    public void add(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar = randTil(0);
        String ques = tar[0] + "+" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[2]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + tar[2] + " | " + result + "--");
    }

    /**
     * 减法
     */
    public void delete(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar = randTil(0);
        String ques = tar[2] + "-" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[0]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + tar[0] + " | " + result + "--");
    }

    /**
     * 乘法
     */
    public void multi(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar =  randTil(1);
        String ques = tar[0] + "*" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[2]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + tar[2] + " | " + result + "--");
    }

    /**
     * 除法
     */
    public void div(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar = randTil(1);
        String ques = tar[2] + "\\" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[0]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + + tar[0] + " | " + result + "--");
    }
    /**
     * 数字生成工具
     */
    public int[] randTil(int cal){
        int[] tar = new int[3];
        int num1 = (int)(Math.random()*99) + 1;
        int num2 = (int)(Math.random()*99) + 1;
        if(cal == 0){
            tar[2] = Math.max(num1, num2);
            if(num1 > num2){
                tar[0] = tar[2] - num2;
                tar[1] = num2;
            }else {
                tar[0] = num1;
                tar[1] = tar[2] - num1;
            }
        }
        if(cal == 1){
            tar[0] = (int)(Math.random()*(100/num1-1)) + 1;
            tar[1] = num1;
            tar[2] = tar[0] * tar[1];
        }
        return tar;
    }

 /**
     * 随机出题
     */
    public void test(User user){
        // 初始化用户答题数据
        user.setData("");
        // 创建储存题目分布数组
        int[] num = new int[10];
        // 上一次出现过的数字
        int lastNum = -1;
        // 先保证四种运算出现一次
        for (int i = 0; i < 4; i++) {
            lastNum = randNoRe(lastNum,0, 10);
            num[lastNum] = i + 1;
        }

        lastNum = -1;
        for(int i = 0; i < 10; i++){
           if(num[i] == 0){
                // 只填未填好的数字
                num[i] = randNoRe(lastNum, 1, 4);
                if(i < num.length - 1){
                    if(num[i] == num[i + 1]){
                        i--;
                        num[i] = 0;
                        continue;
                    }
                }
            }
            lastNum = num[i];
        }
        for(int n : num){
            switch (n){
                case 1 : add(user); break;
                case 2 : delete(user); break;
                case 3 : multi(user); break;
                case 4 : div(user); break;
                default:break;
            }
        }
        String[] datas = user.getData().split("--");
        System.out.println("问题 | 正确答案 | 你的答案");
        for (String data : datas) {
            System.out.println(data);
        }
        System.out.println("本次得分:" + user.getScores());
    }

    /**
     * 随机生成与上一次不同的数字组成的数组
     * lastNum:上一个数字,a,b生成范围
     */
    public int randNoRe(int lastNum, int a, int b){
        int n = (int)(Math.random()*b + a);
        while(lastNum == n) {
            n = (int) (Math.random()*b + a);
        }
        return n;
    }

 /**
     * 文件路径
     */
    private static final String FILE_PATH = "E:\\record.txt";
    
/**
     * 保存成绩
     */
    public void recordUser(User user) {
        FileWriter fileWriter = null;
        try {
            File file = new File(FILE_PATH);
            // 判断文件是否存在
            if (!file.isFile()) {
                file.createNewFile();
            }
            // 追加文件
            fileWriter = new FileWriter(file, true);
            // 追加内容
            fileWriter.append(user.getId()).append("  ").append(String.valueOf(user.getScores())).append("  ").append(String.valueOf(user.getTime())).append(" 秒-");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(fileWriter != null){
                try {
                    // 刷新流对象中的缓冲中的数据
                    fileWriter.flush();
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 检查用户
     */
    public void checkUser(User user){

        String[] s1 = null;
        FileReader fileReader = null;
        try{
            // 处理流读取
            fileReader = new FileReader(new File(FILE_PATH));
            BufferedReader bf = new BufferedReader(fileReader);
            String s;
            while ((s = bf.readLine()) != null){
                s1 = s.split("-");
            }
            // 判断是否是新用户
            boolean flag = true;
            for(String str : s1){
                if(str.substring(0,6).equals(user.getId())){
                        // 控制打印次数
                        if(flag){
                            System.out.println("你以前的记录是:");
                            flag = false;
                        }
                        System.out.println(str);
                    }
                }
            // 是新用户
            if(flag){
                System.out.println("新用户,欢迎你使用!");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(fileReader != null){
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

 /**
     * 首页
     */
    public void index(User user){
            // 列出用户历史成绩
            checkUser(user);

            boolean flag = true;
            while (flag) {
                System.out.println("(1)开始测试\n" +
                        "(2)检查分数\n" +
                        "(3)退出"
                );
                // 用户进行功能选择
                Scanner sc = new Scanner(System.in);
                int choice = sc.nextInt();
                switch (choice) {
                    case 1:
                        // 初始化用户成绩
                        user.setScores(0);
                        // 开始计时
                        long start = System.currentTimeMillis();
                        // 开始测试
                        test(user);
                        // 结束计时
                        long end = System.currentTimeMillis();
                        // 设置用户游戏时间
                        user.setTime((int) ((end - start) / 1000));
                        // 保存成绩
                        recordUser(user);
                        break;
                    case 2:
                        // 检查分数
                        checkUser(user);
                        break;
                    case 3:
                        flag = false;
                        System.out.println("退出成功");
                        break;
                    default:break;
                }
            }
    }

1.4【算法思想】

关于如何生成10个数字(每个数字与前一个不同,每个数字至少出现过一次)
在这里插入图片描述

1.5【题解】

import java.io.*;
import java.util.Scanner;

/**
 * @author xh
 */
public class One {

    public static void main(String[] args) {
        // 初始化界面
        Fun fun = new Fun();
        // 加载一位新的用户
        User user = new User(fun.start());
        // 用户进入界面
        fun.index(user);
    }
}

/**
 * 用户类
 */
class User{
    /**
     * 用户ID
      */
    private String id;
    /**
     * 用户成绩
     */
    private int scores = 0;
    /**
     * 用户所用时间
     */
    private int time = 0;

    /**
     * 用户做题数据
     */
    private String data = "";

    /**
     * 初始化用户
      */
    public User(String id){
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public int getScores() {
        return scores;
    }

    public void setScores(int scores) {
        this.scores = scores;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public void addData(String data){
        this.data = this.data.concat(data);
    }
}

class Fun{
    /**
     * 文件路径
     */
    private static final String FILE_PATH = "E:\\record.txt";

    /**
     * 用户输入ID号模块
     */
    public String start(){
        System.out.print("请输入用户 ID 号");
        Scanner sc = new Scanner(System.in);
        String id = sc.next();
         while (!verify(id)){
             System.out.println("ID 号包括两个大写字母和 4 位数字,请重新输入用户ID");
             id = sc.next();
         }
         return id;
    }

    /**
     * 首页
     */
    public void index(User user){
            // 列出用户历史成绩
            checkUser(user);

            boolean flag = true;
            while (flag) {
                System.out.println("(1)开始测试\n" +
                        "(2)检查分数\n" +
                        "(3)退出"
                );
                // 用户进行功能选择
                Scanner sc = new Scanner(System.in);
                int choice = sc.nextInt();
                switch (choice) {
                    case 1:
                        // 初始化用户成绩
                        user.setScores(0);
                        // 开始计时
                        long start = System.currentTimeMillis();
                        // 开始测试
                        test(user);
                        // 结束计时
                        long end = System.currentTimeMillis();
                        // 设置用户游戏时间
                        user.setTime((int) ((end - start) / 1000));
                        // 保存成绩
                        recordUser(user);
                        break;
                    case 2:
                        // 检查分数
                        checkUser(user);
                        break;
                    case 3:
                        flag = false;
                        System.out.println("退出成功");
                        break;
                    default:break;
                }
            }
    }


    /**
     * 保存成绩
     */
    public void recordUser(User user) {
        FileWriter fileWriter = null;
        try {
            File file = new File(FILE_PATH);
            // 判断文件是否存在
            if (!file.isFile()) {
                file.createNewFile();
            }
            // 追加文件
            fileWriter = new FileWriter(file, true);
            // 追加内容
            fileWriter.append(user.getId()).append("  ").append(String.valueOf(user.getScores())).append("  ").append(String.valueOf(user.getTime())).append(" 秒-");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(fileWriter != null){
                try {
                    // 刷新流对象中的缓冲中的数据
                    fileWriter.flush();
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 检查用户
     */
    public void checkUser(User user){

        String[] s1 = null;
        FileReader fileReader = null;
        try{
            // 处理流读取
            fileReader = new FileReader(new File(FILE_PATH));
            BufferedReader bf = new BufferedReader(fileReader);
            String s;
            while ((s = bf.readLine()) != null){
                s1 = s.split("-");
            }
            // 判断是否是新用户
            boolean flag = true;
            for(String str : s1){
                if(str.substring(0,6).equals(user.getId())){
                        // 控制打印次数
                        if(flag){
                            System.out.println("你以前的记录是:");
                            flag = false;
                        }
                        System.out.println(str);
                    }
                }
            // 是新用户
            if(flag){
                System.out.println("新用户,欢迎你使用!");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(fileReader != null){
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 随机出题
     */
    public void test(User user){
        // 初始化用户答题数据
        user.setData("");
        // 创建储存题目分布数组
        int[] num = new int[10];
        // 上一次出现过的数字
        int lastNum = -1;
        // 先保证四种运算出现一次
        for (int i = 0; i < 4; i++) {
            lastNum = randNoRe(lastNum,0, 10);
            num[lastNum] = i + 1;
        }

        lastNum = -1;
        for(int i = 0; i < 10; i++){
            if(num[i] == 0){
                // 只填未填好的数字
                num[i] = randNoRe(lastNum, 1, 4);
                if(i < num.length - 1){
                    if(num[i] == num[i + 1]){
                        i--;
                        num[i] = 0;
                        continue;
                    }
                }
            }
            lastNum = num[i];
        }
        for(int n : num){
            switch (n){
                case 1 : add(user); break;
                case 2 : delete(user); break;
                case 3 : multi(user); break;
                case 4 : div(user); break;
                default:break;
            }
        }
        String[] datas = user.getData().split("--");
        System.out.println("问题 | 正确答案 | 你的答案");
        for (String data : datas) {
            System.out.println(data);
        }
        System.out.println("本次得分:" + user.getScores());
    }

    /**
     * 随机生成与上一次不同的数字组成的数组
     * lastNum:上一个数字,a,b生成范围
     */
    public int randNoRe(int lastNum, int a, int b){
        int n = (int)(Math.random()*b + a);
        while(lastNum == n) {
            n = (int) (Math.random()*b + a);
        }
        return n;
    }

    /**
     * 数字生成工具
     */
    public int[] randTil(int cal){
        int[] tar = new int[3];
        int num1 = (int)(Math.random()*99) + 1;
        int num2 = (int)(Math.random()*99) + 1;
        if(cal == 0){
            tar[2] = Math.max(num1, num2);
            if(num1 > num2){
                tar[0] = tar[2] - num2;
                tar[1] = num2;
            }else {
                tar[0] = num1;
                tar[1] = tar[2] - num1;
            }
        }
        if(cal == 1){
            tar[0] = (int)(Math.random()*(100/num1-1)) + 1;
            tar[1] = num1;
            tar[2] = tar[0] * tar[1];
        }
        return tar;
    }


    /**
     * 加法
     */
    public void add(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar = randTil(0);
        String ques = tar[0] + "+" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[2]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + tar[2] + " | " + result + "--");
    }

    /**
     * 减法
     */
    public void delete(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar = randTil(0);
        String ques = tar[2] + "-" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[0]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + tar[0] + " | " + result + "--");
    }

    /**
     * 乘法
     */
    public void multi(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar =  randTil(1);
        String ques = tar[0] + "*" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[2]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + tar[2] + " | " + result + "--");
    }

    /**
     * 除法
     */
    public void div(User user){
        Scanner sc = new Scanner(System.in);
        int[] tar = randTil(1);
        String ques = tar[2] + "\\" + tar[1] + "=";
        System.out.print(ques);
        int result = sc.nextInt();
        if(result == tar[0]){
            user.setScores(user.getScores() + 10);
        }
        user.addData(ques + "|" + + tar[0] + " | " + result + "--");
    }

    /**
     * 校验用户名
     */
    public boolean verify(String id){
        String format = "[A-Z]{2}[0-9]{4}";
        return id.matches(format);
    }
}

知识总结

一、文件

问题引入:如何判断输入、输出?

参照物:Java程序

输出:程序→文件
内存中的数据储存到持久化设备,这个动作称为输出 Output
输入:文件→程序
持久设备上的数据读取到内存中,这个动作称为输入 Input

Java中把文件或者目录(文件夹)都封装成File对象,如果我们要去操作硬盘上的文件,或者文件夹只要找到File这个类,调用它的功能操作文件或者文件夹

1.File类的构造函数

        String pathName = "e:\\hello.java";
        File f1 = new File(pathName);

        File f2 = new File("e:\\","hello.java");
    
        File dir = new File("e:\\");
        File f3 = new File(dir,"hello.java");

在这里插入图片描述

2.File类的获取

在这里插入图片描述

3.文件和文件夹的创建删除等

在这里插入图片描述

4.listFiles()方法介绍

在这里插入图片描述

        File[] files = dir.listFiles();
        for(File file : files){
            System.out.println(file);
        }

注意:
1、指定的目录必须是存在
2、指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException


二、流

关键字
input 输入 output 输出 stream 流 writer 字符输入流 reader 字符输入流 File 文件
只要会了字节流就都会了
字节流能处理一切

有诗曰:输入还是输出?字符还是字节?

流的分类表

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream

转换流能都将字符流转成字节流

1.字节流

1.1、字节输出流OutputStream

输出流中定义都是写write方法
在这里插入图片描述

1.11、FileOutputStream类

给文件续写、换行

        File file = new File("c:\\file.txt");
        // 第二个参数 传入true
        FileOutputStream fos = new FileOutputStream(file, true); 
        String str = "\r\n" +"换行内容";
        fos.write(str.getBytes());
1.2、字节输入流InputStream

在这里插入图片描述

1.21、读写数据read(byte[])方法
        FileOutputStream fos = new FileOutputStream(destFile);
        // 缓冲区,临时数组容器
        byte[] buf = new byte[1024];//长度定义成1024的整数倍        
        int len = 0;
        while((len=fis.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
            // 将数组中的指定长度的数据写入到输出流中。
            fos.write(buf, 0, len);            
        }
        // 关闭资源。
        fos.close();

2、字符流

2.1.字符编码表

编码表:其实就是生活中字符和计算机二进制的对应关系表。
1、ASCII: 一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx
2、iso-8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx 负数。
3、GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节第一个字节是负数,第二个字节可能是正数

  • GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0

  • GB18030:最新的中文码表,目前还没有正式使用。

4、unicode:国际标准码表:无论是什么文字,都用两个字节存储。

  • Java中的char类型用的就是这个码表。char c = 'a';占两个字节。
  • Java中的字符串是按照系统默认码表来解析的。简体中文版 字符串默认的码表是GBK。

5、UTF-8:基于unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)。

能识别中文的码表:GBK、UTF-8;正因为识别中文码表不唯一,涉及到了编码解码问题。

对于我们开发而言;常见的编码 GBK UTF-8 ISO-8859-1

编码与解码:
文字--->(数字) :编码。 “abc”.getBytes() byte[]
(数字)--->文字 : 解码。 byte[] b={97,98,99} new String(b)
2.2.FileReader读取包含中文的文件
FileReader fr = new FileReader("D:\\test\\cn.txt");
    int ch = 0;
    while((ch = fr.read())!=-1){
        //输出的字符对应的编码值
        System.out.println(ch);
        //输出字符本身
        System.out.println((char)ch);
    }

FileOutputStream fos = new FileOutputStream("D:\\test\\cn.txt");
        fos.write("文字".getBytes());
        fos.close();
2.3.flush()和close()的区别

在这里插入图片描述
flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用
close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。


3.转换流

字符流与字节流之间的桥梁


OutputStreamWriter流对象,如何把字符转成字节输出的呢?

其实在OutputStreamWriter流中维护自己的缓冲区,当我们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。


//创建读取文件的字节流对象
        InputStream in = new FileInputStream("c:\\ccf.txt");
        //创建转换流对象 
        //InputStreamReader isr = new InputStreamReader(in);这样创建对象,会用本地默认码表读取,将会发生错误解码的错误
        InputStreamReader isr = new InputStreamReader(in,"utf-8");
        //使用转换流去读字节流中的字节
        int ch = 0;
        while((ch = isr.read())!=-1){
            System.out.println((char)ch);
        }
        //关闭流
        isr.close();

注意:在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。


总结:
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader(我们需要字符
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter(文件需要字节


4.缓冲流

Java中提供了一套缓冲流,它的存在,可提高IO流的读写速度

4.1.字节缓冲流

字节缓冲流根据流的方向,共有2个

  • 写入数据到流中,字节缓冲输出流 BufferedOutputStream
  • 读取流中的数据,字节缓冲输入流 BufferedInputStream

内部都包含了一个缓冲区通过缓冲区读写,就可以提高了IO流的读写速度

4.11 字节缓冲输出流BufferedOutputStream
/*
     * 写数据到文件的方法
     * 1,创建流
     * 2,写数据
     * 3,关闭流
     */
    private static void write() throws IOException {
        //创建基本的字节输出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt");
        //使用高效的流,把基本的流进行封装,实现速度的提升
        BufferedOutputStream out = new BufferedOutputStream(fileOut);
        //2,写数据
        out.write("hello".getBytes());
        //3,关闭流
        out.close();
    }
4.12.字节缓冲输入流 BufferedInputStream
/*
     * 从文件中读取数据
     * 1,创建缓冲流对象
     * 2,读数据,打印
     * 3,关闭
     */
    private static void read() throws IOException {
        //1,创建缓冲流对象
        FileInputStream fileIn = new FileInputStream("abc.txt");
        //把基本的流包装成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn);
        //2,读数据
        int ch = -1;
        while ( (ch = in.read()) != -1 ) {
            //打印
            System.out.print((char)ch);
        }
        //3,关闭
        in.close();
    }
4.2.字符缓冲流
4.2.1字符缓冲输出流 BufferedWriter

void newLine() 根据当前的系统,写入一个换行符

/*
 * BufferedWriter 字符缓冲输出流
 * 方法
 *     public void newLine()写入一个行分隔符
 * 
 * 需求: 通过缓冲输出流写入数据到文件
 * 分析:
 *     1,创建流对象
 *     2,写数据
 *     3,关闭流
 * 
 */
public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        //创建流
        //基本字符输出流
        FileWriter fileOut = new FileWriter("file.txt");
        //把基本的流进行包装
        BufferedWriter out = new BufferedWriter(fileOut);
        //2,写数据
        for (int i=0; i<5; i++) {
            out.write("hello");
            out.newLine();
        }
        //3,关闭流
        out.close();
    }
}
4.2.2字符缓冲输入流 BufferedReader

public String readLine()
读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

/*
 * BufferedReader 字符缓冲输入流
 * 
 * 方法:
 *     String readLine() 
 * 需求:从文件中读取数据,并显示数据
 */
public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        //1,创建流
        BufferedReader in = new BufferedReader(new FileReader("file.txt"));
        //2,读数据
        //一次一个字符
        //一次一个字符数组
        //一次读取文本中一行的字符串内容
        String line = null;
        while( (line = in.readLine()) != null ){
            System.out.println(line);
        }
        
        //3,关闭流
        in.close();
    }
}

流的总结:

四个明确:

  • 明确一:要操作的数据是数据源还是数据目的。

       源:InputStream      Reader
       目的:OutputStream   Writer

先根据需求明确要读,还是要写。

  • 明确二:要操作的数据是字节还是文本呢?

       源:
           字节:InputStream
           文本:Reader
       目的:
           字节:OutputStream
           文本:Writer

明确具体的体系。

  • 明确三:明确数据所在的具体设备。

       源设备:
           硬盘:文件  File开头。
           内存:数组,字符串。
           键盘:System.in;
           网络:Socket
       目的设备:
           硬盘:文件  File开头。
           内存:数组,字符串。
           屏幕:System.out
           网络:Socket

要使用哪个流对象

  • 明确四:是否需要额外功能呢?

       额外功能:
           转换吗?转换流。InputStreamReader OutputStreamWriter
           高效吗?缓冲区对象。BufferedXXX
    

三个过程

  • 向文件中写入数据的过程

       1,创建输出流对象
       2,写数据到文件
       3,关闭输出流
    
  • 从文件中读数据的过程

       1,创建输入流对象
       2,从文件中读数据
       3,关闭输入流
    
  • 文件复制的过程

       1,创建输入流(数据源)
       2,创建输出流(目的地)
       3,从输入流中读数据
       4,通过输出流,把数据写入目的地
       5,关闭流
    

三、小案例

1、文件的基本操作

@Test
public void testFile() throws Exception{
//创建文件
File file = new File("E:\\test\\b.txt");
file.createNewFile();
//查看文件夹下的文件
File file2 = new File("E:\\test\\b.txt");
String[] list = file2.list();
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
} 
}

2、复制文件带有进度条

@Test
public void testFileInputStream() throws Exception {
File file = new File("E:\\test\\a\\233.mp4");
//拿到文件的大小
long dataLength = file.length();
//构建一个输入流,他的数据要流入内存,咱们的程序
InputStream inputStream = new FileInputStream(file);
//构建一个输出流,他的数据要从内存(咱们的程序)流到另一个文件夹
OutputStream outputStream = new FileOutputStream("E:\\test\\b\\233.mp4");
//新建一个水泵,能存一点水,每次对对1k
byte[] buffer = new byte[1024 *1024*50];
Long currentLength = 0L;
//如果read返回-1说明读完了
int len;
int showNumber = 0;
while ( (len = inputStream.read(buffer)) != -1 ){
outputStream.write(buffer,0,len);
currentLength += len;
//当下加载了百分之多少
int currentPer = (int)(((double)currentLength/dataLength)*100);
//目的是不重复显示
if(showNumber != currentPer){
showNumber = currentPer;
System.out.println("已经拷贝了百分之" + showNumber);
}
}
outputStream.flush();
outputStream.close();
inputStream.close();
}

3、字节流读文件

@Test
public void testInputStream() throws Exception{
//怼了一个输入流到文件上
InputStream wordInput = new FileInputStream("E:\\test\\a\\word.txt");
//建立缓冲区
byte[] bytes = new byte[1024];
int len;
while ( (len = wordInput.read(bytes)) != -1 ){
System.out.println(new String(bytes,0,len, Charset.forName("ISO8859-1")));
} 
wordInput.close();
}

4、字符流对文件

@Test
public void testReader() throws Exception{
//怼了一个输入流到文件上
Reader reader = new FileReader("E:\\test\\a\\word.txt");
BufferedReader br = new BufferedReader(reader);
String str;
while ((str = br.readLine()) != null){
System.out.println(str);
} 
reader.close();
br.close();
}

5、向文件里写内容

@Test
public void testWriter() throws Exception{
//怼了一个输入流到文件上
Writer writer = new FileWriter("E:\\test\\a\\writer.txt");
BufferedWriter bw = new BufferedWriter(writer);
Scanner scanner = new Scanner(System.in);
while (true){
System.out.print("请输入:");
String words = scanner.next();
bw.write(words);
bw.flush();
}
}

6、StringReader就是往String上怼

@Test
public void testStringReader() throws Exception{
//怼了一个string
OutputStream os = new FileOutputStream("E:\\test\\a\\user.txt");
ObjectOutput oo = new ObjectOutputStream(os);
oo.writeObject(new User("小航",3,4));
oo.flush();
oo.close();
os.close();
}

四:小实验-下载网易云音乐

step1:
https://music.163.com/
进入官网,随便搜首歌曲
在这里插入图片描述
step2:进入页面,打开开发者工具(浏览器F12),选择network
在这里插入图片描述
step3:选择media过滤,选择一个有效链接
https://m701.music.126.net/20210714161041/4fa28b697be05c47052a5b51039e5668/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/5755656629/2ce0/caf3/9e65/4e8df6c581219b094bdce6db938379be.m4a

在这里插入图片描述
step4:打开ideal,创建一个class文件Url

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * @author xh
 */
public class Url {

    // 文件基本路劲
    private static final String BASE_URL = "C:\\Users\\Administrator\\Desktop\\homework\\";

    public static void main(String[] args) throws Exception{
        download("https://m701.music.126.net/20210714161041/4fa28b697be05c47052a5b51039e5668/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/5755656629/2ce0/caf3/9e65/4e8df6c581219b094bdce6db938379be.m4a");
    }

    /**
     * 下载方法
     */
    private static void download(String path) throws IOException {
        System.out.println("文件开始下载!");
        // 创建一个url对象
        URL url = new URL(path);
        // 打开和网络的连接,拿到流对象
        InputStream inputStream = url.openStream();
        // 获取文件名(从最后一个 / 截取字符串)
        String fileName = url.getFile().substring(url.getFile().lastIndexOf("/") + 1);
        System.out.println(url.getFile().substring(url.getFile().lastIndexOf("/") + 1));
        File file = new File(BASE_URL + fileName);
        boolean newFile = file.createNewFile();
        if(newFile){
            FileOutputStream outputStream = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len;
            while((len = inputStream.read(buf)) != -1){
                outputStream.write(buf,0,len);
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();

            System.out.println("文件下载成功!");
        }else{
            System.out.println("文件下载失败!");
        }
    }
}
相关文章
|
1月前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
251 3
|
3月前
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
220 5
|
21天前
|
前端开发 Java 数据库连接
帮助新手快速上手的 JAVA 学习路线最详细版涵盖从入门到进阶的 JAVA 学习路线
本Java学习路线涵盖从基础语法、面向对象、异常处理到高级框架、微服务、JVM调优等内容,适合新手入门到进阶,助力掌握企业级开发技能,快速成为合格Java开发者。
268 3
|
1月前
|
NoSQL Java 关系型数据库
Java 从入门到进阶完整学习路线图规划与实战开发最佳实践指南
本文为Java开发者提供从入门到进阶的完整学习路线图,涵盖基础语法、面向对象、数据结构与算法、并发编程、JVM调优、主流框架(如Spring Boot)、数据库操作(MySQL、Redis)、微服务架构及云原生开发等内容,并结合实战案例与最佳实践,助力高效掌握Java核心技术。
218 1
|
1月前
|
Java 测试技术 API
Java IO流(二):文件操作与NIO入门
本文详解Java NIO与传统IO的区别与优势,涵盖Path、Files类、Channel、Buffer、Selector等核心概念,深入讲解文件操作、目录遍历、NIO实战及性能优化技巧,适合处理大文件与高并发场景,助力高效IO编程与面试准备。
|
1月前
|
Java 编译器 API
Java Lambda表达式与函数式编程入门
Lambda表达式是Java 8引入的重要特性,简化了函数式编程的实现方式。它通过简洁的语法替代传统的匿名内部类,使代码更清晰、易读。本文深入讲解Lambda表达式的基本语法、函数式接口、方法引用等核心概念,并结合集合操作、线程处理、事件回调等实战案例,帮助开发者掌握现代Java编程技巧。同时,还解析了面试中高频出现的相关问题,助你深入理解其原理与应用场景。
|
12天前
|
Java API 数据库
2025 年最新 Java 实操学习路线,从入门到高级应用详细指南
2025年Java最新实操学习路线,涵盖从环境搭建到微服务、容器化部署的全流程实战内容,助你掌握Java 21核心特性、Spring Boot 3.2开发、云原生与微服务架构,提升企业级项目开发能力,适合从入门到高级应用的学习需求。
235 0
|
22天前
|
监控 Java API
2025 年全新出炉的 Java 学习路线:从入门起步到实操精通的详细指南
2025年Java学习路线与实操指南,涵盖Java 21核心特性、虚拟线程、Spring Boot 3、微服务、Spring Security、容器化部署等前沿技术,助你从入门到企业级开发进阶。
189 0
|
1月前
|
前端开发 Java 数据库
Java 项目实战从入门到精通 :Java Web 在线商城项目开发指南
本文介绍了一个基于Java Web的在线商城项目,涵盖技术方案与应用实例。项目采用Spring、Spring MVC和MyBatis框架,结合MySQL数据库,实现商品展示、购物车、用户注册登录等核心功能。通过Spring Boot快速搭建项目结构,使用JPA进行数据持久化,并通过Thymeleaf模板展示页面。项目结构清晰,适合Java Web初学者学习与拓展。
181 1
|
1月前
|
算法 Java 测试技术
零基础学 Java: 从语法入门到企业级项目实战的详细学习路线解析
本文为零基础学习者提供完整的Java学习路线,涵盖语法基础、面向对象编程、数据结构与算法、多线程、JVM原理、Spring框架、Spring Boot及项目实战,助你从入门到进阶,系统掌握Java编程技能,提升实战开发能力。
110 0