学习目标:
线程实现对文件的随机读取(服务器满足客户端的请求)
学习内容:
商品类:
public class Product implements Serializable{
private int id;
private String name;
private float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return " [id=" + id + ", name=" + name + ", price=" + price
+ "]";
}
}
存数据类:
public class SaveData {
public static void main(String[] args) throws Exception {
Product p0 = new Product(0, "苹果", 10.5f);
Product p1 = new Product(1, "泰国榴莲", 16.5f);
Product p2 = new Product(2, "菠萝", 20.5f);
Product p3 = new Product(3, "菠萝蜜", 30.5f);
Product p4 = new Product(4, "香蕉", 19.5f);
save(p0);
save(p1);
save(p2);
save(p3);
save(p4);
}
public static void save(Product p) throws Exception {
// 将数据按照既定的规则存入文件中
// id占4个字节,name占20字节,price占4个字节
DataOutputStream dout = new DataOutputStream(new FileOutputStream("d:/x.txt",true));
dout.writeInt(p.getId()); //写入id
byte[] bytes = p.getName().getBytes("GBK");
byte[] b = new byte[20];
// jdk提供的数组拷贝工具方法: 参数1:源数据数组 参数2:从源数组的第几个位置开始拷贝
// 参数3 :目标数组 参数4:目标数组中放数据的起始位置 参数5:拷贝的长度
System.arraycopy(bytes, 0, b, 0, bytes.length);
dout.write(b); // 将商品名写入文件,占20个字节
dout.writeFloat(p.getPrice()); //将价格按照float数写入文件,占4个字节
dout.close();
}
}
读数据方法类:
public class ReadData {
/**
* 根据id查找商品
* @param id
* @return
* @throws Exception
*/
public Product findProductById(int id) throws Exception{
// 可以从文件中任何位置开始读数据的工具:RandomAccessFile
RandomAccessFile raf = new RandomAccessFile("d:/x.txt", "r");
// 读id为2的那个商品的数据
long pos = id*28;
// 让raf的读取位置跳到指定的pos位置
raf.seek(pos);
// 然后开始读数据即可
// 先读4个字节返回一个整数
int pId = raf.readInt();
// 再读20个字节
byte[] b = new byte[20];
int read = raf.read(b);
// 然后将这20个字节转成字符串,但是尾部有大量空格
String string = new String(b);
// 去掉首尾的空格
String name = string.trim();
// 再读价格
float price = raf.readFloat();
raf.close();
Product prodcut = new Product(pId, name, price);
return prodcut;
}
/**
* 根据名称查找商品
* @throws Exception
**/
public List<Product> findProductByName(String keyword) throws Exception {
ArrayList<Product> pList = new ArrayList<>();
// 可以从文件中任何位置开始读数据的工具:RandomAccessFile
RandomAccessFile raf = new RandomAccessFile("d:/x.txt", "r");
int i=0;
while((i+1)*28<=raf.length()) {
raf.seek(4+28*i); //将读取位置定位到名称字段的起始位置
byte[] b = new byte[20];
raf.read(b);
String name = new String(b).trim();
if(name.contains(keyword)) {
raf.seek(i*28); // 回到这条数据的起始位置
int id = raf.readInt(); // 读id数据
raf.read(b); // 读名称字段
float price = raf.readFloat(); // 读价格字段
pList.add(new Product(id, name, price)); // 将符合条件的这条数据加入list中
}
i++;
}
return pList;
}
}
服务器类:
public class NewBiDbServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(3832);
ReadData readData = new ReadData();
while (true) {
Socket sc = ss.accept();
new Thread(new FindDataRunnable(sc,readData)).start();
}
}
}
线程类:
public class FindDataRunnable implements Runnable {
Socket sc;
ReadData readData;
public FindDataRunnable(Socket sc, ReadData readData) {
this.sc = sc;
this.readData = readData;
}
@Override
public void run() {
try {
InputStream in = sc.getInputStream();
OutputStream out = sc.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
/**
* 客户端发过来的请求有两种情况: 1、SELECT * FROM p.dat WHERE id=3 // 想根据id查询商品数据
* 2、SELECT * FROM p.dat WHERE name like 菠萝 // 根据名称关键字查询商品数据
*/
byte[] b = new byte[1024];
int num = in.read(b);
String command = new String(b, 0, num);
if (command.contains("name")) {
// 根据名称关键字去查找商品
String[] split = command.split(" ");
String keyWord = split[split.length - 1];
List<Product> pList = readData.findProductByName(keyWord);
// 返回数据给客户端
oos.writeObject(pList);
// TODO
out.close();
oos.close();
in.close();
sc.close();
} else {
// 根据id去帮用户查找商品
String idStr = command.substring(command.indexOf("=") + 1);
int id = Integer.parseInt(idStr);
Product p = readData.findProductById(id);
String a = p.getId() + "," + p.getName() + "," + p.getPrice();
out.write(a.getBytes("GBK"));
out.close();
sc.close();
}
} catch (Exception e) {
}
}
}
客户端类:
public class TestClient {
@Test
public void testFindById() throws Exception {
Socket sc = new Socket("localhost", 3832);
OutputStream out = sc.getOutputStream();
InputStream in = sc.getInputStream();
out.write("SELECT * FROM p.dat WHERE id=2".getBytes());
byte[] b = new byte[100];
int num = in.read(b);
System.out.println(new String(b,0,num));
out.close();
in.close();
sc.close();
}
@Test
public void testFindByName() throws Exception {
Socket sc = new Socket("localhost", 3832);
OutputStream out = sc.getOutputStream();
out.write("SELECT * FROM p.dat WHERE name like 菠萝".getBytes());
InputStream in = sc.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
List<Product> pList = (List<Product>) ois.readObject();
System.out.println(pList);
out.close();
in.close();
ois.close();
sc.close();
}
}