C语言 超市商品(Goods) 销售 (Stock) 信息管理软件

2024-04-07 08:20

本文主要是介绍C语言 超市商品(Goods) 销售 (Stock) 信息管理软件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

超市商品(Goods) 销售 (Stock) 信息管理软件

数据结构描述:

商品号 商品名 分类 单价 进货量 出货量 库存量 总价 登记日期 生产厂家 电话

数据结构定义:

struct GoodsStock{int Gno;//商品编号char Gname[15];//商品名称char category[10]; //商品分类:如蔬菜类、肉类、米面类等float price;//单价int input; //入库量int output; //出库量int stock; //库存量float totalPrice; //库存总价totalPrice=stock *price:unsigned int date; //商品登记日期 例如20240125 表示2024年1月25日char manufacturer[15]; //生产厂家int Tel; //联系电话
}
// 软件实现步骤:
// (1) 商品数据输入
// 输入商品数据,包括商品号、商品名、分类、单价、进货量、出货量、库存量、总价、登记日期、生产厂家、电话。
// (2) 商品数据输出
// 输出商品数据,包括商品号、商品名、分类、单价、进货量、出货量、库存量、总价、登记日期、生产厂家、电话。
// (3) 统计截止到某月份库存商品余额
// 输入某月份,计算截止到该月份的库存商品余额。
// (4)按商品分类统计入库量和出库量
// 输入商品分类,统计该分类的入库量和出库量。
// (5)按商品号查询商品对应的数据
// 输入商品号,查询商品对应的数据。
// (6)按商品名称查询商品对应的数据
// 输入商品名称,查询商品对应的数据。
// (7)查询低值易耗品明细 (低值易耗品对应多条记录)
// 输出低值易耗品明细,包括商品号、商品名、分类、单价、进货量、出货量、库存量、总价、登记日期、生产厂家、电话。
// (8)按商品分类排序
// 输出按商品分类排序的商品数据。
// (9)价排序
// 输出按单价排序的商品数据。
// (10)修改数据据
// 输入商品号、修改的字段、修改后的值,修改商品对应的数据。
// (12)删除数据
// 输入商品号,删除商品对应的数据。
// (13)存储数据
// 存储商品数据到文件。// 软件实现难点:
// * (1) 商品数据输入
// * (2) 商品数据输出
// * (3) 统计截止到某月份库存商品余额
// * (4)按商品分类统计入库量和出库量
// * (5)按商品号查询商品对应的数据
// * (6)按商品名称查询商品对应的数据
// * (7)查询低值易耗品明细 (低值易耗品对应多条记录)
// * (8)按商品分类排序
// * (9)价排序
// * (10)修改数据据
// * (12)删除数据
// * (13)存储数据

c

软件功能

  • (1)商品数据输入 --以实现
  • (2)商品数据输出 --以实现
  • (3) 统计截止到某月份库存商品余额 --以实现
  • (4)按商品分类统计入库量和出库量 --以实现
  • (5)按商品号查询商品对应的数据 --以实现
  • (6)按商品名称查询商品对应的数据 --以实现
  • (7)查询低值易耗品明细 (低值易耗品对应多条记录) --以实现
  • (8)按商品分类排序 --以实现
  • (9)单价排序 --以实现
  • (10)修改数据 --以实现
  • (12)删除数据 --以实现
  • (13)存储数据 --以实现
  • (14)读取数据 --以实现

说明:

  • (1)低值易耗品指单价<100元的商品
  • (2) 余额=(本月份之前input - 本月份之前output) *price

一号源码

// 用c语言实现超市商品(Goods) 销售 (Stock) 信息管理软件
// 数据结构描述:商品号 商品名 分类 单价 进货量 出货量 库存量 总价 登记日期  生产厂家  电话
// 需要实现的功能有
// * (1)商品数据输入
// * (2)商品数据输出
// * (3) 统计截止到某月份库存商品余额
// * (4)按商品分类统计入库量和出库量
// * (5)按商品号查询商品对应的数据
// * (6)按商品名称查询商品对应的数据
// * (7)查询低值易耗品明细 (低值易耗品对应多条记录)
// * (8)按商品分类排序
// * (9)价排序
// * (10)修改数据据
// * (12)删除数据
// * (13)存储数据
// 数据结构定义:#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MAX_GOODS_NUM 100 // 商品最大数量
#define MAX_NAME_LEN 20 // 商品名称最大长度
#define MAX_CATEGORY_LEN 20 // 商品分类最大长度
#define MAX_DATE_LEN 20 // 日期最大长度typedef struct Goods {int goods_num; // 商品号char name[MAX_NAME_LEN]; // 商品名称char category[MAX_CATEGORY_LEN]; // 商品分类    float price; // 商品单价int in_num; // 进货量int out_num; // 出货量int stock_num; // 库存量    float total_price; // 总价char date[MAX_DATE_LEN]; // 登记日期//商品登记日期 例如20240125 表示2024年1月25日char producer[MAX_NAME_LEN]; // 生产厂家char phone[MAX_NAME_LEN]; // 电话    
} Goods;Goods goods[MAX_GOODS_NUM]; // 商品数组
int goods_num = 0; // 商品数量// 商品数据输入
void input_goods() {Goods g;printf("请输入商品号: ");scanf("%d", &g.goods_num);printf("请输入商品名称: ");scanf("%s", g.name);printf("请输入商品分类: ");scanf("%s", g.category);printf("请输入商品单价: ");scanf("%f", &g.price);printf("请输入进货量: ");scanf("%d", &g.in_num);printf("请输入出货量: ");scanf("%d", &g.out_num);printf("请输入库存量: ");scanf("%d", &g.stock_num);g.total_price = g.price * g.stock_num;printf("请输入登记日期: ");scanf("%s", g.date);printf("请输入生产厂家: ");scanf("%s", g.producer);printf("请输入电话: ");scanf("%s", g.phone);goods[goods_num] = g;goods_num++;
}// 商品数据输出以表格的形式输出一定要对齐
// 用虚线绘制表格进行输出
void output_goods() {printf("%-10s%-10s%-10s%-10s%-8s%-8s%-8s%-10s%-12s%-10s%s\n", "商品号", "商品名称", "商品分类", "商品单价", "进货量", "出货量", "库存量", "总价", "登记日期", "生产厂家", "电话");printf("--------------------------------------------您的数据如下------------------------------------------\n");for (int i = 0; i < goods_num; i++) {printf("%-10d%-10s%-10s%.2f\t%-8d%-8d%-8d%.2f\t%-12s%-10s%s\n", goods[i].goods_num, goods[i].name, goods[i].category, goods[i].price, goods[i].in_num, goods[i].out_num, goods[i].stock_num, goods[i].total_price, goods[i].date, goods[i].producer, goods[i].phone);}
}
// void output_goods() {
//     for (int i = 0; i < goods_num; i++) {
//         printf("商品号: %d\n", goods[i].goods_num);
//         printf("商品名称: %s\n", goods[i].name);
//         printf("商品分类: %s\n", goods[i].category);
//         printf("商品单价: %.2f\n", goods[i].price);
//         printf("进货量: %d\n", goods[i].in_num);
//         printf("出货量: %d\n", goods[i].out_num);
//         printf("库存量: %d\n", goods[i].stock_num);
//         printf("总价: %.2f\n", goods[i].total_price);
//         printf("登记日期: %s\n", goods[i].date);
//         printf("生产厂家: %s\n", goods[i].producer);
//         printf("电话: %s\n", goods[i].phone);
//     }
// }// 统计截止到某月份库存商品余额
// 余额=(本月份之前input - 本月份之前output) *price
// 这是数据用例
// 商品号    商品名称  商品分类  商品单价  进货量  出货量  库存量  总价      登记日期    生产厂家  电话
// --------------------------------------------您的数据如下------------------------------------------
// 1         手机      数码      999.00    10      7       10      9990.00 20230201    安徽      199
// 2         手机      数码      888.00    10      2       10      8880.00 20230301    安徽      2void balance_goods() {int month;printf("请输入月份: ");scanf("%d", &month);int in_num = 0;int out_num = 0;for (int i = 0; i < goods_num; i++) {if (goods[i].date[0] < month) {in_num += goods[i].in_num;out_num += goods[i].out_num;}}float balance = (in_num - out_num) * goods[0].price;printf("截止到%d的库存商品余额为: %.2f\n", month, balance);
}// 按商品分类统计入库量和出库量
void category_inout() {char category[MAX_CATEGORY_LEN];printf("请输入商品分类: ");scanf("%s", category);int in_num = 0;int out_num = 0;for (int i = 0; i < goods_num; i++) {if (strcmp(goods[i].category, category) == 0) {in_num += goods[i].in_num;out_num += goods[i].out_num;}}printf("商品分类%s的入库量为: %d\n", category, in_num);printf("商品分类%s的出库量为: %d\n", category, out_num);
}// 按商品号查询商品对应的数据
void query_goods_num() {int goods_num;printf("请输入商品号: ");scanf("%d", &goods_num);for (int i = 0; i < goods_num; i++) {if (goods[i].goods_num == goods_num) {printf("商品号: %d\n", goods[i].goods_num);printf("商品名称: %s\n", goods[i].name);printf("商品分类: %s\n", goods[i].category);printf("商品单价: %.2f\n", goods[i].price);printf("进货量: %d\n", goods[i].in_num);printf("出货量: %d\n", goods[i].out_num);printf("库存量: %d\n", goods[i].stock_num);printf("总价: %.2f\n", goods[i].total_price);printf("登记日期: %s\n", goods[i].date);printf("生产厂家: %s\n", goods[i].producer);printf("电话: %s\n", goods[i].phone);break;}}
}// 按商品名称查询商品对应的数据
void query_goods_name() {char name[MAX_NAME_LEN];printf("请输入商品名称: ");scanf("%s", name);for (int i = 0; i < goods_num; i++) {if (strcmp(goods[i].name, name) == 0) {printf("商品号: %d\n", goods[i].goods_num);printf("商品名称: %s\n", goods[i].name);printf("商品分类: %s\n", goods[i].category);printf("商品单价: %.2f\n", goods[i].price);printf("进货量: %d\n", goods[i].in_num);printf("出货量: %d\n", goods[i].out_num);printf("库存量: %d\n", goods[i].stock_num);printf("总价: %.2f\n", goods[i].total_price);printf("登记日期: %s\n", goods[i].date);printf("生产厂家: %s\n", goods[i].producer);printf("电话: %s\n", goods[i].phone);break;}}
}// 查询低值易耗品明细 (低值易耗品对应多条记录)
void low_value_goods() {printf("%-10s%-10s%-10s%-10s%-8s%-8s%-8s%-10s%-12s%-10s%s\n", "商品号", "商品名称", "商品分类", "商品单价", "进货量", "出货量", "库存量", "总价", "登记日期", "生产厂家", "电话");printf("--------------------------------------------低易耗品数据如下------------------------------------------\n");for (int i = 0; i < goods_num; i++) {if (goods[i].price < 100) {printf("%-10d%-10s%-10s%.2f\t%-8d%-8d%-8d%.2f\t%-12s%-10s%s\n", goods[i].goods_num, goods[i].name, goods[i].category, goods[i].price, goods[i].in_num, goods[i].out_num, goods[i].stock_num, goods[i].total_price, goods[i].date, goods[i].producer, goods[i].phone);}}
}// 按商品分类排序
void sort_category() {for (int i = 0; i < goods_num - 1; i++) {for (int j = i + 1; j < goods_num; j++) {if (strcmp(goods[i].category, goods[j].category) > 0) {Goods temp = goods[i];goods[i] = goods[j];goods[j] = temp;}}}output_goods();
}// 价排序
void sort_price() {for (int i = 0; i < goods_num - 1; i++) {for (int j = i + 1; j < goods_num; j++) {if (goods[i].price > goods[j].price) {Goods temp = goods[i];                goods[i] = goods[j];goods[j] = temp;}}        }output_goods();
}   // 修改数据据
void modify_goods() {int goods_num;printf("请输入需要修改的商品号: ");    scanf("%d", &goods_num);for (int i = 0; i < goods_num; i++) {if (goods[i].goods_num == goods_num) {printf("请输入新的商品名称: ");            scanf("%s", goods[i].name);printf("请输入新的商品分类: ");            scanf("%s", goods[i].category);printf("请输入新的商品单价: ");            scanf("%f", &goods[i].price);printf("请输入新的进货量: ");            scanf("%d", &goods[i].in_num);printf("请输入新的出货量: ");            scanf("%d", &goods[i].out_num);printf("请输入新的库存量: ");            scanf("%d", &goods[i].stock_num);goods[i].total_price = goods[i].price * goods[i].stock_num;printf("请输入新的登记日期: ");            scanf("%s", goods[i].date);printf("请输入新的生产厂家: ");            scanf("%s", goods[i].producer);printf("请输入新的电话: ");            scanf("%s", goods[i].phone);break;}}
}// 删除数据
void delete_goods() {int del_goods_num;printf("请输入需要删除的商品号: ");    scanf("%d", &del_goods_num);// 当商品号相等的时候删除该数据for (int i = 0; i < goods_num; i++) {if (goods[i].goods_num == del_goods_num) {// 清空要删除的元素memset(&goods[i], 0, sizeof(Goods));// 将后面的元素全部向前移动for (int j = i; j < goods_num - 1; j++) {goods[j] = goods[j + 1];}// 最后一个元素需要清空memset(&goods[goods_num - 1], 0, sizeof(Goods));goods_num--;break;}}
}// 存储数据
void save_goods() {FILE *fp;fp = fopen("goods.dat", "wb");if (fp == NULL) {printf("文件打开失败!\n");return;}fwrite(&goods_num, sizeof(int), 1, fp);for (int i = 0; i < goods_num; i++) {fwrite(&goods[i], sizeof(Goods), 1, fp);}printf("数据存储成功!\n");fclose(fp);
}// 读取数据
void load_goods() {FILE *fp;fp = fopen("goods.dat", "rb");if (fp == NULL) {printf("文件打开失败!\n");return;}fread(&goods_num, sizeof(int), 1, fp);for (int i = 0; i < goods_num; i++) {fread(&goods[i], sizeof(Goods), 1, fp);}printf("数据读取成功!\n");fclose(fp);
}int main() {int choice;while (1) {printf("1. 商品数据输入\n");printf("2. 商品数据输出\n");printf("3. 统计截止到某月份库存商品余额\n");printf("4. 按商品分类统计入库量和出库量\n");printf("5. 按商品号查询商品对应的数据\n");printf("6. 按商品名称查询商品对应的数据\n");printf("7. 查询低值易耗品明细\n");printf("8. 按商品分类排序\n");printf("9. 价排序\n");printf("10. 修改数据据\n");printf("11. 删除数据\n");printf("12. 存储数据\n");printf("13. 读取数据\n");printf("0. 退出\n");printf("请输入选项: ");scanf("%d", &choice);switch (choice) {case 1:input_goods();break;case 2:output_goods();break;case 3:stock_balance();break;case 4:category_inout();break;case 5:query_goods_num();break;case 6:query_goods_name();break;case 7:low_value_goods();break;case 8:sort_category();break;case 9:sort_price();break;case 10:modify_goods();break;case 11:delete_goods();break;case 12:save_goods();break;case 13:load_goods();break;case 0:return 0;default:printf("输入错误!\n");break;}}return 0;
}

关于答辩可能会被问到的问题

一:

这个名为balance_goods的函数的功能是计算截止到指定月份的库存商品余额。

具体工作流程如下:

  1. 程序首先要求用户输入一个月份。
  2. 随后,程序将遍历商品列表,在遍历过程中,它会检查每个商品的登记日期的月份部分,如果小于等于用户输入的月份,就会将相应的进货量和出货量累加到in_numout_num中。
  3. 接着,程序会使用累加后的in_numout_num计算库存余额,它会首先计算进货量和出货量的差值,然后乘以第一个商品的单价得到库存余额。
  4. 最后,程序会输出截止到指定月份的库存商品余额。

需要注意的是,在这个函数中,“goods_num”和“goods”是全局变量,函数会直接访问它们。另外,该函数假设了第一个商品的单价适用于所有商品,这一点可能需要根据实际需求进行调整。

二:

这个名为 category_inout 的函数的功能是统计特定商品分类的入库量和出库量。

程序工作如下:

  1. 首先,函数要求用户输入一个商品分类。
  2. 然后,程序会遍历商品列表,针对每个商品,检查其商品分类是否与用户输入的相匹配。这里使用了 strcmp 函数来比较字符串。
  3. 对于属于用户输入的商品分类的商品,它将把相应的进货量和出货量累加到 in_numout_num 中。
  4. 最后,程序输出特定商品分类的入库量和出库量。

strcmp 函数用于比较两个字符串是否相等,如果相等则返回0,否则返回一个非零值。在这里,它用于比较商品的分类信息,以确定是否属于用户输入的商品分类。

需要注意的是,这个函数假设用户输入的商品分类是准确的,并且商品分类信息是正确地存储在 goods 结构体数组中。如果用户输入的是一个不存在的商品分类,或者商品分类信息有误,这个函数可能不会得到准确的结果。

这个函数的原理是通过遍历商品列表,并根据用户输入的商品分类信息进行统计。如果您对这个函数有更多的问题或需要

三:

这个名为 sort_category 的函数的功能是对商品列表按照商品分类进行排序,并且在排序完成后调用 output_goods 函数来输出排序后的商品信息。

函数的工作原理如下:

  1. 外部循环从第一个商品到倒数第二个商品,用变量 i 表示当前比较的商品的索引。
  2. 内部循环从外部循环的下一个商品到最后一个商品,用变量 j 表示当前正在比较的商品的索引。
  3. 对于每一对商品 (goods[i]goods[j]),使用 strcmp 函数比较它们的商品分类。如果 goods[i] 的商品分类大于 goods[j] 的商品分类(按照字典顺序),则交换它们的位置,这样就能够实现按照商品分类进行升序排序。
  4. 当外部循环结束时,商品列表将按照商品分类进行了排序。
  5. 最后,调用 output_goods 函数来输出排序后的商品信息。

需要注意的是,这里使用了所谓的“冒泡排序”算法来对商品列表进行排序。冒泡排序算法通过多次遍历未排序部分,并且两两比较相邻元素的大小,将较大(或较小)的元素交换到右边,逐步将未排序部分中较大(或较小)的元素“浮”到顶端,最终完成整个列表的排序。

在这个函数中,每次外部循环都会将当前未排序部分中最小的元素“浮”到顶端,直到整个列表完成排序。

四:

这个名为 save_goods 的函数使用了文件操作来将商品数据存储到一个名为 “goods.dat” 的二进制文件中。

下面是函数的工作原理:

  1. 使用 fopen 函数以二进制写入模式打开一个名为 “goods.dat” 的文件。
  2. 如果文件打开失败(fp == NULL),则输出错误信息并且函数提前返回。
  3. 如果文件成功打开,则先将商品数量 goods_num 写入文件,以便在读取数据时知道该读取多少个商品数据。
  4. 然后,对于每个商品,使用 fwrite 函数将商品信息以结构体的形式写入到文件中。
  5. 最后,输出数据存储成功的信息,并且关闭文件。

这种方法使用了 C 语言标准库中的文件操作函数,这些函数提供了一种将数据持久化到文件的方法。使用二进制写入模式,可以将数据按照它们在内存中的表示直接写入到文件中。

值得注意的是,这种二进制文件存储的方法相对来说更加高效,因为它直接将数据存储到文件中,而不需要像文本文件一样进行额外的转换和解析。

五:

该程序在是怎么存储的数据?

程序中使用了结构体 Goods 来存储商品数据,结构体中包含了商品号、商品名称、商品分类、商品单价、进货量、出货量、库存量、总价、登记日期、生产厂家、电话等信息。

程序中使用了数组 goods 来存储商品数据,数组的大小为 MAX_GOODS_NUM,用来存储商品数据。

程序中使用了文件操作函数来存储和读取数据,文件名为 goods.dat。

程序中使用了 memset 函数来清空数组元素,memset 函数用来将内存块中的数据清零,memset 函数的第一个参数是指向要清零的内存块的指针,第二个参数是要清零的内存块的大小,第三个参数是要清零的值。

这篇关于C语言 超市商品(Goods) 销售 (Stock) 信息管理软件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/882099

相关文章

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

Ubuntu 怎么启用 Universe 和 Multiverse 软件源?

《Ubuntu怎么启用Universe和Multiverse软件源?》在Ubuntu中,软件源是用于获取和安装软件的服务器,通过设置和管理软件源,您可以确保系统能够从可靠的来源获取最新的软件... Ubuntu 是一款广受认可且声誉良好的开源操作系统,允许用户通过其庞大的软件包来定制和增强计算体验。这些软件

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2