写在前面:这个题目主要通过仔细阅读题目的需求,再通过对文件流以及Vector、ArrayList等容器的控制来完成整个代码体系的构建。因为当时正在学习,对代码的构建逻辑不够规范,思想不够到位的地方也难以避免,在这里抱歉抱歉。
不过这一版的构建完思路之后写的非常顺,在容器的使用上比较讨巧思路比较简单,希望看完之后能够有所帮助。
编写一个Inventory.java完成以下功能:
1.程序首先打开并读取Inventory.txt中记录的所有库存记录,然后读取Transactions.txt,处理这个文件中包含的事务,记录发货记录到Shipping.txt,并记录错误信息到Errors.txt中。最后更新库存到另外一个文件NewInventory.txt中。
2.文件Inventory.txt和NewInventory.txt的每行包含一个存货记录,没条记录包含下面一些字段息,这些字段之间用一个tab分开(见后面的文件格式):
字段 | 格式和含义 |
Item number | 字符串型,货物编号 |
Quantity | 整型,货物数量 |
Supplier | 字符串型,供应商编号 |
Description | 字符串型,货物描述 |
3.字段Items按照从小到大的顺序写入文件的。注意Item号不必连续,如Item号为752的后面可能是800。
4.文件Transactions.txt包含几个不同的处理记录(每行一条记录)。每条记录前面以一个大写字母开头,表示这条记录是什么类型的事务。在不同的大写字母后面是不同的信息格式。所有的字段也是以tab键分开的(见Transactions.txt文件格式)。
5.以'O'开头(Order的首字母)的事务表示这是一个发货订单,即某一种货物应该发给特定的客户。Item number和Quantity的格式如上面表格定义。Custom编号和上面的Supplier编号一致。处理一条定单记录(以'O'开头的事务)意味着从减少库存记录中相应货物的数量(减少的数量=发货单中的数量),记录发货信息到Shipping.txt中。注意:Inventory.txt中的quantity不应该小于0,如果对于某一种货物,库存的数量小于发货单的数量的话,系统应该停止处理发货单,并记录出错信息到Errors.txt。如果对于某一种货物有多个发货单,而且库存总量小于这些发货单的总和的话,系统应该按照发货单中的数量从小到大的有限原则满足客户。也就是说,对于某一种货物如果一个数量Quantity少的发货单没有处理之前,数量Quantity多的发货单永远不会被处理。(这种处理原则不受发货单记录在Transactions.txt的先后顺序影响)6.以'R'开头的事务表示这是一个到货单记录,在'R'后面是Item number和它的数量Quanlity。处理一条到货单意味着增加库存中相应货物的数量(增加的数量=到货单中的数量)。注意:如果在Transactions.txt文件中,到货单出现在发货单之后,到货单中的货物数量可以用来填补发货单中的数量(可以理解成在Transactions.txt中,优先处理到货单)。
7.以'A'开头的事务表示向库存中增加一种新的货物(即这种货物以前库存中没有),在'A'后面是Item number,供应商supplier以及货物的描述description。处理一个新增货物记录意味着向库存中增加一个数量Quantity为0的新的Item。你可以假设在一个Transactions.txt中,新增货物记录总是出现在第一个到货单之前。
8.以'D'开头的事务表示从库存中删除一种货物,在'D'后面是Item号。删除操作总是在所有的事物处理之后才被处理,以保证对于可能出现的同一种货物的发货单的操作能在删除之前被正确处理。如果要删除的某种货物的库存量Quantity不为0的话,系统应该向Errors.txt记录出错信息。
9.文件Shipping.txt中的每一行代表给某一客户的发货信息。Shipping.txt中的每一行分别是客户编号、Item号、货物数量,它们之间用tab键分隔。如果发货单中有两条客户编号和Item编号一样的记录,在Shipping.txt中应该将这两条发货信息合并(即将它们的数量相加)。
10.Errors.txt文件包含未发送的发货记录和库存量大于0的删除记录。Errors.txt每一行包含Custom编号、Item编号以及发货单上的数量Quantity。对于删除操作,Custom编号为0,数量Quntity为库存中的Quantity.
11.实验测试数据:
Inventory.txt
Transactions.txt
开始做题:
一、需求分析
首先对题目进行需求分析,依次是:
1. 用Transactions处理Inventory,最后输出NewInventory、Error、Shipping三个文件
2. NewInventory的Items编号从小到大 (按我强迫症的理解
3. 事件的处理顺序是:AROD
4. O的处理要求
1)数量够才输出
2)对于相同货物且总数不满足所有订单的货物,先输出给小数量订单客户
(A、R只有3.的处理顺序要求 略过)
5. D的处理要求:数量为零才删除
6. Error的产生条件:
1)O中数量不够未发送的订单
2)D中错误删除数量不为零的订单
7. Shipping的产生条件:
1)O中数量够的订单
注意:需要合并Shipping中给同一个客户的统一货物订单数量,整合为一条放在Shipping。
二、数据存储形式
1) 首先进行逻辑构建,把Inventory看做一个仓库的货物存储单,选择的容器类型ArrayList作为静态变量,创建Inventory类存储单条货物信息。如下: Inventory类
package warehouse_management;import java.util.ArrayList;public class Inventory { static ArrayList<Inventory> Ivy = new ArrayList<>(); String m_Item_number; int m_Quantity; String m_Supplier; String m_Description; public Inventory(String Item_number, int Quantity, String Supplier, String Description){ this.m_Item_number = Item_number; this.m_Quantity = Quantity; this.m_Supplier = Supplier; this.m_Description = Description; }}
2)因为题目的需求是用Transaction对Inventory进行更新,产生新文件,则使用字符流准备读取两个文件,使用字符流产生新文件并输出,因为Inventory有原始数据,读取之后将其存入上面Inventory类声明的静态变量ArrayList Ivy 中, 另外因为Transaction要多遍的读取,因此放置在Vector容器 vec 中当中方便索引以及查找。准备需求1
截取的操作如下:(其中存在部分的测试代码在注释中,可以使用进行测试查看)
//首先打开inventory 将文件内容存入arraylist静态成员中 File file_in = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Inventory.txt"); BufferedReader br_in = new BufferedReader(new FileReader(file_in)); String line_in; while((line_in = br_in.readLine()) != null){ String[] buff_in = line_in.split("\\s+"); Ivy.add(new Inventory(buff_in[0],Integer.parseInt(buff_in[1]),buff_in[2],buff_in[3])); } br_in.close();//测试完成:检查ivy是否正常接收对象// System.out.println("大小是:" + Ivy.size());// for(int i = 0; i < 3 ; i++){// System.out.println(Ivy.get(i).m_Item_number + " " + Ivy.get(i).m_Quantity + " " + Ivy.get(i).m_Supplier + " " + Ivy.get(i).m_Description);// } //现在打开transactions进行文件的读取,并且存进vector<String[]>里 File file_tran = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Transactions.txt"); Vector<String[]> vec= new Vector<>(); BufferedReader br_tran = new BufferedReader(new FileReader(file_tran)); String line_tran; while((line_tran = br_tran.readLine()) != null){ String[] buff_tran = line_tran.split("\\s+"); vec.add(buff_tran); } br_tran.close();//测试完成:检查vector数组是否正常接收数据// for(int i = 0 ; i < 6; i++){//// System.out.println(i + " " + vec.get(i)[1]);// } //打开shipping文件和error文件的输出准备 File file_sh = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Shipping.txt"); File file_er = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Error.txt"); //创建输出流,准备进行输出 BufferedWriter bw_sh = new BufferedWriter(new FileWriter(file_sh)); BufferedWriter bw_er = new BufferedWriter(new FileWriter(file_er));
注意:这里比较容易出错的就是Transactions的字母s没打,导致文件没找到打不开的问题。容易粗心的同学需要浅浅注意一下。(问就是我一开始也没看到,哭了。
三、处理需求
已经对我们所拥有的文件数据进行了处理,并且都有了合理的数据形式,那么直接开始进行最重要的操作——Transactions操作的处理(完成需求3
1)其中A、R订单就是简单的存放数据,此处我们的处理方式是对vec进行全部的查找,找到是A(或者R)的订单的就直接处理了(比较简单,略过)代码如下:
//首先处理A订单 for(String[] strings : vec){ if(Objects.equals(strings[0] , "A")){ Ivy.add(new Inventory(strings[1], 0 , strings[2] , strings[3])); } } //然后处理R订单 for(String[] strings : vec){ if(Objects.equals(strings[0] , "R")){ for(Inventory inventory : Ivy){ if(Objects.equals(inventory.m_Item_number, strings[1])) inventory.m_Quantity += Integer.parseInt(strings[2]); } } }
2)然后处理O订单,注意这个地方的逻辑(为了放全图,可以放大看。
核心逻辑:使用Vector<int>将我们找到的待处理特殊的内容下标存入,再之后可以随时通过下标在存放Transactions的vec变量中寻找具体订单内容。
第一步:(完成需求4、6.1)、7
(具体怎么排序的可以自己写,看别人的排序可能就觉得一团乱。
//第一步,先把所有的O订单存起来,并进行排序 Vector<Integer> vec_O_index = new Vector<>(); for(int i = 0 ; i < vec.size() ; i++){ if(Objects.equals(vec.get(i)[0] , "O")){ //当O订单中有元素 for(int j = 0 ; j < vec_O_index.size() ; j++){ //当序号相等 分为两类大情况 1. 数量大于当前元素 2. 数量小于当前元素 //1. 第一: 当前查找的已经是最后一个vec_O容器中内容 //1. 第二: 后一个item序号与当前这个不同 //1. 第三:前后数量大小比较结果相反 if(Objects.equals(vec.get(vec_O_index.get(j))[1], vec.get(i)[1])){ if(Integer.parseInt(vec.get(vec_O_index.get(j))[2]) < Integer.parseInt(vec.get(i)[2])){ if(j == vec_O_index.size() - 1 || !Objects.equals(vec.get(vec_O_index.get(j + 1))[1], vec.get(i)[1]) || Integer.parseInt(vec.get(vec_O_index.get(j + 1))[2]) > Integer.parseInt(vec.get(i)[2])){ vec_O_index.add(j + 1 , i); break; } }else{ vec_O_index.add(j , i); break; } //当其他订单中没有相同的元素 }else if (j == vec_O_index.size() - 1){ vec_O_index.add(i); break; } } //如果当O订单集合里无元素 if(vec_O_index.size() == 0) vec_O_index.add(i); } }//测试完成:检查O订单的存储数量 确定每个订单正确排序并且只进入一次// System.out.println("O订单目前有:" + vec_O_index.size());// for(Integer index: vec_O_index){// System.out.println(index);// }
第二步:
//第二步:处理O订单 bw_er.write("进销管理产生Error信息如下:\n"); bw_er.flush(); Vector<Integer> vec_sh_index = new Vector<>(); for(Integer index : vec_O_index){ for(Inventory inventory : Ivy){ if(Objects.equals(vec.get(index)[1], inventory.m_Item_number)){ if(inventory.m_Quantity > Integer.parseInt(vec.get(index)[2])){ inventory.m_Quantity -= Integer.parseInt(vec.get(index)[2]); //存储并合并准备输出的shipping信息: for(int i = 0 ; i < vec_sh_index.size();i++){ //如果两个货物订单的货物编号与客户编号相同 则进行出货订单合并 if(Objects.equals(vec.get(index)[1], vec.get(vec_sh_index.get(i))[1]) && Objects.equals(vec.get(index)[3], vec.get(vec_sh_index.get(i))[3])){ vec.get(vec_sh_index.get(i))[2] = String.valueOf(Integer.parseInt(vec.get(index)[2]) + Integer.parseInt(vec.get(vec_sh_index.get(i))[2])); }else if(i == vec_sh_index.size() - 1){ vec_sh_index.add(index); break; } } if(vec_sh_index.size() == 0){ vec_sh_index.add(index); } }else{ //输出error信息 bw_er.write("货物编号:" + vec.get(index)[1] + " 发货数量不足,客户编号: " + vec.get(index)[3] + "\n"); bw_er.flush(); } break; } } } //一起输出shipping信息 bw_sh.write("货物进销管理产生shipping信息如下:\n"); for(Integer index : vec_sh_index){ bw_sh.write("货物编号:" + String.format("%-8s", vec.get(index)[1])+"\t出货数量:" +String.format("%-8s", vec.get(index)[2]) + "\t客户:"+ String.format("%-8s", vec.get(index)[3]) + "\n"); bw_sh.flush(); }
3)处理D订单,逻辑一样,代码如下:(完成需求5,6.2)
//然后处理D订单 for(String[] strings : vec){ if(Objects.equals(strings[0] , "D")){ for(int i = 0 ; i < Ivy.size() ; i++){ if(Objects.equals(Ivy.get(i).m_Item_number, strings[1])){ if(Ivy.get(i).m_Quantity == 0) Ivy.remove(i); else{ //输出error信息: bw_er.write("编号: " + strings[1] + " 还有存货,不可删除货物信息\n"); bw_er.flush(); break; } } } } }
四、观察输出结果,调整debug
1)然后,因为Error与Shpping以上已经处理完成了,我们可以关闭文件流直接观察我们产生的文件什么样子的,有一些格式上的代码在文件输出流的时候有写,可以注意看。(完成需求1
产生的NewInventory文件通过一次arraylist的自定义排序方法进行序号的排序(完成需求2,其中匿名函数与正常的写法,两种方法仍选一种都在代码段标志出来了。
bw_sh.close(); bw_er.close();//测试完成:输出正确的error与shipping信息//观察txt文件内容 //进行arraylist根据item编号的排序 自定义arraylist排序方法 Ivy.sort(Comparator.comparingInt(in -> Integer.parseInt(in.m_Item_number))); //上述表达式为lambda的使用 其中以逗号分割,()关闭的是形参 箭头标记 -> //如下是单表达式或者声明代码块 (in1 , in2) -> in1.m_Quantity - in2.m_Quantity 其中正数为升序 //创建NewInventory文件 File file_newIn = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\NewInventory.txt"); BufferedWriter bw_newIn = new BufferedWriter(new FileWriter(file_newIn)); bw_newIn.write("货物编号\t"+"数量 \t"+"供货商 \t"+"货物描述\n"); for(Inventory inventory : Ivy){ bw_newIn.write( String.format("%-8s", inventory.m_Item_number) + String.format("%-8s", inventory.m_Quantity) + String.format("%-8s", inventory.m_Supplier) + String.format("%-8s",inventory.m_Description) + "\n"); bw_newIn.flush(); } bw_newIn.close(); System.out.println("货物进销系统表单更新完毕,文件已生成..."); }
2)观察文件输出良好,如下:
Error文件:
Shipping文件:
NewInventory文件:
文件排版一片和谐,数据没啥问题,挺ok行了哈哈哈。
至此,所有代码就做完啦。
最后把代码完整贴出:
两个类都在Package包warehouse_management内
Inventory类:
package warehouse_management;import java.util.ArrayList;public class Inventory { static ArrayList<Inventory> Ivy = new ArrayList<>(); String m_Item_number; int m_Quantity; String m_Supplier; String m_Description; public Inventory(String Item_number, int Quantity, String Supplier, String Description){ this.m_Item_number = Item_number; this.m_Quantity = Quantity; this.m_Supplier = Supplier; this.m_Description = Description; }}
warehouse_TEST类
package warehouse_management;import java.io.*;import java.util.Comparator;import java.util.Objects;import java.util.Vector;import static warehouse_management.Inventory.Ivy;public class warehouse_TEST { public static void main(String[] args) throws IOException { //首先打开inventory 将文件内容存入arraylist静态成员中 File file_in = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Inventory.txt"); BufferedReader br_in = new BufferedReader(new FileReader(file_in)); String line_in; while((line_in = br_in.readLine()) != null){ String[] buff_in = line_in.split("\\s+"); Ivy.add(new Inventory(buff_in[0],Integer.parseInt(buff_in[1]),buff_in[2],buff_in[3])); } br_in.close();//测试完成:检查ivy是否正常接收对象// System.out.println("大小是:" + Ivy.size());// for(int i = 0; i < 3 ; i++){// System.out.println(Ivy.get(i).m_Item_number + " " + Ivy.get(i).m_Quantity + " " + Ivy.get(i).m_Supplier + " " + Ivy.get(i).m_Description);// } //现在打开transactions进行文件的读取,并且存进vector<String[]>里 File file_tran = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Transactions.txt"); Vector<String[]> vec= new Vector<>(); BufferedReader br_tran = new BufferedReader(new FileReader(file_tran)); String line_tran; while((line_tran = br_tran.readLine()) != null){ String[] buff_tran = line_tran.split("\\s+"); vec.add(buff_tran); } br_tran.close();//测试完成:检查vector数组是否正常接收数据// for(int i = 0 ; i < 6; i++){//// System.out.println(i + " " + vec.get(i)[1]);// } //打开shipping文件和error文件的输出准备 File file_sh = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Shipping.txt"); File file_er = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\Error.txt"); //创建输出流,准备进行输出 BufferedWriter bw_sh = new BufferedWriter(new FileWriter(file_sh)); BufferedWriter bw_er = new BufferedWriter(new FileWriter(file_er)); //首先处理A订单 for(String[] strings : vec){ if(Objects.equals(strings[0] , "A")){ Ivy.add(new Inventory(strings[1], 0 , strings[2] , strings[3])); } } //然后处理R订单 for(String[] strings : vec){ if(Objects.equals(strings[0] , "R")){ for(Inventory inventory : Ivy){ if(Objects.equals(inventory.m_Item_number, strings[1])) inventory.m_Quantity += Integer.parseInt(strings[2]); } } } //第一步,先把所有的O订单存起来,并进行排序 Vector<Integer> vec_O_index = new Vector<>(); for(int i = 0 ; i < vec.size() ; i++){ if(Objects.equals(vec.get(i)[0] , "O")){ //当O订单中有元素 for(int j = 0 ; j < vec_O_index.size() ; j++){ //当序号相等 分为两类大情况 1. 数量大于当前元素 2. 数量小于当前元素 //1. 第一: 当前查找的已经是最后一个vec_O容器中内容 //1. 第二: 后一个item序号与当前这个不同 //1. 第三:前后数量大小比较结果相反 if(Objects.equals(vec.get(vec_O_index.get(j))[1], vec.get(i)[1])){ if(Integer.parseInt(vec.get(vec_O_index.get(j))[2]) < Integer.parseInt(vec.get(i)[2])){ if(j == vec_O_index.size() - 1 || !Objects.equals(vec.get(vec_O_index.get(j + 1))[1], vec.get(i)[1]) || Integer.parseInt(vec.get(vec_O_index.get(j + 1))[2]) > Integer.parseInt(vec.get(i)[2])){ vec_O_index.add(j + 1 , i); break; } }else{ vec_O_index.add(j , i); break; } //当其他订单中没有相同的元素 }else if (j == vec_O_index.size() - 1){ vec_O_index.add(i); break; } } //如果当O订单集合里无元素 if(vec_O_index.size() == 0) vec_O_index.add(i); } }//测试完成:检查O订单的存储数量 确定每个订单正确排序并且只进入一次// System.out.println("O订单目前有:" + vec_O_index.size());// for(Integer index: vec_O_index){// System.out.println(index);// } //第二步:处理O订单 bw_er.write("进销管理产生Error信息如下:\n"); bw_er.flush(); Vector<Integer> vec_sh_index = new Vector<>(); for(Integer index : vec_O_index){ for(Inventory inventory : Ivy){ if(Objects.equals(vec.get(index)[1], inventory.m_Item_number)){ if(inventory.m_Quantity > Integer.parseInt(vec.get(index)[2])){ inventory.m_Quantity -= Integer.parseInt(vec.get(index)[2]); //存储并合并准备输出的shipping信息: for(int i = 0 ; i < vec_sh_index.size();i++){ //如果两个货物订单的货物编号与客户编号相同 则进行出货订单合并 if(Objects.equals(vec.get(index)[1], vec.get(vec_sh_index.get(i))[1]) && Objects.equals(vec.get(index)[3], vec.get(vec_sh_index.get(i))[3])){ vec.get(vec_sh_index.get(i))[2] = String.valueOf(Integer.parseInt(vec.get(index)[2]) + Integer.parseInt(vec.get(vec_sh_index.get(i))[2])); }else if(i == vec_sh_index.size() - 1){ vec_sh_index.add(index); break; } } if(vec_sh_index.size() == 0){ vec_sh_index.add(index); } }else{ //输出error信息 bw_er.write("货物编号:" + vec.get(index)[1] + " 发货数量不足,客户编号: " + vec.get(index)[3] + "\n"); bw_er.flush(); } break; } } } //一起输出shipping信息 bw_sh.write("货物进销管理产生shipping信息如下:\n"); for(Integer index : vec_sh_index){ bw_sh.write("货物编号:" + String.format("%-8s", vec.get(index)[1])+"\t出货数量:" +String.format("%-8s", vec.get(index)[2]) + "\t客户:"+ String.format("%-8s", vec.get(index)[3]) + "\n"); bw_sh.flush(); } //然后处理D订单 for(String[] strings : vec){ if(Objects.equals(strings[0] , "D")){ for(int i = 0 ; i < Ivy.size() ; i++){ if(Objects.equals(Ivy.get(i).m_Item_number, strings[1])){ if(Ivy.get(i).m_Quantity == 0) Ivy.remove(i); else{ //输出error信息: bw_er.write("编号: " + strings[1] + " 还有存货,不可删除货物信息\n"); bw_er.flush(); break; } } } } } bw_sh.close(); bw_er.close();//测试完成:输出正确的error与shipping信息//观察txt文件内容 //进行arraylist根据item编号的排序 自定义arraylist排序方法 Ivy.sort(Comparator.comparingInt(in -> Integer.parseInt(in.m_Item_number))); //上述表达式为lambda的使用 其中以逗号分割,()关闭的是形参 箭头标记 -> //如下是单表达式或者声明代码块 (in1 , in2) -> in1.m_Quantity - in2.m_Quantity 其中正数为升序 //创建NewInventory文件 File file_newIn = new File("D:\\CODE\\JAVA_Learn\\IDEA_PROJECT\\experiment\\NewInventory.txt"); BufferedWriter bw_newIn = new BufferedWriter(new FileWriter(file_newIn)); bw_newIn.write("货物编号\t"+"数量 \t"+"供货商 \t"+"货物描述\n"); for(Inventory inventory : Ivy){ bw_newIn.write( String.format("%-8s", inventory.m_Item_number) + String.format("%-8s", inventory.m_Quantity) + String.format("%-8s", inventory.m_Supplier) + String.format("%-8s",inventory.m_Description) + "\n"); bw_newIn.flush(); } bw_newIn.close(); System.out.println("货物进销系统表单更新完毕,文件已生成..."); }}
希望一起进步哈哈。