准备工作:
1.在服务端和客户端项目中都建立中间传递对象,implements序列化
1 public class ContextDemo implements Serializable { 2 3 // 0:上线 1:发送信息 2:下线 3:抖窗 4:发送文件 4 private int type; 5 private HashSet<String> clients; 6 private String info; 7 private String name; 8 private String time; 9 private String last; 10 private ArrayList<Byte> list2; 11 12 public String getLast() { 13 return last; 14 } 15 16 public void setLast(String last) { 17 this.last = last; 18 } 19 public ArrayList<Byte> getList2() { 20 return list2; 21 } 22 23 public void setList2(ArrayList<Byte> list2) { 24 this.list2 = list2; 25 } 26 27 public String getName() { 28 return name; 29 } 30 31 public void setName(String name) { 32 this.name = name; 33 } 34 35 public int getType() { 36 return type; 37 } 38 39 public void setType(int type) { 40 this.type = type; 41 } 42 43 public HashSet<String> getClients() { 44 return clients; 45 } 46 47 public void setClients(HashSet<String> clients) { 48 this.clients = clients; 49 } 50 51 public String getInfo() { 52 return info; 53 } 54 55 public void setInfo(String info) { 56 this.info = info; 57 } 58 59 public String getTime() { 60 return time; 61 } 62 63 public void setTime(String time) { 64 this.time = time; 65 } 66 67 }
2.服务端实现监听
服务端静态创建一个可以监听客户端连接的serversocket和可以存储在线用户名与socket的Hashmap,服务端开启监听,并在监听到任意客户端的连接时开启一个新的服务端监听线程(将该用户的socket通过构造函数传递给这个线程)
1 public static ServerSocket ss; 2 public static HashMap<String, Socket> online; 3 public static Socket socket; 4 5 static { 6 try { 7 ss = new ServerSocket(8080); 8 System.out.println("服务器已开启"); 9 online = new HashMap<String, Socket>(); 10 } catch (IOException e) { 11 e.printStackTrace(); 12 } 13 } 14 15 public void action() { 16 try { 17 while (true) { 18 Socket s = ss.accept(); 19 System.out.println("服务器正在监听"); 20 new Server_Thread(s).start(); 21 } 22 } catch (IOException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } 26 } 27 28 public static void main(String[] args) { 29 30 new Chat_Server().action(); 31 32 }
线程中定义
(1)发送给全部在线用户的方法,主要是通过创建Hashmap的iterator来实现遍历,获取到每一个在线用户的socket,并用这个用户的socket来建立outputstream进行消息的传递
1 // 定义发送给全部用户的方法 2 public void sendtoall(ContextDemo servercontext) { 3 Collection<Socket> clients = online.values(); 4 Iterator<Socket> iterator = clients.iterator(); 5 ObjectOutputStream oo; 6 while (iterator.hasNext()) { 7 8 Socket socket = iterator.next(); 9 try { 10 oo = new ObjectOutputStream(socket.getOutputStream()); 11 oo.writeObject(servercontext); 12 oo.flush(); 13 } catch (IOException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } 17 } 18 }
(2)发送给指定用户的方法,方法实现与发送给全部用户的方法基本一致,只是需要进行判断,如果选中的用户中包含遍历出来的在线用户,再取socket进行发送
1 // 定义发送给指定用户的方法 2 public void sendtothis(ContextDemo servercontext) { 3 HashSet<String> clients = clientcontext.getClients(); 4 Set<String> oo = online.keySet(); 5 Iterator<String> it = oo.iterator(); 6 //如果用的同一个输出流对象,可能会因前一个未写完而发生错误 7 ObjectOutputStream ooo; 8 while (it.hasNext()) { 9 String name = it.next(); 10 if (clients.contains(name)) { 11 Socket s = online.get(name); 12 try { 13 ooo = new ObjectOutputStream(s.getOutputStream()); 14 ooo.writeObject(servercontext); 15 ooo.flush(); 16 } catch (IOException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 } 21 } 22 }
注意:此时应该在其中单独定义一个objectoutputstream,因为写出的时候有时间差!!!此bug耗费10小时寻找!!!!(关掉一个客户端后,另外一个报IOexcption)
线程开始不停地监听从客户端发过来的信息(中间传递对象),并判断type,通过switch语句执行不同的操作
1 @Override 2 public void run() { 3 try { 4 while (true) { 5 in = new ObjectInputStream(socket.getInputStream()); 6 clientcontext = (ContextDemo) in.readObject(); 7 8 // 分析type的种类,来用以判断执行哪种操作 9 switch (clientcontext.getType()) {
一、注册
界面:
获取到用户输入的用户名密码,进行一系列的判断,与配置文件中的数值进行比对,如果无误则保存当前用户输入的用户名、密码进配置文件,并成功登陆到聊天室界面(通过构造函数传递socket和username),否则则报错
1 try { 2 Properties userPro = new Properties(); 3 userPro.load(new FileInputStream("Users.properties")); 4 5 String username = usertext.getText(); 6 String passwordFirst = new String(password1.getPassword()); 7 String passwordLast = new String(password2.getPassword()); 8 9 if (username.length() != 0) { 10 11 if (userPro.containsKey(username)) { 12 JOptionPane.showMessageDialog(getContentPane(), "用户名已经存在!"); 13 } else { 14 15 if(passwordFirst.equals(passwordLast)){ 16 if(passwordFirst.length()!=0){ 17 userPro.setProperty(username, passwordFirst); 18 userPro.store(new FileOutputStream("Users.properties"), "用户名——密码"); 19 20 //进入聊天界面 21 Socket socket = new Socket("localhost", 8080); 22 ChatRoom chatRoom = new ChatRoom(username,socket); 23 chatRoom.setVisible(true); 24 setVisible(false); 25 }else { 26 JOptionPane.showMessageDialog(getContentPane(), "密码不能为空"); 27 } 28 }else { 29 JOptionPane.showMessageDialog(getContentPane(), "两次输入密码不一致"); 30 } 31 } 32 } else { 33 JOptionPane.showMessageDialog(getContentPane(), "用户名不能为空"); 34 } 35 } 36 catch (FileNotFoundException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } catch (IOException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 }
二、登录
界面:
用户输入用户名和密码,此时通过与项目自带的properties配置文件中的内容进行比对,如果有记录,则可以进入到聊天室(通过设置了每个testfield和登录按钮的keypressed事件,可通过检测按下回车按钮进入),若没有,则要求进入注册界面。
注意:如可以进入到聊天室界面,需要将此时新建的socket和用户名通过聊天室界面的构造函数传给聊天室。
1 try { 2 Properties properties = new Properties(); 3 properties.load(new FileInputStream("Users.properties")); 4 5 String usernameString = textusername.getText(); 6 String pasString = new String(password1.getPassword()); 7 8 if(properties.containsKey(usernameString)){ 9 if(properties.getProperty(usernameString).equals(pasString)){ 10 Socket socket = new Socket("localhost", 8080); 11 ChatRoom chatRoom = new ChatRoom(usernameString,socket); 12 chatRoom.setVisible(true); 13 setVisible(false); 14 }else { 15 JOptionPane.showMessageDialog(getContentPane(), "密码输入错误"); 16 } 17 }else { 18 JOptionPane.showMessageDialog(getContentPane(), "该用户名不存在"); 19 }
三、聊天室主界面
界面:
1.本用户上线报告服务器+服务器将该用户上线信息发送给全部用户
(1)客户端的构造函数中,将本用户的socket,用户名,当前系统时间,中间传递对象的类型(上线类型为0),封装进中间传递对象并通过socket的outputstream发送给服务端,并开启客户端线程进行监控服务端传过来的信息
1 // 上线则汇报给服务器 2 try { 3 4 out = new ObjectOutputStream(socket.getOutputStream()); 5 // 创建传输对象 6 ContextDemo clientcontext = new ContextDemo(); 7 clientcontext.setType(0); 8 clientcontext.setName(username); 9 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 10 clientcontext.setTime(sdf.format(new Date())); 11 // 发送给服务端 12 out.writeObject(clientcontext); 13 out.flush(); 14 // 开启客户端线程 15 new Client_Thread().start(); 16 17 } catch (IOException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 }
客户端线程开始监听
1 @Override 2 public void run() { 3 4 try { 5 while (true) { 6 System.out.println("客户端线程启动"); 7 in = new ObjectInputStream(socket.getInputStream()); 8 final ContextDemo servercontext = (ContextDemo) in.readObject(); 9 switch (servercontext.getType()) {
(2)服务端得到该用户的中间传递对象,判断出执行上线操作,执行相应的switch语句,将用户名与socket存入hashmap,并创建当前用户的上线信息,对象类型type,以及在线用户名的集合封装进对象发送给所有的在线用户
1 // 上线 2 case 0: 3 // 添加在线用户进online 4 { 5 6 online.put(clientcontext.getName(), socket); 7 8 ContextDemo serverContext = new ContextDemo(); 9 // 将用户上线信息发送给各客户端 10 serverContext.setType(0); 11 serverContext.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + " 上线啦!"); 12 // 将在线用户用户名全部发给客户端 13 HashSet<String> set = new HashSet<String>(); 14 set.addAll(online.keySet()); 15 serverContext.setClients(set); 16 sendtoall(serverContext); 17 break; 18 }
(3)客户端监听到信息,判断出为上下线更新操作,先清空在线列表集合,在将所要取得的各种信息从对象中取得,并获取到在线人数集合中数目以实现在线人数显示,并将上线消息显示在testArea中
1 case 0: 2 // 重新装填容器 3 { 4 // 清空容器 5 online.clear(); 6 HashSet<String> set = servercontext.getClients(); 7 Iterator<String> iterator = set.iterator(); 8 while (iterator.hasNext()) { 9 String name = iterator.next(); 10 if (username.equals(name)) { 11 online.add(name + "(本机)"); 12 13 } else { 14 online.add(name); 15 } 16 } 17 18 // 显示在list中 19 listmodel = new UUListModel(online); 20 count = listmodel.getSize(); 21 list.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "在线用户:"+count+"人", 22 TitledBorder.LEADING, TitledBorder.TOP, null, new Color(255, 0, 0))); 23 list.setModel(listmodel); 24 docs.insertString(docs.getLength(), servercontext.getInfo() + " ", attrset); 25 break; 26 }
2.发送消息
(1)客户端获取到list中选中的用户(若不选则为群发),将该选中用户、自己的用户名、时间、要发送的信息等内容封装进对象,设置type为1(发送信息识别码),将对象传递给服务器,在自己的聊天界面添加聊天的内容,随后清空list表的选中状态以及发送框的内容(发送按钮与回车键均可发送消息)
1 // 发送按钮 2 JButton btnNewButton = new JButton("u53D1u9001"); 3 btnNewButton.addActionListener(new ActionListener() { 4 public void actionPerformed(ActionEvent arg0) { 5 6 List selected = list.getSelectedValuesList(); 7 String info = textArea_1.getText(); 8 9 if (selected.size() < 1) { 10 // 在客户端中,容器online中本机的名字后面多加了字符,所以在客户端不能与hashmap中的key匹配,所以本机收不到本机传来的信息 11 selected = online; 12 } 13 14 if (info.equals("")) { 15 JOptionPane.showMessageDialog(getContentPane(), "不能发送空信息"); 16 return; 17 } 18 19 ContextDemo clientcontext = new ContextDemo(); 20 clientcontext.setInfo(info); 21 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 22 String time = sdf.format(new Date()); 23 clientcontext.setTime(time); 24 clientcontext.setType(1);// 发信息 25 clientcontext.setName(username); 26 HashSet<String> people = new HashSet<String>(); 27 people.addAll(selected); 28 29 clientcontext.setClients(people); 30 31 // 清空发送页面 32 textArea_1.setText(""); 33 // 发送界面获得焦点 34 textArea_1.requestFocus(); 35 // 列表消除选中状态 36 list.clearSelection(); 37 38 try { 39 out = new ObjectOutputStream(ChatRoom.socket.getOutputStream()); 40 out.writeObject(clientcontext); 41 out.flush(); 42 } catch (IOException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 } 46 47 try { 48 docs.insertString(docs.getLength(), time + " " + "我对"+selected+"说: " + info + " ", attrset); 49 } catch (BadLocationException e) { 50 // TODO Auto-generated catch block 51 e.printStackTrace(); 52 } 53 } 54 });
(2)服务器判断出为发送消息后,将得到的信息、时间等消息进行封装,再通过发送给指定用户的方法将封装好的对象传递给指定的用户
1 // 发信息 2 case 1: { 3 ContextDemo servercontext = new ContextDemo(); 4 servercontext.setType(1); 5 servercontext.setName(clientcontext.getName()); 6 servercontext.setInfo(clientcontext.getInfo()); 7 servercontext.setTime(clientcontext.getTime()); 8 9 sendtothis(servercontext); 10 break; 11 }
(3)指定的客户端收到对象后判断出了是要进行发送消息的操作,解封对象,取得消息等信息,在消息窗口显示
1 // 发信息 2 case 1: { 3 String info = servercontext.getInfo(); 4 String time = servercontext.getTime(); 5 docs.insertString(docs.getLength(), 6 time + " " + servercontext.getName() + "对我说: " + info + " ", attrset); 7 break; 8 }
3.下线
(1)聊天室页面添加窗口关闭的监听事件,在其后弹出对话框确定是否退出,若退出则设置type为2(下线识别码)、时间等信息封装进对象发送给服务器
1 // 下线操作 2 this.addWindowListener(new WindowAdapter() { 3 @Override 4 public void windowClosing(WindowEvent e) { 5 6 int result = JOptionPane.showConfirmDialog(getContentPane(),"您确定要离开聊天室"); 7 if (result == 0) { 8 ContextDemo clientcontext = new ContextDemo(); 9 clientcontext.setType(2); 10 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 11 clientcontext.setTime(sdf.format(new Date())); 12 clientcontext.setName(username); 13 14 try { 15 out = new ObjectOutputStream(socket.getOutputStream()); 16 out.writeObject(clientcontext); 17 out.flush(); 18 } catch (IOException e1) { 19 // TODO Auto-generated catch block 20 e1.printStackTrace(); 21 } 22 } 23 } 24 });
(2)服务器判断为是下线操作后,首先建立服务端对象,设置type为2,用当前用户传递过来的socket传递此对象给即将下线的客户端批准其下线,随后用下线用户的用户名在Hashmap中删除此用户,随后新建另一服务端对象,封装下线的信息、时间、当前在线用户名等内容发送给其余所有在线的客户端,让他们执行上下线更新操作,并在case的最后用return退出whlie(true)循环,在finally中关闭掉输入输出流对象与socket对象,意在此客户端与服务端的线程关闭
1 // 下线 2 case 2: { 3 // 通知请求下线客户端,批准下线 4 ContextDemo servercontext1 = new ContextDemo(); 5 servercontext1.setType(2); 6 out = new ObjectOutputStream(socket.getOutputStream()); 7 out.writeObject(servercontext1); 8 out.flush();//需要时间 9 10 // 刷新在线hashmap 11 online.remove(clientcontext.getName()); 12 13 // 通知其他在线用户,该用户已下线 14 ContextDemo servercontext2 = new ContextDemo(); 15 servercontext2.setType(0); 16 servercontext2.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + "用户已下线 "); 17 HashSet<String> set = new HashSet<String>(); 18 set.addAll(online.keySet()); 19 servercontext2.setClients(set); 20 sendtoall(servercontext2); 21 // 退出当前循环,不再监听该客户端传来的信息 22 return; 23 }
(3)
1)即将下线的客户端接收到对象后,判断出是执行下线操作,用return退出while(true),并在finally中关闭掉socket与输入输出流对象,并用System.exit(0)退出虚拟机断线
1 // 下线 2 case 2:{ 3 return; 4 }
2)其余在线客户端接收到对象,判断是要进行上下线操作,所以执行与上线更新时一样的操作
1 // 上下线刷新操作 2 case 0: 3 // 重新装填容器 4 { 5 // 清空容器 6 online.clear(); 7 HashSet<String> set = servercontext.getClients(); 8 Iterator<String> iterator = set.iterator(); 9 while (iterator.hasNext()) { 10 String name = iterator.next(); 11 if (username.equals(name)) { 12 online.add(name + "(本机)"); 13 14 } else { 15 online.add(name); 16 } 17 } 18 19 // 显示在list中 20 listmodel = new UUListModel(online); 21 count = listmodel.getSize(); 22 list.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "在线用户:"+count+"人", 23 TitledBorder.LEADING, TitledBorder.TOP, null, new Color(255, 0, 0))); 24 list.setModel(listmodel); 25 docs.insertString(docs.getLength(), servercontext.getInfo() + " ", attrset); 26 break; 27 }
4.抖窗
(1)客户端将列表中得到的用户名封装进对象,设置type为3,再将时间等信息封装进对象,将对象发送给服务端
1 btnShakeFrame.addActionListener(new ActionListener() { 2 public void actionPerformed(ActionEvent e) { 3 4 List selected = list.getSelectedValuesList(); 5 6 if (selected.size() < 1) { 7 // 在客户端中,容器online中本机的名字后面多加了字符,所以在客户端不能与hashmap中的key匹配,所以本机收不到本机传来的信息 8 selected = online; 9 } 10 11 ContextDemo clientcontext = new ContextDemo(); 12 clientcontext.setType(3); 13 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 14 String time = sdf.format(new Date()); 15 clientcontext.setTime(time); 16 clientcontext.setName(username); 17 HashSet<String> set = new HashSet<String>(); 18 set.addAll(selected); 19 clientcontext.setClients(set); 20 21 // 列表消除选中状态 22 list.clearSelection(); 23 24 try { 25 out = new ObjectOutputStream(socket.getOutputStream()); 26 out.writeObject(clientcontext); 27 out.flush(); 28 } catch (IOException e1) { 29 // TODO Auto-generated catch block 30 e1.printStackTrace(); 31 } 32 33 try { 34 docs.insertString(docs.getLength(), time + "您发送了一个屏幕抖动 ", attrset); 35 } catch (BadLocationException e1) { 36 // TODO Auto-generated catch block 37 e1.printStackTrace(); 38 } 39 } 40 });
(2)服务端判断出是要进行抖窗操作后,封装有用的信息进对象,并通过发送给指定用户方法进行发送
1 // 抖窗 2 case 3: { 3 ContextDemo servercontext = new ContextDemo(); 4 servercontext.setType(3); 5 servercontext.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + "对你抖了一下屏 "); 6 7 sendtothis(servercontext); 8 break; 9 }
(3)指定的客户端判断要进行抖屏,先解封有用的信息进消息显示窗口,然后再调用封装好的抖屏方法进行抖屏操作
1 // 抖窗 2 case 3: { 3 String info = servercontext.getInfo(); 4 docs.insertString(docs.getLength(), info, attrset); 5 shakeFrame(); 6 break; 7 }
1 public void shakeFrame() { 2 int x = ChatRoom.this.getX(); 3 int y = ChatRoom.this.getY(); 4 for (int i = 0; i < 20; i++) { 5 if ((i & 1) == 0) { 6 x += 8; 7 y += 8; 8 } else { 9 x -= 8; 10 y -= 8; 11 } 12 ChatRoom.this.setLocation(x, y); 13 try { 14 Thread.sleep(50); 15 } catch (InterruptedException e1) { 16 e1.printStackTrace(); 17 } 18 } 19 }
5.发送文件
(1)客户端先获取到想要发送文件给哪个用户的用户名,随后弹出文件选择框,构建文件的抽象路径,并得到后缀名,其后通过文件的输入流将所得到的文件一个字节一个字节的读入到Arraylist<byte>集合中,将后缀名保存到一个字符串中,将这些与其他有用的信息一起封装进对象,将对象发送给服务器
1 btnSendFile.addActionListener(new ActionListener() { 2 public void actionPerformed(ActionEvent e) { 3 4 List selected = list.getSelectedValuesList(); 5 if (selected.size() < 1) { 6 JOptionPane.showMessageDialog(getContentPane(), "必须选择一名用户"); 7 return; 8 } 9 if (selected.toString().contains(username+"(本机)")) { 10 JOptionPane.showMessageDialog(getContentPane(), "不能向自己发送文件"); 11 return; 12 } 13 14 JFileChooser chooser = new JFileChooser(); 15 chooser.setDialogTitle("选择文件框"); 16 chooser.showDialog(getContentPane(), "选择"); 17 18 //判断是否拿到文件 19 if(chooser.getSelectedFile()!=null){ 20 path = chooser.getSelectedFile().getPath(); 21 file = new File(path); 22 //获取文件的后缀名 23 int i =file.getName().indexOf("."); 24 last = file.getName().substring(i); 25 26 //判断文件是否为空 27 if(file.length()==0){ 28 JOptionPane.showMessageDialog(getContentPane(), "文件为空,不能传送"); 29 return; 30 } 31 } 32 33 ContextDemo clientcontext = new ContextDemo(); 34 //发送文件(基础工作) 35 clientcontext.setType(4); 36 //保存后缀名 37 clientcontext.setLast(last); 38 clientcontext.setName(username); 39 HashSet<String> set = new HashSet<String>(); 40 set.addAll(selected); 41 clientcontext.setClients(set); 42 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 43 String time = sdf.format(new Date()); 44 clientcontext.setTime(time); 45 46 //发送文件(文件部分操作) 47 list2 = new ArrayList<Byte>(); 48 try { 49 input = new FileInputStream(file); 50 51 int result = -1; 52 53 while((result = input.read()) != -1) 54 { 55 list2.add((byte)result); 56 } 57 58 59 60 } catch (FileNotFoundException e2) { 61 // TODO Auto-generated catch block 62 e2.printStackTrace(); 63 } catch (IOException e1) { 64 // TODO Auto-generated catch block 65 e1.printStackTrace(); 66 }finally { 67 68 try { 69 if(input != null) 70 { 71 input.close(); 72 } 73 } catch (IOException e1) { 74 e1.printStackTrace(); 75 } 76 } 77 78 clientcontext.setList2(list2); 79 80 81 // 列表消除选中状态 82 list.clearSelection(); 83 84 //发送给服务端 85 try { 86 out = new ObjectOutputStream(socket.getOutputStream()); 87 out.writeObject(clientcontext); 88 out.flush(); 89 } catch (IOException e1) { 90 // TODO Auto-generated catch block 91 e1.printStackTrace(); 92 } 93 94 try { 95 docs.insertString(docs.getLength(), time + "您发送了一个文件 ", attrset); 96 } catch (BadLocationException e1) { 97 // TODO Auto-generated catch block 98 e1.printStackTrace(); 99 } 100 } 101 }); 102
(2)服务端判断出是要进行文件的发送操作,将所有有用的信息封装进对象发送给指定的用户
1 // 发送文件 2 case 4: { 3 ContextDemo servercontext = new ContextDemo(); 4 servercontext.setList2(clientcontext.getList2()); 5 servercontext.setLast(clientcontext.getLast()); 6 servercontext.setInfo(clientcontext.getTime() + " " + clientcontext.getName() + "对你发送了一个文件 "); 7 servercontext.setType(4); 8 9 sendtothis(servercontext); 10 11 break; 12 }
(3)指定客户端收到对象后,先将字节集合解封出来,用iterator将字节写入一个字节数组,再通过缓冲字节流读入字节,通过解封出来的后缀名构造好新的文件后,通过缓冲字节流写入文件,并接收到需要的信息显示在消息窗口中
1 //接收到文件 2 case 4: 3 { 4 ArrayList<Byte> list3 = new ArrayList<Byte>(); 5 list3 = servercontext.getList2(); 6 Iterator<Byte> it = list3.iterator(); 7 byte[] dedao = new byte[10000000]; 8 int i = 0; 9 while(it.hasNext()){ 10 dedao[i] = it.next(); 11 i++; 12 } 13 14 15 ii = new ByteArrayInputStream(dedao); 16 inputStream = new BufferedInputStream(ii,10000); 17 //获取后缀名 18 String thLast = servercontext.getLast(); 19 output = new FileOutputStream("sourse/dedao"+thLast); 20 outputStream = new BufferedOutputStream(output,10000); 21 22 byte[] b = new byte[10000];//暂存读取的字节内容 23 int result = -1; 24 while((result = inputStream.read(b)) != -1) 25 { 26 outputStream.write(b, 0, result); 27 } 28 output.flush(); 29 30 31 32 String info = servercontext.getInfo(); 33 docs.insertString(docs.getLength(), info, attrset); 34 break; 35 }