Java基础课的中下基础课05
目录
(3)用BufferedReader和BufferedWriter做登录
(1)ObjectInputStream / ObjectOutputStream
二十五、IO之File类及常用方法
25.1 什么是I/O
I/O相关(输入/输出)流(数据流动)
数据流动的方向,读数据(输入Input) 写数据(输出output)
25.2 什么是文件
文件:一种电脑的存储形式,文件有不同的格式:.txt .doc .ppt .mp4 .jpg .zip等...
文件夹:是目录或路径
(1)为什么用文件存储
1、变量 只能存一份
2、数组 存储好多个 数据类型统一
3、集合 存储好多个 存储后个数还能改变 泛型----数据类型统一
如上三个都是Java中的类型(对象)-----------都存储在内存里,那么程序执行完毕,虚拟机jvm停止的时候,内存空间就回收了,数据都是临时性存储的。
4、文件 存储好多信息 文件是存储在硬盘上的-------都是永久性保存,数据虽然安全,但是文件毕竟不在内存中,需要通过I/O操作文件
25.3 File类
File:与电脑上的文件或文件夹产生一一对应的映射关系
File:是个类,在java.io中,可以表示文件或目录路径名(文件夹)的抽象形式,File与真实硬盘中的文件或文件夹,不是一个东西
File是在内存中的一个对象<---映射--->硬盘上的文件或文件夹,产生一个映射关系,互相映射
canRead() canWrite() isHidden() isFile()
isDirectory() 判断当前的file是否是一个目录(文件)
length() 获取文件中字节的个数
lastMondified() 获取文件最后的修改时间----毫秒值
String path = getAbsolutePath() 获取文件的绝对路径,绝对路径可以通过完整的字符串,定位盘符、文件夹、文件;
相对路径没有盘符的写法,当前工程(项目)所在的位置找寻
String name = getName() 获取文件的名字
boolean = createNeswFIle() 创建新的文件
boolean = mkdir() 创建新的文件夹,外层没有,不能创建
boolean = mkdirs() 创建新的文件夹,外层没有,可以自动创建
String name = getParent() 获取当前file的父亲file名字
File file = getParentFile() 获取当前file的父亲file对象
String[] names = list() 获取当前file的所有儿子的名字(只有文件夹可以调用,文件调用就是空的,只有文件夹才会有儿子)
File[] files = listFiles() 获取当前file的所有儿子的对象
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
?
/**
* @Author: Insight
* @Description: TODO 操作File类
* @Date: 2023/11/3 20:25
* @Version: 1.0
*/
public class TestFile {
? ?public static void main(String[] args) {
?
? ? ? ?//File类没有无参构造函数,也就是创建对象时参数不能为空
? ? ? ?File file = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//Test.txt");
? ? ? ?//file对象 是真实的文件吗? 不是
? ? ? ?//file对象在堆内存中,创建出来的一个对象空间
? ? ? ?//路径是看创建的对象,是否能与硬盘中的一个真实文件产生对应映射关系
? ? ? ?//通过文件流去读取文件的内容
? ? ? ?//系统内硬盘上的文件的名字,是不区分大小写的,内存中File对象,变量名字区分大小写
?
? ? ? ?//文件本身的一些属性 --->
? ? ? ?//如果test.txt是否能打开,
? ? ? ?System.out.println(file.canExecute());//true
? ? ? ?//如果test.txt可写就true,否则false
? ? ? ?System.out.println(file.canRead());//true
? ? ? ?System.out.println(file.canWrite());//true
? ? ? ?//文件是否隐藏
? ? ? ?System.out.println(file.isHidden());//false
? ? ? ?//判断当前的file是否是一个文件
? ? ? ?System.out.println(file.isFile());//true
? ? ? ?//判断当前的file是否是一个目录(文件)
? ? ? ?System.out.println(file.isDirectory());//false
System.out.println("==============================================================");
?
? ? ? ?//文件的大小是多少
? ? ? ?//Array.length List.size() String.length() File.length()
? ? ? ?long l = file.length();
? ? ? ?System.out.println(l);//0
System.out.println("==============================================================");
?
? ? ? ?//获取文件最后修改时间
? ? ? ?long time = file.lastModified();//毫秒的 看不懂可以格式化一下
? ? ? ?Date date = new Date(time);
? ? ? ?SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd KK:mm:ss");
? ? ? ?System.out.println(sdf.format(date));//2023-11-04 09:57:39
System.out.println("==============================================================");
?
? ? ? ?//修改文件的时间
? ? ? ?file.setLastModified(time);
System.out.println("==============================================================");
?
? ? ? ?//获取文件的名字
? ? ? ?String name = file.getName();//Test.txt
System.out.println("==============================================================");
?
? ? ? ?//获取文件的绝对路径
? ? ? ?String path = file.getAbsolutePath();
? ? ? ?System.out.println(path);//D:\IDEA_JavaCode\Duyi\JavaBasics05\TestFile\Test.txt
System.out.println("==============================================================");
?
? ? ? ?//获取文件的相对路径,通常是用相对路径,自动找到跟目录
? ? ? ?File file2 = new File("TestFile\\Test.txt");
? ? ? ?String path2 = file2.getAbsolutePath();
? ? ? ?System.out.println(path2);//D:\IDEA_JavaCode\Duyi\JavaBasics05\TestFile\TestFil\Test.txt
System.out.println("==============================================================");
?
? ? ? ?//创建一个file对象
? ? ? ?File file1 = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//Test02.txt");
? ? ? ?//文件夹是不占空间的,占内存的是文件,是文件夹中的文件,所以文件夹是没有异常的
? ? ? ?//通过这个对象,回头在硬盘上,创建文件,如果文件盘符写错了,他就真写不了了
? ? ? ?try{
? ? ? ? ? ?boolean value = file1.createNewFile();//编译时异常
? ? ? ? ? ?System.out.println(value);//true
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
System.out.println("==============================================================");
?
? ? ? ?//创建file对象
? ? ? ?File file3 = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//Test03");
? ? ? ?//在硬盘上,创建一个新的文件夹,文件夹的创建是没有什么异常的
? ? ? ?//文件夹是不占空间的,占内存的是文件,是文件夹中的文件,所以文件夹是没有异常的
? ? ? ?boolean value = file3.mkdir();
? ? ? ?System.out.println(value);//true
?
? ? ? ?File file4 = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//Test04//inter.txt");
? ? ? ?boolean b2 = file4.mkdir();//外层(父元素)需要真实存在才能创建(Test04)
? ? ? ?System.out.println(b2);//false
? ? ? ?boolean b = file4.mkdirs();//可以创建文件夹,如果外层没有,也会同时创建文件夹
? ? ? ?System.out.println(b);//true
System.out.println("==============================================================");
?
? ? ? ?File file5 = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//inter");
? ? ? ?String pname = file5.getParent();//当前file的父亲名字 只是名字 TestFile
? ? ? ?//这个用的多一点开发
? ? ? ?File pfile = file5.getParentFile();//当前file的父亲对象 file----表示D盘IDEA_JavaCode//Duyi//JavaBasics05//TestFile//文件夹下的对象
? ? ? ?System.out.println(pname);
? ? ? ?System.out.println(pfile.getAbsolutePath());
System.out.println("==============================================================");
?
? ? ? ?//遍历当前file的所有父目录
? ? ? ?File files = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//Test.txt");
? ? ? ?//想通过循环的方式看到这个文件往上的每一层关系
? ? ? ?File pfiles = files.getParentFile();//获取它的父亲
? ? ? ?while (pfiles != null) {//等于null说明是盘符
? ? ? ? ? ?System.out.println(pfiles.getAbsolutePath());//先输出自己的父亲是谁
? ? ? ? ? ?pfiles = pfiles.getParentFile();//再找一遍,找父亲的父亲
? ? ? }
System.out.println("==============================================================");
?
? ? ? ?File filess = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile");
? ? ? ?//数组对象为空,证明当前的file是一个文件
? ? ? ?//数组对象不文空,证明当前的file是一个文件夹
? ? ? ?//如果数组对象的长度不为0,证明当前的file是一个不为空的文件夹,文件夹内有元素
? ? ? ?File[] file0 = filess.listFiles();
? ? ? ?System.out.println(file0);
? ? ? ?System.out.println(file0.length);
System.out.println("==============================================================");
?
? ? ? ?//遍历当前file的子元素需要通过while循环,那么如果当前file的子元素中还有子元素又需要while循环,所以遍历子元素不能和父元素一样
? ? ? ?File file00 = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile//Test02.txt");
? ? ? ?boolean bb = file.delete();//不能瞎玩啊
? ? ? ?System.out.println(bb);
System.out.println("==============================================================");
?
? ? ? ?
? }
}
? 如果把下面的属性改了,上面的代码就会跟随你文件属性进行改变
25.4 什么叫流,做什么?
流:就是操作文件中的内容
输入流:读取文件中的内容
输出流:向文件中写内容
比如:文件的复制和文件的加密
二十六、IO之文件夹遍历删除(递归)
26.1递归的理解
1、文件夹的遍历----需要一个递归来完成
public class TestMethod {
? ?public void testOne() {
? ? ? ?this.testTwo();
? ? ? ?System.out.println("我是testOne方法");
? }
? ?public void testTwo() {
? ? ? ?this.testThree();
? ? ? ?System.out.println("我是testOne方法");
? }
? ?public void testThree() {
? ? ? ?this.testOne();
? ? ? ?System.out.println("我是testOne方法");
? }
? ?public static void main(String[] args) {
? ? ? ?TestMethod tm = new TestMethod();
? ? ? ?//调用One,One等Two做完在做事,Two等Three做完在做,所以Three最先做,然后在Two、One
? ?/*
? ? ? ?临时执行testOne(1.调用TestTwo 2.自己的执行;未销毁因为还未执行完)
? ? ? ?临时执行testTwo(1.调用TestThree 2.自己的执行;未销毁因为还未执行完)
? ? ? ?临时执行testThree(1.自己的执行;执行完销毁)
? ? ? ?本质上就是递归
? ?*/
? ? ? ?tm.testOne();
? }
}
理解递归:
public class TestRecursion {
? ?//建房子
? ?//递归思想:如果你想让我做事(让我盖第五层),只盖第5层,所以我要求别人先把前四层盖好了我才盖(5等4,4等3)
? ?//调用顺序是从上到下的,执行顺序是从下到上的;1、让别人先做事;2、我自己做事
? ?//5 等4做完 ---执行
? ?//4 等3做完 ---执行
? ?//3 等2做完 ---执行
? ?//2 等1做完 ---执行
? ?//1 不等 ---直接执行
? ?public void buildHouse(int floor) {//5层
? ? ? ?//判断当前floor是否为1,若不是找一个别人先盖之前的层
? ? ? ?if (floor > 1) {
? ? ? ? ? ?this.buildHouse(floor-1);
? ? ? }
? ? ? ?//2、我自己做事
? ? ? ?System.out.println("盖到第" + floor + "层了");
? }
?
? ?public static void main(String[] args) {
? ? ? ?TestRecursion testRecursion = new TestRecursion();
? ? ? ?testRecursion.buildHouse(5);
? }
}
26.2 文件夹遍历删除
递归不是一层一层找的,而是一个分支一直找到底
public class NewTestFile {
? ?//方法:用来展示(遍历)文件夹;参数-file(代表文件或文件夹)
? ?//递归不是一层一层找的,而是一个分支一直找到底
? ?public void showFile(File file) {
? ? ? ?
? ? ? ?//1.判断file是否一个文件夹,文件夹内如果有元素,找一个人先做
? ? ? ?//获取file的子元素,files==nul是个文件,files!=null是个文件夹,files.length!=是一个带元素的文件夹
? ? ? ?File[] files = file.listFiles();//src文件夹所有子元素
? ? ? ?if (files != null && files.length != 0) {
? ? ? ? ? ?for(File f:files) {//将每一个子元素都找人遍历一遍
? ? ? ? ? ? ? ?this.showFile(f);//循环第一次 src文件夹中的test 第二次 test文件夹中的test.html
? ? ? ? ? }
? ? ? }
? ? ? ?
? ? ? ?//2.做自己的显示(file是文件或file是一个空文件夹),放前面运行和放后面运行不一样
? ? ? ?System.out.println(file.getAbsolutePath());
? }
?
? ?public static void main(String[] args) {
? ? ? ?NewTestFile newTestFile = new NewTestFile();
? ? ? ?File file = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02//Test");
? ? ? ?newTestFile.showFile(file);//找到src中的所有子
? }
}
递归删除文件夹中的子元素,别瞎玩
public static void main(String[] args) {
? ?NewTestFile newTestFile = new NewTestFile();
? ?File file = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02//Test");
? ?newTestFile.deleteFile(file);//删除之后回收站也没有。别瞎玩
}
?
public void deleteFile(File file) {
? ?//判断file不是空文件夹,找人先做事
? ?File[] files = file.listFiles();
? ?if (file != null && files.length != 0) {
? ? ? ?for (File f:files) {
? ? ? ? ? ?this.deleteFile(f);
? ? ? }
? }
? ?//删除file(file是个文件或file是一个空文件夹)
? ?file.delete();
}
1、文件夹的遍历、文件夹的删除----需要一个递归
2、文件夹的路径---循环
二十七、字节型文件流
27.1 流
file对象不能操作文件中的内容--------需要通过I/O的方式来完成
流 按照方向(功能)来区分:in(读取) out(写入)
操作的目标来区分:文件流、数组流、字符串流、数据流、对象流、网络流....
学习文件流:读取文件中的信息in,将信息写入文件中out;
文件流按照读取或写入的单位(字节数)大小来区分:
(1)字节型文件流(1字节) FileInputStream / FileOutputStream
(2)字符型文件流(2字节~1字符) FileReader / FileWriter
27.2 字节型文件流(1字节)
(1)字节型文件输入流FileInputStream
FileInputStream
(1)java.io
(2)了解继承:InputStream类,字节型输入流的父类
(3)创建对象:调用一个带file类型的构造方法、调用一个带String类型的构造方法
(4)常用方法:
int code = read(); 每次从流管道中读取一个字节,返回的是字节的code码
int count = read( byte() ); 每次从n流管道中读取若干个字节,存入数组内,返回有效元素个数
?
public static void main(String[] args){
? ? ? ?//理解为:文件是一个仓库,fis对象搬运工,推一个平板车
? ? ? ?try{
? ? ? ? ? ?//创建一个字节型的文件输入流,读取一个文件中内容
? ? ? ? ? ?File file = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + "//Test//aaa//02.txt");
?
? ? ? ? ? ?FileInputStream fis = new FileInputStream(file);//真实去读文件,如果没有此文件就会报错,所以我们可以try
?
? ? ? ? ? ?int i = fis.read(); //读取一个字节 -1,i表示这一个字节的code码,每次只能读一个字节太慢了
? ? ? ? ? ?System.out.println(i);//97
? ? ? ? ? ?//有可能读不到第一个字节
? ? ? ? ? ?while (i != -1) {//知道最后读完
? ? ? ? ? ? ? ?System.out.print((char)i);//读取的字节的UniCode码 0~65535
? ? ? ? ? ? ? ?i = fis.read(); //读取下一行的一个字节 -1
? ? ? ? ? }
?
? ? ? } catch (FileNotFoundException e){
? ? ? ? ? ?e.printStackTrace();
? ? ? } catch (IOException e){
? ? ? ? ? ?e.printStackTrace();
? ? ? }
? }
public static void main(String[] args) {
? ? ? ?try {
?
? ? ? ? ? ?FileInputStream fis = new FileInputStream("D://IDEA_JavaCode//Duyi//JavaBasics05"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?+ "//TestFile02//Test//aaa//02.txt");
? ? ? ? ? ?//创建一个空的数组(不是去数组里读东西,目的是去文件里读东西,然后把东西装入数组内)
? ? ? ? ? ?//利用一个数组从文件中读东西,装数组里,再拿这个数组给他显示出来
? ? ? ? ? ?byte[] b = new byte[5];//每次存储5个字节
? ? ? ? ? ?int count = fis.read(b);//去文件里读东西(读5个),装入数组b内,返回int型count表示读取到的有效字节个数
? ? ? ? ? ?System.out.println("有效字节个数count = " + count);//5
? ? ? ? ? ?while (count != -1) {
? ? ? ? ? ? ? ?//把数组构建成一个String在展示出来
? ? ? ? ? ? ? ?//String value = new String(b);
? ? ? ? ? ? ? ?//第一次 ? a b c d e
? ? ? ? ? ? ? ?//第二次 ? f g \r \n h count=5将第一次的元素覆盖
? ? ? ? ? ? ? ?//3 ? ? ? i j k l m .....
? ? ? ? ? ? ? ?//4 ? ? ? n \r \n o p .....
? ? ? ? ? ? ? ?//5 ? ? ? q \r \n o p count=1,此时的数组内还有第4次的元素,但是第5次就一个元素只能覆盖第4次的第一个元素
? ? ? ? ? ? ? ?//就是构建String出来问题,每次都构建5给元素的位置,最后一行没有5个元素,我们应该有几个元素就构建几个空间
?
? ? ? ? ? ? ? ?//把数组构建成一个String在展示出来
? ? ? ? ? ? ? ?String value02 = new String(b,0,count);//从索引0构建count个空间
? ? ? ? ? ? ? ?System.out.print(value02);
? ? ? ? ? ? ? ?//在读一遍,读下一行
? ? ? ? ? ? ? ?count = fis.read(b);
? ? ? ? ? }
? ? ? }catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
? }
int count = available(); 返回流管道中还有多少缓冲的字节数(就是fis对象与硬盘之间有一个流管道,这个管道进行一一映射,其中这个管道中有流动的数据(元素),available()用于获取流动的元素)
long l = skip( long n ); 跳过几个字节在读取,多线程----利用几个线程同时读取文件(1000字节,5个人同时读取;第一个人读1~200;第二个人2001~400....)
close(); 将流管道关闭,必须要做的事,最好放在finally里,注意代码的健壮性,判断严谨
? ?public static void main(String[] args) {
? ? ? ?//先定义为空,因为new File有可能是空文件夹或没有此文件,会报异常(new的过程才会产生异常)
? ? ? ?//,所以真正的文件或文件夹还是要在try中
? ? ? ?FileInputStream fis = null;
? ? ? ?try {
? ? ? ? ? ?fis = new FileInputStream(new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + "//Test//aaa//02.txt"));
? ? ? ? ? ?long l = fis.skip(5);
? ? ? ? ? ?System.out.println(l);
? ? ? ? ? ?int code = fis.read();
? ? ? ? ? ?System.out.println(code);
?
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//关闭的是流通道,不是file对象,关闭这件事情必须要做(如果不关闭就像你优盘不能退出一样
? ? ? ? ? ?//,当你点击退出时,显示您的设备正在打开)
? ? ? ? ? ?//所以关闭不能在try中如果前面的代码出现问题,这个close就不能执行了,try体系中finally
? ? ? ? ? ?//是必须执行的,所以放在finally
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?//fis在执行try后就不存在了,所以finally中变量fis就失效了(相当于未定义fis),所以要在try体系外定义fis,
? ? ? ? ? ? ? ?//但是你在外面给fis=null,这里的null空无法调用close方法,所以还要在这里定义一个try体系
? ? ? ? ? ? ? ?if (fis != null) {
? ? ? ? ? ? ? ? ? ?fis.close();//如果不为空,我最后就要关闭文件
? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?//如果是空,就没必要关闭了
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
?
? ? ? }
?
? }
(2)字节型文件输出流FileOutputStream
FileOutputStream 将数据写入文件中
(1)java.io
(2)继承OutputStream,所有字节型输出流的父类
(3)创建对象:1、调用一个带FIle参数,还有FIle,Boolean重载
2、调用一个带String参数,还有String,boolean重载
(4)常用方法
write(int code); 将给定code对应的字符写入文件
write( byte[] ); 将数组中的全部字节写入文件,可以用此方法getByte()将写好的字符串转化为byte数组
String str = "1+1=2"; byte[] b = str.getBytes();
close(); 注意在finally中关闭
flush(); 将管道内的字节推入文件中(刷新)
public static void main(String[] args) {
? ?FileOutputStream fos = null;
? ?try {
? ? ? ?//创建一个字节型文件输出流
? ? ? ?File file = new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?+ "//Test//test00//test.txt");
? ? ? ?//如果创建的是文件输入流,若文件路径有问题,则抛出异常 FileNotFoundException(输入读)
? ? ? ?//若创建是输出流,他是输出写入,若文件路径有问题,则直接帮我们创建一个新的文件(文件夹路径写错就不行)
? ? ? ?fos = new FileOutputStream(file);
? ? ? ?//我们写的a是写在了流管道里面了(第一次run执行a写入了txt文件中)
? ? ? ?//fos.write(97);
? ? ? ?//这时我们在写一个b,但是打开text文件中发现上次写入的a被这次的b覆盖了(第二次run),其实是构建的事FileOutputStream(file)
? ? ? ?//它每次都创建一个新的file对象,然后覆盖了你之前的txt文件,如果想追加内容需要FileOutputStream(file,true)利用构造方法
? ? ? ?fos.write(98);
? ? ? ?//刷新,将管道中的字节,推入文件中
? ? ? ?fos.flush();
? ? ? ?System.out.println("写入完毕");
? } catch (IOException e) {
? ? ? ?e.printStackTrace();
? } finally {
? ? ? ?try {
? ? ? ? ? ?if (fos != null) {
? ? ? ? ? ? ? ?fos.close();
? ? ? ? ? }
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
? }
?
}
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//创建一个字节型文件输出流
fos = new FileOutputStream("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02"
+ "//Test//test00//test.txt",true);
//创建一个数组(带信息的)
//byte[] b = new byte[]{97,98,99};
String str = "1+1=2";
byte[] b = str.getBytes();
fos.write(b);//将信息写入
fos.flush();//刷新
System.out.println("写入完毕");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
(3)小总
字节型文件流:FileInputStream、FileOutputStream
(1)所在的包java.io
(2)各自继承关系InputStream / OutStream
(3)构造方法
利用file对象构造 new FileInputStream( file ); new OutputStream( file, true );
利用String对象构造 new FileInputStream( " " ); new OutputStream( " " ,true);
27.3 小任务文件夹复制
(1)文件的复制
public class OperateFile {
public void copyFile(File file, String path) {
FileInputStream fis = null;
FileOutputStream fos = null;
try{
//创建输入流
fis = new FileInputStream(file);
//创建新的file对象,用于操作复制
File newFile = new File(path + "//" + file.getName());
//给新file创建输出流
fos = new FileOutputStream(newFile);
//读取文件,不可能一次读完,所以循环
byte[] b = new byte[1024];//每次读取 1kb~8kb之间
int count = fis.read(b);//每次1024个字节,最后一行没有1024,那么默认值是0,所以
//循环读取
while (count != -1) {
//可以在这里做点手脚,比如加密
//要将读取到的有效字节 写入,利用构造方法
fos.write(b,0,count);
fos.flush();
count = fis.read(b);//在读
}
System.out.println("复制完毕");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭输入流
try{
if (fis != null) {
//输入流和输出流 各关各个,如果出现一次就会导致下一个未关闭
fis.close();
}
}catch (IOException e) {
e.printStackTrace();
}
//关闭输出流
try{
if (fos != null) {
//输入流和输出流 各关各个,如果出现一次就会导致下一个未关闭
fos.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
OperateFile of = new OperateFile();
of.copyFile(new File("D://IDEA_JavaCode//Duyi//JavaBasics05//TestFile02" +
"//Test//test.txt"), "D://IDEA_JavaCode//Duyi//JavaBasics05//" +
"TestFile02//Test02");
}
可以做点加密
如果想把加密完成的文件解密回去,首先将加密后的文件剪切到原路径下(把原路径下最开始的文件删除),然后在加密一次,也即是将元素在互换回去。
//循环读取
while (count != -1) {
//可以在这里做点手脚,比如加密,每一次数组的前两个元素位置互换 1024
byte temp = b[10];
b[0] = b[1];
b[1] = temp;
//要将读取到的有效字节 写入,利用构造方法
fos.write(b,0,count);
fos.flush();
count = fis.read(b);//在读
}
(2)文件夹的复制
//文件夹的复制 ,file可以表示文件 或者 文件夹
? ?public void superCopyFile(File file, String newPath) {
? ? ? ?//获取file(原文件)的绝对路径,拼串的方式获取新文件的名字
? ? ? ?String oldFilePath = file.getAbsolutePath();
? ? ? ?//按照冒号进行拆分(冒号没有了),只剩C和Test//aaa,[1]表示Test//aaa这一堆
? ? ? ?//将目标路径放在想复制的路径前面D://Test//bb复制到
? ? ? ?String newFilePath = newPath + oldFilePath.split(":")[1];
? ? ? ?//创建新的file对象
? ? ? ?File newFile = new File(newFilePath);
? ? ? ?//判断当前传递进来的file是个文件还是文件夹 isFile isDirectory listFiles直接找寻当前文件夹的子元素
? ? ? ?//获取当前传递进来的file对象的所以子元素
? ? ? ?File[] files = file.listFiles();
? ? ? ?//如果是文件夹,先把外层的文件夹复制过去,才能往里面写
? ? ? ?if (files != null) {//file不空说明是一个文件夹,才有数组对象
? ? ? ? ? ?//通过新的file对象操作,在硬盘上创建一个文件夹
? ? ? ? ? ?newFile.mkdir();//不用mkdirs因为这个file就一个,先把一个文件夹创建过去,下一次递归还是一个文件
? ? ? ? ? ?System.out.println(newFile.getName() + "文件夹复制完毕");
? ? ? ? ? ?//如果里面还有元素怎么办?递归
? ? ? ? ? ?//发现这个if什么时候会执行?是不是只有是文件夹的时候才会执行,文件是走的if 文件夹走下面else
? ? ? ? ? ?if (files != null && files.length != 0) {//证明里面还有东西
? ? ? ? ? ? ? ?//里面有子文件或文件夹,就在调用
? ? ? ? ? ? ? ?for (File f:files) {
? ? ? ? ? ? ? ? ? ?this.superCopyFile(f,newPath);
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? } else {//file是一个文件,没有子元素,不需要数组对象
? ? ? ? ? ?//创建两个文件流,分别读取旧的file和写入新的newFile
? ? ? ? ? ?FileInputStream fis = null;
? ? ? ? ? ?FileOutputStream fos = null;
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?fis = new FileInputStream(file);
? ? ? ? ? ? ? ?fos = new FileOutputStream(newFile);
? ? ? ? ? ? ? ?byte[] b = new byte[1024];
? ? ? ? ? ? ? ?int count = fis.read(b);
? ? ? ? ? ? ? ?//循环读取
? ? ? ? ? ? ? ?while (count != -1) {
? ? ? ? ? ? ? ? ? ?//将有效字节读到就写入
? ? ? ? ? ? ? ? ? ?fos.write(b,0,count);
? ? ? ? ? ? ? ? ? ?fos.flush();
? ? ? ? ? ? ? ? ? ?//别忘记在读一边,将读来的信息进行覆盖
? ? ? ? ? ? ? ? ? ?count = fis.read(b);
? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?System.out.println(newFile.getName() + "文件复制完毕");
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? } finally {
? ? ? ? ? ? ? ?//关闭输入流
? ? ? ? ? ? ? ?try {
? ? ? ? ? ? ? ? ? ?if (fis != null) {
? ? ? ? ? ? ? ? ? ? ? ?fis.close();
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?//关闭输出流
? ? ? ? ? ? ? ?try {
? ? ? ? ? ? ? ? ? ?if (fos != null) {
? ? ? ? ? ? ? ? ? ? ? ?fos.close();
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? }
?
? }
//剪切思路也是差不多
public void 剪切(){
this.superCopyFile();
this.deleteFile()
}
二十八、字符型文件流
27.2 字符型文件流
(1)和上面的字节型文件流使用方法一样,就是byte数组变成char数字,字符型是为了识别汉字的
(2)只能操作纯文本的文件.txt
(3)创建字符流对象的时候,会产生编译时异常 FileNotFoundException
(1)FileReader输入流
(1)java.io包
(2)继承 InputStreamReader
(3)常用:int code = read(); int count = read(char[])
(2)FileWriter输出流
(1)java.io包
(2)继承 OutputStreamWriter
(3)常用:write(int); write(char[]); write(String); flush close
(4)构造方法:
带file参数; 带file,boolean参数; 带String参数; 带String,boolean参数
(3)字符集
字符集
字符:文字和符号总成(Character)
不同国家的数字和符号是一样的,字母
不同国家的文字(中文、日文、韩文)
计算机最早产生是按照英文单词,单个字符设计的;字母、数字、符号--------1字节、8bit、256
如果计算机想要处理上述字母符号以外的其他字符--比如中文2字节,需要将中文进行字符编码----拆分和组合
拆分组合的规则------所谓的字符编码
平台(操作系统)默认字符集GBK,Linux(MacOs)默认字符集UTF-8
编译使用的开发环境 Idea---UTF-8 Eclipse---GBK
所以我们怎么才能让中文不出现乱码,我们改平台的字符集是比较麻烦的,所以我们改编译器的字符集
设置默认字符集为UTF-8
try{
//创建一个字符型文件输入流----一个字符
FileReader fr = new FileReader(new File("D://IDEA_JavaCode//Duyi//JavaBasics05" +
"//TestFile02//Test//test.txt"));
int code = fr.read();
System.out.println(code);//25105读出来的时候是以GBK的形式读取的
System.out.println((char)code);//我
} catch (IOException e) {
e.printStackTrace();
}
二十九、缓冲流
29.1 缓存流
文件流:FileInputStream/FileOutputStream、FileReader/FileWriter
缓冲流:为了在流管道内增加缓存的数据,让我们使用流读取的文字更加的流程
为了保证数据是源源不断的流出,而不是断断续续的,可以在管道的硬盘端变粗(增加缓存数据),让主干的数据远远大于流出的数据(这里就是将高级流去包装低级流,缓冲流也叫高级流,它的创建通过低级流来完成的),让我们使用流读取的文字更加的流程
缓冲流也叫高级流,它的创建通过低级流来完成的,缓冲流的创建它里面放的是FileInputStream、FileOutputStream、FileReader、FileWriter是这四个低级流,就是高级流BufferedInputStream/BufferedOutputStream、BufferedReader/BufferedWriter将前面四个包装起来了,但是后面四个的性能和效率更高,但是使用方法差不多
缓冲流:BufferedInputStream/BufferedOutputStream、BufferedReader/BufferedWriter
29.2 字节型缓存流
public static void main(String[] args) {
try {
/*TODO 高级流的构建方式需要使用低级流构建*/
FileInputStream fis = new FileInputStream(new File("D://IDEA_JavaCode//Duyi//JavaBasics05//" +
"TestFile02//Test//test.txt"));
BufferedInputStream bis = new BufferedInputStream(fis);//装入低级流
FileOutputStream fos = new FileOutputStream(new File("D://IDEA_JavaCode//Duyi//JavaBasics05//" +
"TestFile02//Test//test.txt"));
BufferedOutputStream bos = new BufferedOutputStream(fos);//装入低级流
} catch (IOException e) {
e.printStackTrace();
}
}
(1)BufferedInputStream
(1) 构建方式,使用低级流构建,需要将低级流装入高级流
(2)基本使用与低级流的方式完全一致
read(); skip(); available(); close();
bis.read(); bis.read(byte[]); bis.available(); bis.skip(long); bis.close();
(2)BufferedOutputStream
(1) 构建方式,使用低级流构建,需要将低级流装入高级流(注意:缓存流构建的时候没有boolean类型的参数)
(2)基本使用与低级流方法完全一致
write(); flush(); close();
bos.write(int); bos.write(byte[]); bos.flush(); bos.close();
29.3 字符型缓冲流
(1)BufferedReader
try{
? ? ? ? ? ?FileReader fr = new FileReader(new File("D://IDEA_JavaCode//Duyi//JavaBasics05//" +
? ? ? ? ? ? ? ? ? ?"TestFile02//Test//test.txt"));
? ? ? ? ? ?BufferedReader br = new BufferedReader(fr);
? ? ? ? ? ?//读取文件中一行的信息
? ? ? ? ? ?String value = br.readLine();
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?System.out.println(value);
? ? ? ? ? ? ? ?value = br.readLine();
? ? ? ? ? }
?
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
(3)用BufferedReader和BufferedWriter做登录
既然BufferedReader可以通过String value = br.readLine();方法读取一行信息,那么我们可不可以用它做登录?
以前数组、box、集合(List Set Map)用这些来做真实数据的存储,但是他们都是临时性的存储,因为他们都在内存中
所以用文件更好,永久性的存储,存储在硬盘上
public class TestBufferedReaderAndWriter {
? ?/**
? ? * @Description: TODO 用来做登录用户认证
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 12:24
? ? * @Param: [username, password]
? ? * @Return: java.lang.String
? ? */
? ?public String login(String username, String password) {
? ? ? ?//真实的名字和密码,永久的存在数据库中-----数据持久化
? ? ? ?//文件我们采用.txt形式的纯文本(方便),文本中的内容,以行为单位的,每一行记录一个人的信息
? ? ? ?try {
? ? ? ? ? ?BufferedReader br = new BufferedReader(new FileReader("D://IDEA_JavaCode//Duyi//JavaBasics05//" +
? ? ? ? ? ? ? ? ? ?"TestFile02//Test//login.txt"));
? ? ? ? ? ?//user表示一行的记录信息,记录着账号和密码
? ? ? ? ? ?String user = br.readLine();
? ? ? ? ? ?while (user != null) {
? ? ? ? ? ? ? ?//如果读到以后,将user信息,按照-拆分,分别于方法的参数进行比较 v[0]账号 v[1]密码
? ? ? ? ? ? ? ?String[] value = user.split("-");
? ? ? ? ? ? ? ?if (value[0].equals(username)) {
? ? ? ? ? ? ? ? ? ?if (value[1].equals(password)) {
? ? ? ? ? ? ? ? ? ? ? ?return "登录成功!";
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?//在读一边,进行下一行信息
? ? ? ? ? ? ? ?user = br.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
?
? ? ? }
? ? ? ?return "用户名或密码错误!";
? }
?
? ?public static void main(String[] args) {
? ? ? ?TestBufferedReaderAndWriter test = new TestBufferedReaderAndWriter();
? ? ? ?String result = test.login("xxx","123");
? ? ? ?System.out.println(result);
?
? ? ? ?try{
? ? ? ? ? ?//也可以向txt中写入信息,append追加信息
? ? ? ? ? ?BufferedWriter bw = new BufferedWriter(new FileWriter("D://IDEA_JavaCode//Duyi//JavaBasics05//" +
? ? ? ? ? ? ? ? ? ?"TestFile02//Test//login.txt",true));
? ? ? ? ? ?//写入
? ? ? ? ? ?bw.newLine();
? ? ? ? ? ?bw.write("sada-12434");
? ? ? ? ? ?bw.flush();
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
?
? }
?
}
三十、小总文件流
文件流:
低级: 字节型 FileInputStream / FileOutputStream
字符型 FileReader / FileWriter
缓存(高级): 字节型 BufferedInputStream / BufferedOutputStream(操作文件/文件夹本身的加密复制)
字符型 BufferedReader / BufferedWriter(开发的时候经常用,通常操作纯文本拿它来做数据库来用)
三十一、数组流(了解)
数组流: byte数组 ByteArrayInputStream / ByteArrayOutputStream
char数组 CharArrayReader / CharArrayWriter
三十二、对象流
(1)为什么有要用文件:文件永久性保存信息,将很多的数据直接存入为念----数据持久化
(2)如果按照以行为单位写信息:好处在于每一行记录的信息都是相关的,信息的我们可以读取出来,可以直接看懂文件;
第一:不安全,你能看懂别人也行
第二:如果对象中有一些方法(动作)它是无法记录的,只能记录一些String信息,属性也行
所以才会出现对象流。
对象流:ObjectInputStream / ObjectOutputStream
(1)将对象直接存入文件中,将对象拆分成字节码,然后直接写入文件
32.1 对象的序列化和反序列化
(1)ObjectInputStream / ObjectOutputStream
对象的序列化:将一个完整的对象,拆分成字节碎片,记录在文件中(将对象写入文件)
对象的反序列化:将文件记录的对象碎片,反过来组合成一个完整的对象(从文件中读取对象)
如果想要将对象序列化到文件中:
(1)需要让对象Person实现Serializable接口下 ,是一个示意性的接口(里面没有实质性的动作)
public static void main(String[] args) {
try {
//将对象直接记录在文件中,永久保存,对象的序列化(持久化)
Person p1 = new Person("cyx",18);
//对象输出流
FileOutputStream fos = new FileOutputStream("D://IDEA_JavaCode//Duyi//JavaBasics05//" +
"TestFile02//Test//test.text");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//将对象拆分成碎片,序列化到文件里,不能随便的序列化,必须要有一定规则的才行---去对象Person中实现Serializable接口
oos.writeObject(p1);
oos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
(2)同时为了让对象可以反序列化,我们需要让对象多存在一个属性private long serialVersionUID = 任意L,然后就可以将对象写进文件里了
如果想要将对象反序列化(就是从文件中读出来),需要给对象提供一个序列化的版本号,jdk有很多版本,如果我用1.7版本写一个String,然后读String是在一个1.8版本的运行环境中读的,写的版本和读的版本不一致,可能就导致方法里面的东西不一样(比如String在1.8版本进行了更新,更新了一些其他功能)
就是拿出来的对象需要和你现在的运行版本进行比对一下,如果版本没错我就给你反序列化读出来,否则无法反序列化)
然后输入移入User对象
package testbuffered;
import java.io.Serializable;
/**
* @Description: TODO 人类
* @Author: 曹宇希
* @Date: 2023/11/7 13:40
* @Version: 1.0
* @Company: 版权所有
*/
public class Person implements Serializable {
/**
* @Description: TODO 反序列化需要添加版本号,添加一个serialVersionUID然后给初始值,这个值可以随意
* @Author: 曹宇希
* @Date: 2023/11/7 19:20
*/
private long serialVersionUID = 5291531515806950297L;
private String name;
private int age;
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void eat() {
System.out.println("Person的eat方法");
}
/**
* @Description: TODO 重写toString方法,就可以直接打印对象里面的东西了
* @Author: 曹宇希
* @Date: 2023/11/7 19:13
* @Param: []
* @Return: java.lang.String
*/
@Override
public String toString() {
return this.name + "," + this.age;
}
}
public static void main(String[] args) {
try{
//需要一个对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D://IDEA_JavaCode//Duyi" +
"//JavaBasics05//" +
"TestFile02//Test//test.text"));
//readObject返回值是Object
Person p = (Person) ois.readObject();
System.out.println(p);
p.eat();
} catch (Exception e) {
e.printStackTrace();
}
}
三十三、银行系统(网上银行)练习
33.1 业务说明
1、实现一个银行业务系统
2、要求有如下的业务功能
(1)登录
(2)查询余额
(3)存款
(4)取款
(5)转账
(6)开户
(7)销户
3、记录银行的用户信息
账户-密码-余额
33.2 登录模块
我能拿到项目的时候第一件事先做什么?
我们所有的功能业务是不是需要底层数据的支持啊?
1、底层数据如何存储:先采用文件形式.txt,然后每一行记录一个人的所有信息(账户-密码-余额),以后是需要数据库的引入
那这个.txt数据存储在哪里合适?
(1)文件存储在固定的位置,这样可能会造成客户不存在这个数据,比如你存储在E盘,但是客户没有E盘,还有就是你写的项目和你的数据不在一个地方,也不方便查看(不建议)
(2)文件存储在当前项目的内部,这样项目和代码都在一起,你把项目部署在客户上,这个数据就跟着项目一起走了
(1)基本登录思想
(1)先在项目中创建一个数据User.txt(暂时当作数据库)
(2)创建Test类(因为一开始不知道后面还有什么类出现)
(3)设计login方法,参数String用户给的名字和密码,返回String一串登录是否成功的信息
1.要比对数据信息是否正确,所以采用字符型输入流进行读取信息(BufferedReader),采用相对路径File file = new File("src\atmsystem\User.txt");,这个高级流要装入低级流
2.创建输入流后采用读取一行的形式readLine()
3.如果数据为空读取的第一行也为空,所以加循环判断 value != null,数据库不为空就一直读取到空为止;然后将读取到信息进行拆分(user[0]用户名,user[1]密码),拆分后进行用户名和密码判断,如果对就直接返回String信息就结束了;如果不对在while里添加读取下一行readLine()进行读取下一行;不对之后还有return错误信息(这个不能写try中,因为如果输入流有误,就无法执行return了)
4.login方法写完进行测试,创建TestMain类进行测试各个方法是否有误Test t = new Test(); t.login("曹宇希","123456");
package atmsystem;
?
import java.io.*;
?
/**
* @Description: TODO 模拟网络银行的业务
* @Author: 曹宇希
* @Date: 2023/11/7 20:07
* @Version: 1.0
* @Company: 版权所有
*/
public class Test {
? ?/**
? ? * @Description: TODO 登录
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? * @Param: [username, password] 用户给的名字, 用户给的密码
? ? * @Return: java.lang.String 返回登录成功与否
? ? */
?
? ?public String login(String username, String password) {
? ? ? ?try{
? ? ? ? ? ?//创建一个字符型输入流,读取真实文件的记录
? ? ? ? ? ?//file采取的是相对路径,会自动找到当前项目的跟目录,src前面是当前工程的跟目录D:\IDEA.....\src...
? ? ? ? ? ?File file = new File("src\\atmsystem\\User.txt");
? ? ? ? ? ?FileReader fileReader = new FileReader(file);
? ? ? ? ? ?BufferedReader bufferedReader = new BufferedReader(fileReader);
? ? ? ? ? ?//读取一行数据信息,value表示一行人的信息
? ? ? ? ? ?String value = bufferedReader.readLine();
? ? ? ? ? ?//如何数据库不为空,就一致读到为空为止
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?String[] user = value.split("-");
? ? ? ? ? ? ? ?if (user[0].equals(username)) {
? ? ? ? ? ? ? ? ? ?if (user[1].equals(password)) {
? ? ? ? ? ? ? ? ? ? ? ?return "登录成功!";
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?//总要读取下一行
? ? ? ? ? ? ? ?value = bufferedReader.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? }
? ? ? ?return "密码或用户名错误!";
? }
}
(4)对登录的疑问?我们做完之后会有很多客户去用,每一次只有登录都要让对象读一边,那么读文件就需要一个管道,频繁读文件特别慢,那能不能一次性都读到计算机里,留着它,以后登录就不需要读文件了,而是读取你留好的那个地方,这就是缓存机制性能高
发现登录的方法,每一次调用需要创建流管道,读取文件的信息,内存中操作登录的业务,文件不在一个地方,认为读取过程很慢,
(5)解决登录性能的优化。创建一个Map集合充当缓存,将文件中的数据全部都读出来,就读一次;创建Map集合充当缓存,将文件中的数据全部读取出来
一行记录,创建一个对象存起来,一个人,一个对象,三个属性,HashMap<String, User>第二个参数无论是什么,它的目的都是为了存储人的所有信息的,所以拿对象当第二个参数来提高阅读性,因为对象的名字可以随便写(自己创建),人的信息是可变的数组不太好,Map阅读性差,对象中的属性可以自己定义
private HashMap<String, User> userBox = new HashMap<String, User>();
(2)整体优化后:
-
创建UserBox缓存,用Map集合充当缓存,存储用户数据信息,key为用户账户,value为User对象用于存储用户数据信息,提供阅读性
-
创建User对象,实现Serializable接口,对象中定义属性(版本号、String账户、String密码、Float余额),设定构造方法用于创建对象,创建get和set方法用于获取和设置用户数据信息
-
缓存创建完成后,要给Map集合存入用户数据信息,创建程序块{}用于将数据存入map集合
-
程序块中采用try{ } catch( ){ } finally{ }结构,在此结构中创建字符型输入流FileReader和字符型缓存输入流BufferedReader,用于读取,采用读取一行信息的形式String value = bufferedReader.readLine();,由于读取信息不是一次读完,所以while (value != null) {}循环遍历
-
在while中将读取到的信息value进行拆分成数组String[] userValue = value.split("-");,将这些信息存入对象中 new User(String,String,Float);,然后再将对象存入Map集合中hashMap<String账户,User对象>,然后再去读取一行信息value = bufferedReader.readLine();
-
最后将字符型输入流FielReader和字符型缓存输入流BufferedReader关闭
-
设计login方法,登录 参数:用户给的名字, 用户给的密码,返回值:返回登录成功与否
-
在login中获取缓存中的用户名User user = userBox.get(username),也就是获取key然后找value,value是User对象;然后if判断对象中存数据信息与输入的是否一致
package atmsystem;
?
import java.io.*;
import java.util.HashMap;
?
//模拟网络银行的业务
public class Test {
// Map集合充当缓存(方便查找),存储人当中的所有数据,参数:String每个人的用户名不同(key) User对象存用户数据(value) ? ?
? // 登录方法,每一次调用都创建流管道,读取文件的信息很慢,利用Map集合充当缓存,将文件中的数据全部读取出来放入缓存中
? ?
? ?//一行记录,创建一个对象存起来,一个人,一个对象,三个属性,HashMap<String, User>第二个参数无论是什么,它的目的都是
? ?//为了存储人的所有信息的,所以拿对象当第二个参数来提高阅读性,因为对象的名字可以随便写(自己创建),人的信息是可变的数组
? ?//不太好,Map阅读性差,对象中的属性可以自己定义
? ?private HashMap<String, User> userBox = new HashMap<String, User>();
? ?// 程序块给Map存用户数据程序块目的在对象创建之前,给Map集合进行赋值操作,将数据存入缓存中
? {
? ? ? ?FileReader fileReader = null;
? ? ? ?BufferedReader bufferedReader = null;
? ? ? ?try{
? ? ? ? ? ?//创建一个字符型输入流,读取真实文件的记录
? ? ? ? ? ?//file采取的是相对路径,会自动找到当前项目的跟目录,src前面是当前工程的跟目录D:\IDEA.....\src...
? ? ? ? ? ?File file = new File("src\\atmsystem\\User.txt");
? ? ? ? ? ?fileReader = new FileReader(file);
? ? ? ? ? ?bufferedReader = new BufferedReader(fileReader);
? ? ? ? ? ?//读取一行数据信息,value表示一行人的信息
? ? ? ? ? ?String value = bufferedReader.readLine();
? ? ? ? ? ?//如何数据库不为空,就一致读到为空为止
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?//将value的信息拆分成三段
? ? ? ? ? ? ? ?String[] userValue = value.split("-");
? ? ? ? ? ? ? ?//构建一个User对象,存储三段信息(三个属性刚好存储), User构造方法中第三个参数(第三个属性)是Float类型的
? ? ? ? ? ? ? ?User user = ?new User(userValue[0], userValue[1], Float.parseFloat(userValue[2]));
? ? ? ? ? ? ? ?//将对象存入Map集合<账户,User对象>
? ? ? ? ? ? ? ?userBox.put(userValue[0],user);
? ? ? ? ? ? ? ?//再次读取
? ? ? ? ? ? ? ?value = bufferedReader.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//fileReader关闭字符型输入流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileReader != null) {
? ? ? ? ? ? ? ? ? ?fileReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//bufferedReader关闭字符型缓存流
? ? ? ? ? ?try{
? ? ? ? ? ? ? ?if (bufferedReader != null) {
? ? ? ? ? ? ? ? ? ?bufferedReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
? }
?
//登录 参数:用户给的名字, 用户给的密码,返回值:返回登录成功与否
? ?public String login(String username, String password) {
? ? ? ?User user = userBox.get(username);
? ? ? ?if (user != null && user.getPassword().equals(password)) {
? ? ? ? ? ?return "登录成功!";
? ? ? }
? ? ? ?return "密码或用户名错误!";
? }
}
package atmsystem;
?
import java.io.Serializable;
//User 记录数据库中的一行信息,把账户-密码-余额以对象的形式包起来,继承Serializable接口
public class User implements Serializable {
?
? ?//版本号
? ?private static final long serialVersionUID = -322964954562611312L;
?
? ?private String username;
?
? ?private String password;
?
? ?private Float userBalance;
//构造器
? ?public User(){}
? ?public User(String username, String password, Float userBalance) {
? ? ? ?this.username = username;
? ? ? ?this.password = password;
? ? ? ?this.userBalance = userBalance;
? }
//get,set方法
? ?public String getUsername() {
? ? ? ?return username;
? }
?
? ?public void setUsername(String username) {
? ? ? ?this.username = username;
? }
?
? ?public String getPassword() {
? ? ? ?return password;
? }
?
? ?public void setPassword(String password) {
? ? ? ?this.password = password;
? }
?
? ?public Float getUserBalance() {
? ? ? ?return userBalance;
? }
?
? ?public void setUserBalance(Float userBalance) {
? ? ? ?this.userBalance = userBalance;
? }
}
33.2 查询余额模块
package atmsystem;
?
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
?
/**
* @Description: TODO 模拟网络银行的业务
* @Author: 曹宇希
* @Date: 2023/11/7 20:07
* @Version: 1.0
* @Company: 版权所有
*/
public class Test {
? ?/**
? ? * @Description: TODO Map集合充当缓存,存储人当中的所有数据
? ? * ? ? ? ? ? ? ? ? String每个人的用户名不同(key) User对象存用户数据(value)
? ? *登录方法,每一次调用都创建流管道,读取文件的信息很慢,利用Map集合充当缓存,将文件中的数据全部读取出来
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? */
? ?private HashMap<String, User> userBox = new HashMap<String, User>();
? ?/**
? ? * @Description: TODO 程序块给Map存用户数据
? ? * 程序块目的在对象创建之前,给Map集合进行赋值操作,将数据存入缓存中
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:59
? ? */
? {
? ? ? ?FileReader fileReader = null;
? ? ? ?BufferedReader bufferedReader = null;
? ? ? ?try{
? ? ? ? ? ?//创建一个字符型输入流,读取真实文件的记录
? ? ? ? ? ?//file采取的是相对路径,会自动找到当前项目的跟目录,src前面是当前工程的跟目录D:\IDEA.....\src...
? ? ? ? ? ?File file = new File("src\\atmsystem\\User.txt");
? ? ? ? ? ?fileReader = new FileReader(file);
? ? ? ? ? ?bufferedReader = new BufferedReader(fileReader);
? ? ? ? ? ?//读取一行数据信息,value表示一行人的信息
? ? ? ? ? ?String value = bufferedReader.readLine();
? ? ? ? ? ?//如何数据库不为空,就一致读到为空为止
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?//将value的信息拆分成三段
? ? ? ? ? ? ? ?String[] userValue = value.split("-");
? ? ? ? ? ? ? ?//构建一个User对象,存储三段信息(三个属性刚好存储), User构造方法中第三个参数(第三个属性)是Float类型的
? ? ? ? ? ? ? ?User user = ?new User(userValue[0], userValue[1], Float.parseFloat(userValue[2]));
? ? ? ? ? ? ? ?//将对象存入Map集合<账户,User对象>
? ? ? ? ? ? ? ?userBox.put(userValue[0],user);
? ? ? ? ? ? ? ?//再次读取
? ? ? ? ? ? ? ?value = bufferedReader.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//fileReader关闭字符型输入流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileReader != null) {
? ? ? ? ? ? ? ? ? ?fileReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//bufferedReader关闭字符型缓存流
? ? ? ? ? ?try{
? ? ? ? ? ? ? ?if (bufferedReader != null) {
? ? ? ? ? ? ? ? ? ?bufferedReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
? }
?
/*网络银行的业务,所有的业务方法,按照我们之前的优化结构设计,以下只有业务逻辑,判断、比较、
计算等等,看不到任何数据的操作(从哪查,从哪存都看不见),横线以上都是对数据的真实操作,所以
这两个应该是放在不同的类中*/
? ?/**
? ? * @Description: TODO 登录
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? * @Param: [username, password] 用户给的名字, 用户给的密码
? ? * @Return: java.lang.String 返回登录成功与否
? ? */
? ?public String login(String username, String password) {
? ? ? ?User user = this.selectOne(username);
? ? ? ?if (user != null && user.getPassword().equals(password)) {
? ? ? ? ? ?return "登录成功!";
? ? ? }
? ? ? ?return "密码或用户名错误!";
? }
?
? ?/**
? ? * @Description: TODO 查询余额
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:17
? ? * @Param: [username] 账户
? ? * @Return: java.lang.Float
? ? */
? ?public Float queryBalance(String username) {
? ? ? ?User user = this.selectOne(username);
? ? ? ?return user.getUserBalance();
? }
?
? ?/**
? ? * @Description: TODO 存款
? ? * 我们只做业务,至于怎么查出来的,怎么存入的不用管
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [username, depositMoney] 账户 存入的金额
? ? * @Return: void
? ? */
? ?public void deposit(String username, Float depositMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User user = this.selectOne(username);
? ? ? ?//将原有的金额 加上 存入的金额
? ? ? ?user.setUserBalance(user.getUserBalance() + depositMoney);
? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ?this.update(user);
? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ?//将临时的数据永久的写入文件
? ? ? ?this.commit();
? }
?
? ?/**
? ? * @Description: TODO ? 查询缓存中的对象信息
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:41
? ? * @Param: [username] 账户
? ? * @Return: atmsystem.User 对象
? ? */
? ?public User selectOne(String username) {
? ? ? ?//这里是一行,以后如果不是一行的时候,只需要改变这个方法就可以了
? ? ? ?return userBox.get(username);
? }
? ?/**
? ? * @Description: TODO 将一个修改完毕的对象在存入集合
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:51
? ? * @Param: [user]
? ? * @Return: void
? ? */
? ?public void update(User user) {
? ? ? ?//集合做了修改
? ? ? ?userBox.put(user.getUsername(), user);
?
? }
?
? ?/**
? ? * @Description: TODO 将修改后的对象数据全部写入文件中
? ? * HashMap<String, User>
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:57
? ? * @Param: []
? ? * @Return: void
? ? */
? ?public void commit() {
? ? ? ?FileWriter fileWriter = null;
? ? ? ?BufferedWriter bufferedWriter = null;
? ? ? ?try {
? ? ? ? ? ?//创建一个字符型文件输出流
? ? ? ? ? ?File file = new File("");
? ? ? ? ? ?fileWriter = new FileWriter(file);
? ? ? ? ? ?bufferedWriter = new BufferedWriter(fileWriter);
? ? ? ? ? ?//遍历集合,因为Map的集合key是不一样的,userBox.keySet()返回值是Set集合所以用迭代器
? ? ? ? ? ?Iterator<String> names = userBox.keySet().iterator();
? ? ? ? ? ?while (names.hasNext()) {
? ? ? ? ? ? ? ?//Set集合内获取的某一个人名,用人名确定对象
? ? ? ? ? ? ? ?String name = names.next();
? ? ? ? ? ? ? ?//获取对象,记录一个人的真实数据
? ? ? ? ? ? ? ?User user = userBox.get(name);
? ? ? ? ? ? ? ?//将user的真实数据拼凑成一行字符串
? ? ? ? ? ? ? ?StringBuilder builder = new StringBuilder(user.getUsername());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getPassword());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getUserBalance());
? ? ? ? ? ? ? ?//将字符串在重写写入文件里,字符型文件输出流将拼接好的builder写入文件
? ? ? ? ? ? ? ?//write参数是String的,builder转为字符串
? ? ? ? ? ? ? ?bufferedWriter.write(builder.toString());
? ? ? ? ? ? ? ?//换行
? ? ? ? ? ? ? ?bufferedWriter.newLine();
? ? ? ? ? ? ? ?bufferedWriter.flush();
? ? ? ? ? }
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//关闭字符型输出流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileWriter != null) {
? ? ? ? ? ? ? ? ? ?fileWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//关闭字符型输出缓存流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (bufferedWriter != null) {
? ? ? ? ? ? ? ? ? ?bufferedWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
?
? }
?
? ?/**
? ? * @Description: TODO 取款
? ? * 与存款一样就是加减的问题
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [username, withdrawalMoney] 账户 取出的金额
? ? * @Return: void
? ? */
? ?public void withdrawal(String username, Float withdrawalMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User user = this.selectOne(username);
? ? ? ?//如果账户的金额大于取出的金额就可以取
? ? ? ?if (user.getUserBalance() > withdrawalMoney) {
? ? ? ? ? ?//将原有的金额 减去 取出的金额
? ? ? ? ? ?user.setUserBalance(user.getUserBalance() - withdrawalMoney);
? ? ? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ? ? ?this.update(user);
? ? ? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ? ? ?//将临时的数据永久的写入文件
? ? ? ? ? ?this.commit();
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + username + "您的账户余额不足!");
? ? ? }
?
? }
?
? ?/**
? ? * @Description: TODO 转账
? ? * 转账就是先存后取
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [outName, inName, transferMoney] 转出账户,转入账户,转账金额
? ? * @Return: void
? ? */
? ?public void transfer(String outName, String inName, Float transferMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User outUser = this.selectOne(outName);
? ? ? ?//如果转出用户的金额大于转账金额就可以转
? ? ? ?if (outUser.getUserBalance() > transferMoney) {
? ? ? ? ? ?//查询收账用户,查询到底转账的给哪个用户
? ? ? ? ? ?User inUser = this.selectOne(inName);
? ? ? ? ? ?//收账的用户不为空,说明收账用户存在
? ? ? ? ? ?if (inUser != null) {
? ? ? ? ? ? ? ?//转出用户的余额 - 传出的钱
? ? ? ? ? ? ? ?outUser.setUserBalance(outUser.getUserBalance() - transferMoney);
? ? ? ? ? ? ? ?//收账用户的余额 + 上面转出的钱
? ? ? ? ? ? ? ?inUser.setUserBalance(inUser.getUserBalance() + transferMoney);
? ? ? ? ? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ? ? ? ? ?this.update(outUser);
? ? ? ? ? ? ? ?this.update(inUser);
? ? ? ? ? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ? ? ? ? ?//将临时的数据永久的写入文件
? ? ? ? ? ? ? ?this.commit();
? ? ? ? ? } else {
? ? ? ? ? ? ? ?System.out.println("对不起,您输入的" + inName + "账户不存在!");
? ? ? ? ? }
?
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + outName + "您的账户余额不足!");
? ? ? }
?
? }
}
你会发现登录需要先查询集合中的对象key,通过key去找数据value信息;然后余额也需要这一步也是先查。那么以后在添加方法也会执行此代码过程,太繁琐了,所以我们设计一个查询方法selectOne(String username),目的为了我的所有业务服务,参数账户名,返回值User对象
1、设计selectOne方法用于查询缓存(Map集合)中的对象,怎么进行查Map集合,通过Key查询相应Value(userBox.get(账户名)),key表示账户,value表示一个人的数据信息,参数:String账户,返回值一个User对象
33.3 存款模块
存款就是在数据库中做一个对金额的修改,数据库中的用户名不变,密码也不变,数据库中的行数也没变;他只是某一行当中的某个信息发生改变。
在没有集合前,我们修改数据库.txt,是修改某一行的记录,我们读取一行可以,写一行新的也可以,但是在.txt中修改金额根本做不到
所以,我们想要修改数据,需要将原数据存到一个临时的地方,然后在临时的地方进行修改,然后再把修改后的临时数据在存入到原数据的文件下。
在有了集合后,集合除了可以充当缓存,增强执行性能以外,还能用来做数据的修改。(先将集合内的数据做修改,找到某一个user对象,将对象中的balance属性修改,然后在将集合内所有最终的数据全部写入文件中,文件内的所有内容替换掉)
33.4 整体代码
package atmsystem;
?
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
?
/**
* @Description: TODO 模拟网络银行的业务
* @Author: 曹宇希
* @Date: 2023/11/7 20:07
* @Version: 1.0
* @Company: 版权所有
*/
public class Test {
? ?/**
? ? * @Description: TODO Map集合充当缓存,存储人当中的所有数据
? ? * ? ? ? ? ? ? ? ? String每个人的用户名不同(key) User对象存用户数据(value)
? ? *登录方法,每一次调用都创建流管道,读取文件的信息很慢,利用Map集合充当缓存,将文件中的数据全部读取出来
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? */
? ?private HashMap<String, User> userBox = new HashMap<String, User>();
? ?/**
? ? * @Description: TODO 程序块给Map存用户数据
? ? * 程序块目的在对象创建之前,给Map集合进行赋值操作,将数据存入缓存中
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:59
? ? */
? {
? ? ? ?FileReader fileReader = null;
? ? ? ?BufferedReader bufferedReader = null;
? ? ? ?try{
? ? ? ? ? ?//创建一个字符型输入流,读取真实文件的记录
? ? ? ? ? ?//file采取的是相对路径,会自动找到当前项目的跟目录,src前面是当前工程的跟目录D:\IDEA.....\src...
? ? ? ? ? ?File file = new File("src\\atmsystem\\User.txt");
? ? ? ? ? ?fileReader = new FileReader(file);
? ? ? ? ? ?bufferedReader = new BufferedReader(fileReader);
? ? ? ? ? ?//读取一行数据信息,value表示一行人的信息
? ? ? ? ? ?String value = bufferedReader.readLine();
? ? ? ? ? ?//如何数据库不为空,就一致读到为空为止
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?//将value的信息拆分成三段
? ? ? ? ? ? ? ?String[] userValue = value.split("-");
? ? ? ? ? ? ? ?//构建一个User对象,存储三段信息(三个属性刚好存储), User构造方法中第三个参数(第三个属性)是Float类型的
? ? ? ? ? ? ? ?User user = ?new User(userValue[0], userValue[1], Float.parseFloat(userValue[2]));
? ? ? ? ? ? ? ?//将对象存入Map集合<账户,User对象>
? ? ? ? ? ? ? ?userBox.put(userValue[0],user);
? ? ? ? ? ? ? ?//再次读取
? ? ? ? ? ? ? ?value = bufferedReader.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//fileReader关闭字符型输入流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileReader != null) {
? ? ? ? ? ? ? ? ? ?fileReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//bufferedReader关闭字符型缓存流
? ? ? ? ? ?try{
? ? ? ? ? ? ? ?if (bufferedReader != null) {
? ? ? ? ? ? ? ? ? ?bufferedReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
? }
?
/*网络银行的业务,所有的业务方法,按照我们之前的优化结构设计,以下只有业务逻辑,判断、比较、
计算等等,看不到任何数据的操作(从哪查,从哪存都看不见),横线以上都是对数据的真实操作,所以
这两个应该是放在不同的类中*/
? ?/**
? ? * @Description: TODO 登录
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? * @Param: [username, password] 用户给的名字, 用户给的密码
? ? * @Return: java.lang.String 返回登录成功与否
? ? */
? ?public String login(String username, String password) {
? ? ? ?User user = this.selectOne(username);
? ? ? ?if (user != null && user.getPassword().equals(password)) {
? ? ? ? ? ?return "登录成功!";
? ? ? }
? ? ? ?return "密码或用户名错误!";
? }
?
? ?/**
? ? * @Description: TODO 查询余额
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:17
? ? * @Param: [username] 账户
? ? * @Return: java.lang.Float
? ? */
? ?public Float queryBalance(String username) {
? ? ? ?User user = this.selectOne(username);
? ? ? ?return user.getUserBalance();
? }
?
? ?/**
? ? * @Description: TODO 存款
? ? * 我们只做业务,至于怎么查出来的,怎么存入的不用管
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [username, depositMoney] 账户 存入的金额
? ? * @Return: void
? ? */
? ?public void deposit(String username, Float depositMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User user = this.selectOne(username);
? ? ? ?//将原有的金额 加上 存入的金额
? ? ? ?user.setUserBalance(user.getUserBalance() + depositMoney);
? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ?this.update(user);
? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ?//将临时的数据永久的写入文件
? ? ? ?this.commit();
? }
?
? ?/**
? ? * @Description: TODO ? 查询缓存中的对象信息
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:41
? ? * @Param: [username] 账户
? ? * @Return: atmsystem.User 对象
? ? */
? ?public User selectOne(String username) {
? ? ? ?//这里是一行,以后如果不是一行的时候,只需要改变这个方法就可以了
? ? ? ?return userBox.get(username);
? }
? ?/**
? ? * @Description: TODO 将一个修改完毕的对象在存入集合
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:51
? ? * @Param: [user]
? ? * @Return: void
? ? */
? ?public void update(User user) {
? ? ? ?//集合做了修改
? ? ? ?userBox.put(user.getUsername(), user);
?
? }
?
? ?/**
? ? * @Description: TODO 将修改后的对象数据全部写入文件中
? ? * HashMap<String, User>
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:57
? ? * @Param: []
? ? * @Return: void
? ? */
? ?public void commit() {
? ? ? ?FileWriter fileWriter = null;
? ? ? ?BufferedWriter bufferedWriter = null;
? ? ? ?try {
? ? ? ? ? ?//创建一个字符型文件输出流
? ? ? ? ? ?File file = new File("");
? ? ? ? ? ?fileWriter = new FileWriter(file);
? ? ? ? ? ?bufferedWriter = new BufferedWriter(fileWriter);
? ? ? ? ? ?//遍历集合,因为Map的集合key是不一样的,userBox.keySet()返回值是Set集合所以用迭代器
? ? ? ? ? ?Iterator<String> names = userBox.keySet().iterator();
? ? ? ? ? ?while (names.hasNext()) {
? ? ? ? ? ? ? ?//Set集合内获取的某一个人名,用人名确定对象
? ? ? ? ? ? ? ?String name = names.next();
? ? ? ? ? ? ? ?//获取对象,记录一个人的真实数据
? ? ? ? ? ? ? ?User user = userBox.get(name);
? ? ? ? ? ? ? ?//将user的真实数据拼凑成一行字符串
? ? ? ? ? ? ? ?StringBuilder builder = new StringBuilder(user.getUsername());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getPassword());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getUserBalance());
? ? ? ? ? ? ? ?//将字符串在重写写入文件里,字符型文件输出流将拼接好的builder写入文件
? ? ? ? ? ? ? ?//write参数是String的,builder转为字符串
? ? ? ? ? ? ? ?bufferedWriter.write(builder.toString());
? ? ? ? ? ? ? ?//换行
? ? ? ? ? ? ? ?bufferedWriter.newLine();
? ? ? ? ? ? ? ?bufferedWriter.flush();
? ? ? ? ? }
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//关闭字符型输出流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileWriter != null) {
? ? ? ? ? ? ? ? ? ?fileWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//关闭字符型输出缓存流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (bufferedWriter != null) {
? ? ? ? ? ? ? ? ? ?bufferedWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
?
? }
?
? ?/**
? ? * @Description: TODO 取款
? ? * 与存款一样就是加减的问题
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [username, withdrawalMoney] 账户 取出的金额
? ? * @Return: void
? ? */
? ?public void withdrawal(String username, Float withdrawalMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User user = this.selectOne(username);
? ? ? ?//如果账户的金额大于取出的金额就可以取
? ? ? ?if (user.getUserBalance() > withdrawalMoney) {
? ? ? ? ? ?//将原有的金额 减去 取出的金额
? ? ? ? ? ?user.setUserBalance(user.getUserBalance() - withdrawalMoney);
? ? ? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ? ? ?this.update(user);
? ? ? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ? ? ?//将临时的数据永久的写入文件
? ? ? ? ? ?this.commit();
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + username + "您的账户余额不足!");
? ? ? }
?
? }
?
? ?/**
? ? * @Description: TODO 转账
? ? * 转账就是先存后取
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [outName, inName, transferMoney] 转出账户,转入账户,转账金额
? ? * @Return: void
? ? */
? ?public void transfer(String outName, String inName, Float transferMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User outUser = this.selectOne(outName);
? ? ? ?//如果转出用户的金额大于转账金额就可以转
? ? ? ?if (outUser.getUserBalance() > transferMoney) {
? ? ? ? ? ?//查询收账用户,查询到底转账的给哪个用户
? ? ? ? ? ?User inUser = this.selectOne(inName);
? ? ? ? ? ?//收账的用户不为空,说明收账用户存在
? ? ? ? ? ?if (inUser != null) {
? ? ? ? ? ? ? ?//转出用户的余额 - 传出的钱
? ? ? ? ? ? ? ?outUser.setUserBalance(outUser.getUserBalance() - transferMoney);
? ? ? ? ? ? ? ?//收账用户的余额 + 上面转出的钱
? ? ? ? ? ? ? ?inUser.setUserBalance(inUser.getUserBalance() + transferMoney);
? ? ? ? ? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ? ? ? ? ?this.update(outUser);
? ? ? ? ? ? ? ?this.update(inUser);
? ? ? ? ? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ? ? ? ? ?//将临时的数据永久的写入文件
? ? ? ? ? ? ? ?this.commit();
? ? ? ? ? } else {
? ? ? ? ? ? ? ?System.out.println("对不起,您输入的" + inName + "账户不存在!");
? ? ? ? ? }
?
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + outName + "您的账户余额不足!");
? ? ? }
?
? }
}
package atmsystem;
?
import java.io.Serializable;
?
/**
* @Description: TODO User 记录数据库中的一行信息
* ? ? ? ? ? ? ? ? 把账户-密码-余额以对象的形式包起来
* ? ? ? ? ? ? ? ? 继承Serializable接口
* @Author: 曹宇希
* @Date: 2023/11/8 13:51
* @Version: 1.0
* @Company: 版权所有
*/
public class User implements Serializable {
? ?/**
? ? * @Description: TODO 版本号
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:35
? ? */
? ?private static final long serialVersionUID = -322964954562611312L;
? ?/**
? ? * @Descript
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:03
? ? */ ?
? ?private String username;
? ?/**
? ? * @Description: TODO 用户密码 ?
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:03
? ? */
? ?private String password;
? ?/**
? ? * @Description: TODO 用户余额 ?
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:04
? ? */
? ?private Float userBalance;
?
? ?/**
? ? * @Description: TODO 构造方法
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:10
? ? * @Param: [username, password, userBalance]
? ? * @Return:
? ? */
? ?public User(){}
? ?public User(String username, String password, Float userBalance) {
? ? ? ?this.username = username;
? ? ? ?this.password = password;
? ? ? ?this.userBalance = userBalance;
? }
? ?/**
? ? * @Description: TODO 以下是get,set方法
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 15:24
? ? * @Param: []
? ? * @Return: java.lang.String
? ? */
?
? ?public String getUsername() {
? ? ? ?return username;
? }
?
? ?public void setUsername(String username) {
? ? ? ?this.username = username;
? }
?
? ?public String getPassword() {
? ? ? ?return password;
? }
?
? ?public void setPassword(String password) {
? ? ? ?this.password = password;
? }
?
? ?public Float getUserBalance() {
? ? ? ?return userBalance;
? }
?
? ?public void setUserBalance(Float userBalance) {
? ? ? ?this.userBalance = userBalance;
? }
}
33.4 如何分类
1、我们写Test类,这个类中是银行的整体操作,包含数据的操作,业务逻辑的判断
2、我们发现这个数据的操作 和 业务逻辑是两个不同的模块,我们要实现每一个类只干一件事,这样才能体现出面向对象的思想
3、创建AtmDao类,用于存放数据的所有操作,首先Test类中:程序块缓存、selectOne方法查询缓存中的对象、update将一个修改完毕的对象在存入集合、commit方法将修改后的对象数据全部写入文件中;都是操作数据的,所以将这些都移入AtmDao类
这个DAO层属于---持久层,专门操作数据的层
4、这样Test类只负责业务上的逻辑,而DAO层AtmDao类只负责操作数据
网络银行的业务,所有的业务方法,按照我们之前的优化结构设计,以下只有业务逻辑,判断、比较、 计算等等,看不到任何数据的操作(从哪查,从哪存都看不见),横线以上都是对数据的真实操作,所以 这两个应该是放在不同的类中
package atmsystem;
?
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
?
/**
* @Description: TODO 操作数据
* DAO作为层次--持久层,为了操作数据,只负责读写数据
* @Author: 曹宇希
* @Date: 2023/11/9 10:44
* @Version: 1.0
* @Company: 版权所有
*/
public class AtmDao {
? ?/**
? ? * @Description: TODO Map集合充当缓存,存储人当中的所有数据
? ? * ? ? ? ? ? ? ? ? String每个人的用户名不同(key) User对象存用户数据(value)
? ? *登录方法,每一次调用都创建流管道,读取文件的信息很慢,利用Map集合充当缓存,将文件中的数据全部读取出来
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? */
? ?private HashMap<String, User> userBox = new HashMap<String, User>();
?
? ?/**
? ? * @Description: TODO 程序块给Map存用户数据
? ? * 程序块目的在对象创建之前,给Map集合进行赋值操作,将数据存入缓存中
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:59
? ? */
? {
? ? ? ?FileReader fileReader = null;
? ? ? ?BufferedReader bufferedReader = null;
? ? ? ?try{
? ? ? ? ? ?//创建一个字符型输入流,读取真实文件的记录
? ? ? ? ? ?//file采取的是相对路径,会自动找到当前项目的跟目录,src前面是当前工程的跟目录D:\IDEA.....\src...
? ? ? ? ? ?File file = new File("src\\atmsystem\\User.txt");
? ? ? ? ? ?fileReader = new FileReader(file);
? ? ? ? ? ?bufferedReader = new BufferedReader(fileReader);
? ? ? ? ? ?//读取一行数据信息,value表示一行人的信息
? ? ? ? ? ?String value = bufferedReader.readLine();
? ? ? ? ? ?//如何数据库不为空,就一致读到为空为止
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?//将value的信息拆分成三段
? ? ? ? ? ? ? ?String[] userValue = value.split("-");
? ? ? ? ? ? ? ?//构建一个User对象,存储三段信息(三个属性刚好存储), User构造方法中第三个参数(第三个属性)是Float类型的
? ? ? ? ? ? ? ?User user = ?new User(userValue[0], userValue[1], Float.parseFloat(userValue[2]));
? ? ? ? ? ? ? ?//将对象存入Map集合<账户,User对象>
? ? ? ? ? ? ? ?userBox.put(userValue[0],user);
? ? ? ? ? ? ? ?//再次读取
? ? ? ? ? ? ? ?value = bufferedReader.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//fileReader关闭字符型输入流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileReader != null) {
? ? ? ? ? ? ? ? ? ?fileReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//bufferedReader关闭字符型缓存流
? ? ? ? ? ?try{
? ? ? ? ? ? ? ?if (bufferedReader != null) {
? ? ? ? ? ? ? ? ? ?bufferedReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
? }
?
? ?/**
? ? * @Description: TODO ? 查询缓存中的对象信息
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:41
? ? * @Param: [username] 账户
? ? * @Return: atmsystem.User 对象
? ? */
? ?public User selectOne(String username) {
? ? ? ?//这里是一行,以后如果不是一行的时候,只需要改变这个方法就可以了
? ? ? ?return userBox.get(username);
? }
?
? ?/**
? ? * @Description: TODO 将一个修改完毕的对象在存入集合
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:51
? ? * @Param: [user]
? ? * @Return: void
? ? */
? ?public void update(User user) {
? ? ? ?//集合做了修改
? ? ? ?userBox.put(user.getUsername(), user);
? }
?
? ?/**
? ? * @Description: TODO 将修改后的对象数据全部写入文件中
? ? * HashMap<String, User>
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:57
? ? * @Param: []
? ? * @Return: void
? ? */
? ?public void commit() {
? ? ? ?FileWriter fileWriter = null;
? ? ? ?BufferedWriter bufferedWriter = null;
? ? ? ?try {
? ? ? ? ? ?//创建一个字符型文件输出流
? ? ? ? ? ?File file = new File("");
? ? ? ? ? ?fileWriter = new FileWriter(file);
? ? ? ? ? ?bufferedWriter = new BufferedWriter(fileWriter);
? ? ? ? ? ?//遍历集合,因为Map的集合key是不一样的,userBox.keySet()返回值是Set集合所以用迭代器
? ? ? ? ? ?Iterator<String> names = userBox.keySet().iterator();
? ? ? ? ? ?while (names.hasNext()) {
? ? ? ? ? ? ? ?//Set集合内获取的某一个人名,用人名确定对象
? ? ? ? ? ? ? ?String name = names.next();
? ? ? ? ? ? ? ?//获取对象,记录一个人的真实数据
? ? ? ? ? ? ? ?User user = userBox.get(name);
? ? ? ? ? ? ? ?//将user的真实数据拼凑成一行字符串
? ? ? ? ? ? ? ?StringBuilder builder = new StringBuilder(user.getUsername());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getPassword());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getUserBalance());
? ? ? ? ? ? ? ?//将字符串在重写写入文件里,字符型文件输出流将拼接好的builder写入文件
? ? ? ? ? ? ? ?//write参数是String的,builder转为字符串
? ? ? ? ? ? ? ?bufferedWriter.write(builder.toString());
? ? ? ? ? ? ? ?//换行
? ? ? ? ? ? ? ?bufferedWriter.newLine();
? ? ? ? ? ? ? ?bufferedWriter.flush();
? ? ? ? ? }
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//关闭字符型输出流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileWriter != null) {
? ? ? ? ? ? ? ? ? ?fileWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//关闭字符型输出缓存流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (bufferedWriter != null) {
? ? ? ? ? ? ? ? ? ?bufferedWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
?
? }
}
1、我们发现这个DAO层中,虽然都是操作数据的,但是它也分操作集合,和操作File流
2、所以我们还可以将其分类,创建FileLoaderAndCommit类用于操作File流,将跟流相关的东西全部移入此类中
3、将程序块输入流将信息写入Map集合,commit方法将修改后的数据对象在次装入文件中,将这两个存入此类
package atmsystem;
?
import java.util.HashMap;
?
/**
* @Description: TODO 操作数据
* DAO作为层次--持久层,为了操作数据,只负责读写数据
* @Author: 曹宇希
* @Date: 2023/11/9 10:44
* @Version: 1.0
* @Company: 版权所有
*/
public class AtmDao {
? ?/**
? ? * @Description: TODO Map集合充当缓存,存储人当中的所有数据
? ? * ? ? ? ? ? ? ? ? String每个人的用户名不同(key) User对象存用户数据(value)
? ? *登录方法,每一次调用都创建流管道,读取文件的信息很慢,利用Map集合充当缓存,将文件中的数据全部读取出来
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? */
? ?private HashMap<String, User> userBox = new HashMap<String, User>();
?
? ?/**
? ? * @Description: TODO ? 查询缓存中的对象信息
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:41
? ? * @Param: [username] 账户
? ? * @Return: atmsystem.User 对象
? ? */
? ?public User selectOne(String username) {
? ? ? ?//这里是一行,以后如果不是一行的时候,只需要改变这个方法就可以了
? ? ? ?return userBox.get(username);
? }
?
? ?/**
? ? * @Description: TODO 将一个修改完毕的对象在存入集合
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:51
? ? * @Param: [user]
? ? * @Return: void
? ? */
? ?public void update(User user) {
? ? ? ?//集合做了修改
? ? ? ?userBox.put(user.getUsername(), user);
? }
?
?
}
1、此时FileLoaderAndCommit类中有程序块,将程序块写出方法,程序块目的在对象创建之前,给Map集合进行赋值操作,将数据存入缓存中,所以设计loadFile方法,参数:void 返回值HashMap<String, User>集合
2、commit提交修改后的对象数据全部写入文件中,也设计成含参的,参数HashMap<String ,User> userBox
package atmsystem;
?
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
?
/**
* @Description: TODO 操作File流
* @Author: 曹宇希
* @Date: 2023/11/9 10:49
* @Version: 1.0
* @Company: 版权所有
*/
public class FileLoaderAndCommit {
? ?/**
? ? * @Description: TODO 利用输入流程序块给Map存用户数据
? ? * 程序块目的在对象创建之前,给Map集合进行赋值操作,将数据存入缓存中
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 14:59
? ? */
? ?public HashMap<String, User> loadFile(){
? ? ? ?HashMap<String, User> userBox = new HashMap<String, User>();
? ? ? ?FileReader fileReader = null;
? ? ? ?BufferedReader bufferedReader = null;
? ? ? ?try{
? ? ? ? ? ?//创建一个字符型输入流,读取真实文件的记录
? ? ? ? ? ?//file采取的是相对路径,会自动找到当前项目的跟目录,src前面是当前工程的跟目录D:\IDEA.....\src...
? ? ? ? ? ?File file = new File("src\\atmsystem\\User.txt");
? ? ? ? ? ?fileReader = new FileReader(file);
? ? ? ? ? ?bufferedReader = new BufferedReader(fileReader);
? ? ? ? ? ?//读取一行数据信息,value表示一行人的信息
? ? ? ? ? ?String value = bufferedReader.readLine();
? ? ? ? ? ?//如何数据库不为空,就一致读到为空为止
? ? ? ? ? ?while (value != null) {
? ? ? ? ? ? ? ?//将value的信息拆分成三段
? ? ? ? ? ? ? ?String[] userValue = value.split("-");
? ? ? ? ? ? ? ?//构建一个User对象,存储三段信息(三个属性刚好存储), User构造方法中第三个参数(第三个属性)是Float类型的
? ? ? ? ? ? ? ?User user = ?new User(userValue[0], userValue[1], Float.parseFloat(userValue[2]));
? ? ? ? ? ? ? ?//将对象存入Map集合<账户,User对象>
? ? ? ? ? ? ? ?userBox.put(userValue[0],user);
? ? ? ? ? ? ? ?//再次读取
? ? ? ? ? ? ? ?value = bufferedReader.readLine();
? ? ? ? ? }
? ? ? } catch (Exception e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//fileReader关闭字符型输入流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileReader != null) {
? ? ? ? ? ? ? ? ? ?fileReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//bufferedReader关闭字符型缓存流
? ? ? ? ? ?try{
? ? ? ? ? ? ? ?if (bufferedReader != null) {
? ? ? ? ? ? ? ? ? ?bufferedReader.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
? ? ? ?return userBox;
? }
?
? ?/**
? ? * @Description: TODO 将修改后的对象数据全部写入文件中
? ? * HashMap<String, User>
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:57
? ? * @Param: []
? ? * @Return: void
? ? */
? ?public void commit(HashMap<String, User> userBox) {
? ? ? ?FileWriter fileWriter = null;
? ? ? ?BufferedWriter bufferedWriter = null;
? ? ? ?try {
? ? ? ? ? ?//创建一个字符型文件输出流
? ? ? ? ? ?File file = new File("");
? ? ? ? ? ?fileWriter = new FileWriter(file);
? ? ? ? ? ?bufferedWriter = new BufferedWriter(fileWriter);
? ? ? ? ? ?//遍历集合,因为Map的集合key是不一样的,userBox.keySet()返回值是Set集合所以用迭代器
? ? ? ? ? ?Iterator<String> names = userBox.keySet().iterator();
? ? ? ? ? ?while (names.hasNext()) {
? ? ? ? ? ? ? ?//Set集合内获取的某一个人名,用人名确定对象
? ? ? ? ? ? ? ?String name = names.next();
? ? ? ? ? ? ? ?//获取对象,记录一个人的真实数据
? ? ? ? ? ? ? ?User user = userBox.get(name);
? ? ? ? ? ? ? ?//将user的真实数据拼凑成一行字符串
? ? ? ? ? ? ? ?StringBuilder builder = new StringBuilder(user.getUsername());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getPassword());
? ? ? ? ? ? ? ?builder.append("-");
? ? ? ? ? ? ? ?builder.append(user.getUserBalance());
? ? ? ? ? ? ? ?//将字符串在重写写入文件里,字符型文件输出流将拼接好的builder写入文件
? ? ? ? ? ? ? ?//write参数是String的,builder转为字符串
? ? ? ? ? ? ? ?bufferedWriter.write(builder.toString());
? ? ? ? ? ? ? ?//换行
? ? ? ? ? ? ? ?bufferedWriter.newLine();
? ? ? ? ? ? ? ?bufferedWriter.flush();
? ? ? ? ? }
? ? ? } catch (IOException e) {
? ? ? ? ? ?e.printStackTrace();
? ? ? } finally {
? ? ? ? ? ?//关闭字符型输出流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (fileWriter != null) {
? ? ? ? ? ? ? ? ? ?fileWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? ? ? ?//关闭字符型输出缓存流
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?if (bufferedWriter != null) {
? ? ? ? ? ? ? ? ? ?bufferedWriter.close();
? ? ? ? ? ? ? }
? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ?e.printStackTrace();
? ? ? ? ? }
? ? ? }
?
? }
}
1、此时Test类中只有,负责处理业务逻辑的方法,它需要数据结构的支持,所以可以添加一个属性private AtmDao dao = new AtmDao();,这个dao就是数据,然后Test类中的this就可以替换为dao.用它来调用关于数据操作的事情,
2、你会发现取款,转账,存款这些方法最后都会调用commit来进行提交修改后的数据写入到文件中,其实我们可以在dao中的Update中实现,就是在更新完数据就立马提交
3、回到dao层AtmDao类中,要添加一个负责加载文件,更新文件数据的属性,因为你File操作和数据操作分开了;private FileLoaderAndCommit fileLoaderAndCommit = new FileLoaderAndCommit("src\atmsystem\User.txt"); 这个输入流要传递路径,因为路径不是写死的,所以在FileLoaderAndCommit中添加路径属性,还有设置构造方法fileName;
4、回到AtmDao类中,属性流创建完成后,还要有一个userBox存读取出来的信息private HashMap<String, User> userBox = fileLoaderAndCommit.loadFile();
5、最后都整理完发现Test类不能叫这个名字了,改为AtmService
package atmsystem;
?
/**
* @Description: TODO 模拟网络银行的业务
* 这个类都是负责处理业务逻辑
* @Author: 曹宇希
* @Date: 2023/11/7 20:07
* @Version: 1.0
* @Company: 版权所有
*/
public class AtmService {
/*网络银行的业务,所有的业务方法,按照我们之前的优化结构设计,以下只有业务逻辑,判断、比较、
计算等等,看不到任何数据的操作(从哪查,从哪存都看不见),横线以上都是对数据的真实操作,所以
这两个应该是放在不同的类中*/
? ?/**
? ? * @Description: TODO 数据结构
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/9 18:06
? ? */
? ?private AtmDao dao = new AtmDao();
? ?/**
? ? * @Description: TODO 登录
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? * @Param: [username, password] 用户给的名字, 用户给的密码
? ? * @Return: java.lang.String 返回登录成功与否
? ? */
? ?public String login(String username, String password) {
? ? ? ?User user = dao.selectOne(username);
? ? ? ?if (user != null && user.getPassword().equals(password)) {
? ? ? ? ? ?return "登录成功!";
? ? ? }
? ? ? ?return "密码或用户名错误!";
? }
?
? ?/**
? ? * @Description: TODO 查询余额
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:17
? ? * @Param: [username] 账户
? ? * @Return: java.lang.Float
? ? */
? ?public Float queryBalance(String username) {
? ? ? ?User user = dao.selectOne(username);
? ? ? ?return user.getUserBalance();
? }
?
? ?/**
? ? * @Description: TODO 存款
? ? * 我们只做业务,至于怎么查出来的,怎么存入的不用管
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [username, depositMoney] 账户 存入的金额
? ? * @Return: void
? ? */
? ?public void deposit(String username, Float depositMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User user = dao.selectOne(username);
? ? ? ?//将原有的金额 加上 存入的金额
? ? ? ?user.setUserBalance(user.getUserBalance() + depositMoney);
? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ?dao.update(user);
? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ?//将临时的数据永久的写入文件
? ? ? ?//dao.commit();
? ? ? ?//commit在流类,所以我们给提交设置为自动提交,也就是说在AtmDao类中的update中提交
? }
?
? ?/**
? ? * @Description: TODO 取款
? ? * 与存款一样就是加减的问题
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [username, withdrawalMoney] 账户 取出的金额
? ? * @Return: void
? ? */
? ?public void withdrawal(String username, Float withdrawalMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User user = dao.selectOne(username);
? ? ? ?//如果账户的金额大于取出的金额就可以取
? ? ? ?if (user.getUserBalance() > withdrawalMoney) {
? ? ? ? ? ?//将原有的金额 减去 取出的金额
? ? ? ? ? ?user.setUserBalance(user.getUserBalance() - withdrawalMoney);
? ? ? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ? ? ?dao.update(user);
? ? ? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ? ? ?//将临时的数据永久的写入文件
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + username + "您的账户余额不足!");
? ? ? }
?
? }
?
? ?/**
? ? * @Description: TODO 转账
? ? * 转账就是先存后取
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:20
? ? * @Param: [outName, inName, transferMoney] 转出账户,转入账户,转账金额
? ? * @Return: void
? ? */
? ?public void transfer(String outName, String inName, Float transferMoney) {
? ? ? ?//找到User对象,修改对象中的balance属性
? ? ? ?User outUser = dao.selectOne(outName);
? ? ? ?//如果转出用户的金额大于转账金额就可以转
? ? ? ?if (outUser.getUserBalance() > transferMoney) {
? ? ? ? ? ?//查询收账用户,查询到底转账的给哪个用户
? ? ? ? ? ?User inUser = dao.selectOne(inName);
? ? ? ? ? ?//收账的用户不为空,说明收账用户存在
? ? ? ? ? ?if (inUser != null) {
? ? ? ? ? ? ? ?//转出用户的余额 - 传出的钱
? ? ? ? ? ? ? ?outUser.setUserBalance(outUser.getUserBalance() - transferMoney);
? ? ? ? ? ? ? ?//收账用户的余额 + 上面转出的钱
? ? ? ? ? ? ? ?inUser.setUserBalance(inUser.getUserBalance() + transferMoney);
? ? ? ? ? ? ? ?//将修改后的对象数据,在存入Map集合中
? ? ? ? ? ? ? ?dao.update(outUser);
? ? ? ? ? ? ? ?dao.update(inUser);
? ? ? ? ? ? ? ?//当修改以后就可以将修改后的对象数据全部写入文件中
? ? ? ? ? ? ? ?//将临时的数据永久的写入文件
? ? ? ? ? } else {
? ? ? ? ? ? ? ?System.out.println("对不起,您输入的" + inName + "账户不存在!");
? ? ? ? ? }
?
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + outName + "您的账户余额不足!");
? ? ? }
?
? }
}
?
package atmsystem;
?
import java.util.HashMap;
?
/**
* @Description: TODO 操作数据
* DAO作为层次--持久层,为了操作数据,只负责读写数据
* @Author: 曹宇希
* @Date: 2023/11/9 10:44
* @Version: 1.0
* @Company: 版权所有
*/
public class AtmDao {
? ?/**
? ? * @Description: TODO 负责加载文件,更新文件数据
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/9 18:11
? ? */
? ?private FileLoaderAndCommit fileLoaderAndCommit = new FileLoaderAndCommit("src\\atmsystem\\User.txt");
? ?/**
? ? * @Description: TODO Map集合充当缓存,存储人当中的所有数据
? ? * ? ? ? ? ? ? ? ? String每个人的用户名不同(key) User对象存用户数据(value)
? ? *登录方法,每一次调用都创建流管道,读取文件的信息很慢,利用Map集合充当缓存,将文件中的数据全部读取出来
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/7 20:34
? ? */
? ?private HashMap<String, User> userBox = fileLoaderAndCommit.loadFile();
?
?
? ?/**
? ? * @Description: TODO ? 查询缓存中的对象信息
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:41
? ? * @Param: [username] 账户
? ? * @Return: atmsystem.User 对象
? ? */
? ?public User selectOne(String username) {
? ? ? ?//这里是一行,以后如果不是一行的时候,只需要改变这个方法就可以了
? ? ? ?return userBox.get(username);
? }
?
? ?/**
? ? * @Description: TODO 将一个修改完毕的对象在存入集合
? ? * @Author: 曹宇希
? ? * @Date: 2023/11/8 16:51
? ? * @Param: [user]
? ? * @Return: void
? ? */
? ?public void update(User user) {
? ? ? ?//集合做了修改
? ? ? ?userBox.put(user.getUsername(), user);
? ? ? ?//自动提交修改后的数据
? ? ? ?fileLoaderAndCommit.commit(userBox);
? }
?
?
}
package atmsystem;
?
import java.util.Scanner;
?
/**
* @Description: TODO 测试写的方法是否有问题
* @Author: 曹宇希
* @Date: 2023/11/7 21:15
* @Version: 1.0
* @Company: 版权所有
*/
public class TestMain {
? ?public static void main(String[] args) {
? ? ? ?AtmService service = new AtmService();
? ? ? ?Scanner input = new Scanner(System.in);
? ? ? ?System.out.println("欢迎您使用银行自助服务程序,请输入账户:\n");
? ? ? ?String username = input.nextLine();
? ? ? ?System.out.println("请输入密码:");
? ? ? ?String password = input.nextLine();
? ? ? ?String loginResult = service.login(username, password);
? ? ? ?System.out.println(loginResult);
? ? ? ?if ("登录成功!".equals(loginResult)) {
? ? ? ? ? ?System.out.println("恭喜您登录成功,请输入操作项");
? ? ? ? ? ?System.out.println("查询输入1\n存款输入2\n取款输入3\n转账输入4\n退出输入5\n");
? ? ? ? ? ?String option = input.nextLine();
? ? ? ? ? ?switch (option) {
? ? ? ? ? ? ? ?case "1":
? ? ? ? ? ? ? ? ? ?Float userBalance = service.queryBalance(username);
? ? ? ? ? ? ? ? ? ?System.out.println("尊敬的" + username + "用户,您的余额为:" + userBalance);
? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ?default:
? ? ? ? ? ? ? ? ? ?System.out.println("您是输入的数字不匹配!");
? ? ? ? ? }
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + loginResult);
? ? ? }
? }
?
}
package atmsystem;
?
import java.util.Scanner;
?
/**
* @Description: TODO 测试写的方法是否有问题
* @Author: 曹宇希
* @Date: 2023/11/7 21:15
* @Version: 1.0
* @Company: 版权所有
*/
public class TestMain {
? ?public static void main(String[] args) {
? ? ? ?AtmService service = new AtmService();
? ? ? ?Scanner input = new Scanner(System.in);
? ? ? ?System.out.println("欢迎您使用银行自助服务程序,请输入账户:\n");
? ? ? ?String username = input.nextLine();
? ? ? ?System.out.println("请输入密码:");
? ? ? ?String password = input.nextLine();
? ? ? ?String loginResult = service.login(username, password);
? ? ? ?System.out.println(loginResult);
? ? ? ?if ("登录成功!".equals(loginResult)) {
? ? ? ? ? ?System.out.println("恭喜您登录成功,请输入操作项");
? ? ? ? ? ?System.out.println("查询输入1\n存款输入2\n取款输入3\n转账输入4\n退出输入5\n");
? ? ? ? ? ?String option = input.nextLine();
? ? ? ? ? ?switch (option) {
? ? ? ? ? ? ? ?case "1":
? ? ? ? ? ? ? ? ? ?Float userBalance = service.queryBalance(username);
? ? ? ? ? ? ? ? ? ?System.out.println("尊敬的" + username + "用户,您的余额为:" + userBalance);
? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ?default:
? ? ? ? ? ? ? ? ? ?System.out.println("您是输入的数字不匹配!");
? ? ? ? ? }
? ? ? } else {
? ? ? ? ? ?System.out.println("对不起," + loginResult);
? ? ? }
? }
?
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!