线程实现对文件的随机读取(服务器满足客户端的请求)

学习目标:

线程实现对文件的随机读取(服务器满足客户端的请求)

学习内容:

商品类:

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();	
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值