货物进销管理系统
编写一个Inventory.java完成以下功能(没有学过Java文件处理之前,各位同学可以使用硬编码将数据放进两个Vector变量里。等学过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’开头的事务表示这是一个发货订单,即某一种货物应该发给特定的客户。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:
Item numbe Quantity Supplier Description
17 42 6 Widget, blue
1234 0 4 Whatsit
123123 999999 98 Doohicky
Transactions.txt:
O 123123 1000 9
O 17 36 8
O 17 12 4
R 123123 1
D 1234
A 5 4 Thingy
![B]W{D6RBZ@YJKaTeX parse error: Expected 'EOF', got '}' at position 2: X}̲T`O7WB1H](C:\Us…X}T`O7WB1H.png)
实验大致过程
实验的目的大致就是通过阅读两张单子,对货物经行处理。
但是重点是如何把这些属性的性质给抽象出来
初次对类进行封装的时候的确会有很多遗漏,并且在使用过程中缺少应当有的函数,
会导致代码繁琐。
学习出处:(65条消息) java 简要讲解 货物进销管理系统_The_Moth的博客-CSDN博客_java货物进销管理系统
源代码
package ComeOut;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
//中间商,上帝视角
public class Inventory {
//初始化对应类的容器
static ArrayList<Invent> I_T = new ArrayList<>();
static ArrayList<Work_O> W_O = new ArrayList<>();
static ArrayList<Work_R> W_R = new ArrayList<>();
static ArrayList<Work_A> W_A = new ArrayList<>();
static ArrayList<Work_D> W_D = new ArrayList<>();
static ArrayList<Shipping> ship = new ArrayList<>();
static ArrayList<Errors> errors = new ArrayList<>();
public static void main(String[] args) throws Exception{
ReadInvent("Inventory.txt");
ReadTran("Transactions.txt");
m_add();//先处理---A事件
m_get();//处理---R事件
m_send();//处理---O事件
m_delete();//处理---D事件
ArrInvent();//处理---排序
combine();//处理---合并
WriteShipping("Shipping.txt");
WriteErrors("Errors.txt");
WriteNewInventory("NewInventory.txt");
}
//读取仓库数据
static void ReadInvent(String FileName) throws Exception {
//嵌套字符流读取
BufferedReader buffer1 = new BufferedReader(new FileReader(FileName));
//String数组逐行读取
String s = null;
while ((s = buffer1.readLine()) != null)
{
String []read = s.split("\t");//以TAB为分割线
I_T.add(new Invent(read[0], Integer.parseInt(read[1]), read[2], read[3]));//将数据读取到对应抽象类中
}
buffer1.close();
}
//读取对货物多操作的数据
static void ReadTran(String FileName) throws Exception {
//读取数据,但是要分多种情况读取
BufferedReader buffer2 = new BufferedReader(new FileReader(FileName));
//依旧用String数组逐行读取
String s = null;
while ((s = buffer2.readLine()) != null)
{
String []read = s.split("\t");
switch (read[0])
{
case "O":
W_O.add(new Work_O(read[0], read[1], Integer.parseInt(read[2]), read[3]));
break;
case "R":
W_R.add(new Work_R(read[0], read[1], Integer.parseInt(read[2])));
break;
case "A":
W_A.add(new Work_A(read[0],read[1], read[2], read[3]));
break;
case "D":
W_D.add(new Work_D(read[0], read[1]));
break;
}
}
//最后关闭文件流
buffer2.close();
}
//注意上面的全局变量,所以可以直接在函数中使用
//细分为很多个小块
//1.在发生的事件中,默认新增是最优先级的-----A
static void m_add()
{
//向仓库中增加一个新货物,数量为0;
for (int i = 0; i < W_A.size(); i++)
{
I_T.add(new Invent(W_A.get(i).Item_number, 0, W_A.get(i).Supplier, W_A.get(i).Description));
}
}
//2.其次是处理到货的事件
static void m_get()
{
for (int i = 0; i < W_R.size(); i++) {
for (int j = 0; j < I_T.size(); j++) {
if (W_R.get(i).Item_number.equals(I_T.get(j).Item_number))//找出货物,直接加上去
{
I_T.get(j).Quantity += W_R.get(i).Quantity;
}
}
}
}
//3.准备工作完成后处理发货订单
static void m_send()
{
//对O事件的发货数量经行排序
Collections.sort(W_O, new Comparator<Work_O>() {
@Override
public int compare(Work_O o1, Work_O o2) {
if (o1.Quantity > o2.Quantity){
return 1;
}
return -1;
}
});
//遍历发货单,检查仓库是否能正常发货
for (int i = 0; i < W_O.size(); i++) {
for (int j = 0; j < I_T.size(); j++) {
//首先找到需要发送的货物
if ( W_O.get(i).Item_number.equals(I_T.get(j).Item_number)){
//再判断是否能正常发货
//1.能正常发货
if (W_O.get(i).Quantity < I_T.get(j).Quantity){
//货物发出,仓库货物数量减少
I_T.get(j).Quantity -= W_O.get(i).Quantity;
//同时也是一条成功的发货记录,存储到Shoiping中
ship.add(new Shipping(W_O.get(i).Custom, W_O.get(i).Item_number, W_O.get(i).Quantity));
}
else{
//这是库存小于要求发货单的记录
errors.add(new Errors(W_O.get(i).Custom, W_O.get(i).Item_number, W_O.get(i).Quantity));
}
}
}
}
}
//4.完成发货后经行删除操作
static void m_delete()
{
//因为需要再遍历的同时删除,使用使用迭代器来遍历
Iterator iterator = I_T.iterator();
while (iterator.hasNext()){
Invent Delete = (Invent) iterator.next();
for (int i = 0; i < W_D.size(); i++) {
if (Delete.Item_number.equals(W_D.get(i).Item_number)){//删除货物找到
if (Delete.Quantity == 0){//满足条件可以删除
iterator.remove();
break;
}
else{//不满足删除条件,但是又要删除,则记录到错误文件中
errors.add(new Errors("0", Delete.Item_number, Delete.Quantity));
break;
}
}
}
}
}
//5.整理仓库,对仓库里的货物依据编号经行排序
static void ArrInvent()
{
//使用排序器经行排序
Collections.sort(I_T, new Comparator<Invent>() {
@Override
public int compare(Invent o1, Invent o2) {
int a = Integer.parseInt(o1.Item_number);
int b = Integer.parseInt(o2.Item_number);
if (a > b) return 1;
else if (a < b) return -1;
return 0;
}
});
}
//6.合并可以合并的发货单子
static void combine()
{
//在发货单中寻找可以合并的订单
for (int i = 0; i < ship.size() - 1; i++) {
for (int j = i + 1; j < ship.size(); j++) {
//查找是否出现可以合并的订单
if (ship.get(i).Item_number.equals(ship.get(j).Item_number) && ship.get(i).Custom.equals(ship.get(j).Custom)){
//若出现一个买家,买同一个东西的记录,则合并
ship.get(i).Quantity += ship.get(j).Quantity;
//合并后删除多余记录
ship.remove(j);
//同时注意处理,下标,保证遍历完全
i--;
break;
}
}
}
}
//7.把需要写入文件的数据,写到文件中去
static void WriteShipping(String FileNmae) throws IOException {
//嵌套字符流读取
BufferedWriter buffer1 = new BufferedWriter(new FileWriter(FileNmae));
//遍历ship,读取数据
for (int i = 0; i < ship.size(); i++) {
buffer1.write(ship.get(i).toString());
buffer1.newLine();
}
//使用完要关闭流,不然可能出现错误,比如,文件为空
buffer1.close();
// buffer1.flush();
}
static void WriteErrors(String FileNmae) throws IOException {
//嵌套字符流读取
BufferedWriter buffer1 = new BufferedWriter(new FileWriter(FileNmae));
//遍历ship,读取数据
for (int i = 0; i < errors.size(); i++) {
buffer1.write(errors.get(i).toString());
buffer1.newLine();
}
buffer1.close();
}
static void WriteNewInventory(String FileNmae) throws IOException {
//嵌套字符流读取
BufferedWriter buffer1 = new BufferedWriter(new FileWriter(FileNmae));
//遍历ship,读取数据
for (int i = 0; i < I_T.size(); i++) {
buffer1.write(I_T.get(i).toString());
buffer1.newLine();
}
buffer1.close();
}
}
//抽象出两个类,作为信息储存的单位
//作为大仓库!!!
class Invent
{
//构造函数,读文件一一存入
Invent(String Item_number, int Quantity, String Supplier, String Description)
{
this.Item_number = Item_number;
this.Quantity = Quantity;
this.Supplier = Supplier;
this.Description = Description;
}
public String toString()
{
return this.Item_number + "\t" + this.Quantity + "\t" + this.Supplier + "\t" + this.Description;
}
String Item_number;//货物编号
int Quantity;//货物数量
String Supplier;//供应商编号
String Description;//货物描述
}
//O---发货订单
//R---到货记录
//A---新增货物
//D---删除货物
//相同部分作为父类属性---类型和货物编号总是要有的
class Transact
{
Transact(){};//--------查过写报告里面-----------
Transact(String Type, String Item_number)//构造函数实现类型和货物编号的初始化
{
this.Type = Type;
this.Item_number = Item_number;
}
String Type;
String Item_number;
}
//发货订单抽象类
class Work_O extends Transact
{
Work_O(String Type, String Item_number, int Quantity, String Custom)
{
super(Type, Item_number);
this.Quantity = Quantity;
this.Custom = Custom;
}
int Quantity;//订单数量
String Custom;//客户编号
}
//到货记录抽象类
class Work_R extends Transact
{
Work_R(String Type, String Item_number, int Quantity)
{
super(Type, Item_number);
this.Quantity = Quantity;
}
int Quantity;
}
//新增货物抽象类
class Work_A extends Transact
{
Work_A(String Type, String Item_number, String Supplier, String Description)
{
super(Type, Item_number);
this.Supplier = Supplier;
this.Description = Description;
}
String Supplier;//供应商编号
String Description;//货物描述
}
//删除货物抽象类
class Work_D extends Transact
{
Work_D(String Type, String Item_number)
{
super(Type, Item_number);
}
}
//客户信息发送抽象类
class Shipping
{
Shipping(String Custom, String Item_number, int Quantity)
{
this.Custom = Custom;
this.Item_number = Item_number;
this.Quantity = Quantity;
}
//用于将重复的货单,经行相加
public void add(int Quantity)
{
this.Quantity += Quantity;
}
//获取当前的数据,存入到客户信息发送文件中
public String toString()
{
return this.Custom + "\t" + this.Item_number + "\t" + this.Quantity;
}
String Custom;
String Item_number;
int Quantity;
}
//错误信息抽象类
class Errors
{
//包含未发送的发货记录,和库存量大于的删除记录
Errors(String Custom, String Item_number, int Quantity)
{
this.Custom = Custom;
this.Item_number = Item_number;
this.Quantity = Quantity;
}
//获取当前的数据,存入到错误信息文件中
public String toString()
{
return this.Custom + "\t" + this.Item_number + "\t" + this.Quantity;
}
String Custom;
String Item_number;
int Quantity;
}