文件和文件夹的基本操作 public class TestFile { public static void main(String[] args) throws IOException { File file = new File("d:/a");//文件对象 //String[] list = file.list(); //File[] listFiles = file.listFiles(); String[] list = file.list(new FilenameFilter() { public boolean accept(File dir, String name) { return name.contains("a"); } }); System.out.println(Arrays.toString(list)); //file.createNewFile(); //System.out.println(file.exists());//判断是否存在 //System.out.println(file.canRead()); //System.out.println(file.canWrite()); //System.out.println(file.delete()); //System.out.println(file.getAbsolutePath()); //System.out.println(file.getName()); //String fileName = file.getName(); //System.out.println(fileName.substring(fileName.lastIndexOf(".")+1)); // String parent = file.getParent(); // System.out.println(parent); //long freeSpace = file.getFreeSpace(); //System.out.println(freeSpace); //System.out.println(file.length()); //System.out.println(file.getPath()); //System.out.println(file.isFile()); //file.mkdirs(); //System.out.println(file.isDirectory()); } }
java中有四大家族的流,他们都是抽象类:
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流
对于文件有这些流常用:
java.io.FileInputStream
java.io.FIleOUtStream
java.io.FileReader
java.io.FileWriter
对象有关的流:
java.io.ObjectInputStream
java.io.ObjectOutputStream
转换流:
OutputStreamWriter
InputStreamReader
文件的读和写:
public static void main(String[] args) throws Exception{ //创建流---指定文件位置 InputStream is = new FileInputStream("d:/a.txt"); OutputStream os = new FileOutputStream("d:/b.txt",true);//已经创建了b.txt //调用流的方法去读和写 //一个字节一个字节读 // int data; // while((data= is.read())!=-1) { // System.out.println((char)data); // } //一次读多个字节 byte[] data = new byte[4];//缓存数组--8*1024 int length; while((length = is.read(data))!=-1) { //输出到控制台 System.out.println(new String(data,0,length)); os.write(data, 0, length); } os.write(10);//换行 //关闭资源 is.close(); os.close(); System.out.println("over"); } //找一张图片或者音乐,用字节流操作来复制一下这个图片或音乐 public class TestCopyPic { public static void main(String[] args) { InputStream is= null; OutputStream os = null; try { is = new FileInputStream("d:/th.jpg"); os = new FileOutputStream("d:/a/th.jpg",true); byte[] buf = new byte[8*1024]; int length=-1; while((length=is.read(buf))!=-1) { os.write(buf, 0, length); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { //先开的后关 try { os.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } } }
FileWriter和FileReader中的操作方式和FileInputStream以及FileOutStream相似
FileReader fileReader = new FileReader("G:/b/b.text"); BufferedReader bufferedReader = new BufferedReader(fileReader); String s2 = null; while((s2 = bufferedReader.readLine()) != null){ System.out.println(s2); } bufferedReader.close(); FileWriter fileWriter = new FileWriter("G:/b/b.text"); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.newLine(); bufferedWriter.write(123); bufferedWriter.flush(); bufferedWriter.close();
//反序列化流--将序列化过程中所生产的二级制串转化成数据结构或对象 public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants{} //序列化流--将数据结构或对象转换成二进制串 public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants{} //Serializable接口,当一个类的实例要被对象流读写时,要求必须实现serializable接口
服务端:
ServerSocket server = new ServerSocket(6666); //启动监听 Socket socket = server.accept(); //一直没有接收到客户端信号就一直阻塞 System.out.println(socket.getInetAddress().getHostAddress()+"连接了服务器");
客户端:
Socket socket = new Socket("10.7.163.102", 6666);
交互客户端:
package com.qf.cdjava2201.day24.chat; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; public class Server { //接收消息,并且转发消息给所有的客户端--集合,也可以使用线程池 List<ThreadSocket> clients = new ArrayList<Server.ThreadSocket>(); public void start() { try { ServerSocket server = new ServerSocket(8888); while(true) { Socket socket = server.accept(); //接收客户端连接 System.out.println(socket.getInetAddress().getHostAddress()+"连接了服务器"); //保存这个客户端 ThreadSocket client = new ThreadSocket(socket); clients.add(client); new Thread(client).start(); } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new Server().start(); } public class ThreadSocket implements Runnable{ Socket socket; String name; public ThreadSocket(Socket socket) { this.socket = socket; } //处理每个客户端的聊天信息 public void run() { //接收一个名字 try { //从socket中获取输入流并建立缓冲区进行读取 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); name = br.readLine(); //把名字广播给所有的客户端 String msg = "欢迎"+name+"进入聊天室"; sendMsg(msg); while(true) { //接收消息并转发 BufferedReader br1 = new BufferedReader(new InputStreamReader(socket.getInputStream())); String info = br1.readLine(); sendMsg(name+"["+socket.getInetAddress().getHostAddress()+"]:"+info); System.out.println(name+"["+socket.getInetAddress().getHostAddress()+"]:"+info); if(info.equals("88")) { System.out.println(name+"退出了聊天室"); socket.close(); clients.remove(this); break; } } } catch (IOException e) { e.printStackTrace(); } } //广播所有信息的方法 private void sendMsg(String msg) { for (ThreadSocket client : clients) { try { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.socket.getOutputStream())); bw.write(msg); bw.newLine(); bw.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } 客户端 package com.qf.cdjava2201.day24.chat; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class Client { static boolean flag = true; public static void main(String[] args) { Scanner input = new Scanner(System.in); //建立连接 try { Socket socket = new Socket("127.0.0.1",8888); //接收消息--启动一个线程来一直接收消息,客户端不关闭,便一直接收 new Thread(new Runnable() { public void run() { while(flag) { BufferedReader br=null; try { br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String info=""; info = br.readLine(); System.out.println(info); } catch (IOException e1) { //输入88这里有个异常 } } } }).start(); //输入昵称发给服务器 System.out.println("请输入您的昵称:"); String name = input.next(); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write(name); bw.newLine(); bw.flush(); //发送消息 while(true) { System.out.println("请发送消息:"); String msg = input.next(); BufferedWriter bw1 = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw1.write(msg); bw1.newLine(); bw1.flush(); if(msg.equals("88")) { //最后关闭流的方式还可以用socket.shutdownOutput()。相比于socket.close(),这个方法是在服务端收到消息后,还能再发消息给客户端,然后再关闭Socket。 socket.close(); flag = false; break; } } } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //这里设计的通知服务端已发送完命令的方式是设定“88”,但在真实的使用中,肯定是麻烦的,比如不能单独输入88了。 //这里推荐使用“指定长度”的方法。 转载于---博客园,作者:已往之不谏。 如果你了解一点class文件的结构(后续会写,敬请期待),那么你就会佩服这么设计方式,也就是说我们可以在此找灵感,就是我们可以先指定后续命令的长度,然后读取指定长度的内容做为客户端发送的消息。 现在首要的问题就是用几个字节指定长度呢,我们可以算一算: 1个字节:最大256,表示256B 2个字节:最大65536,表示64K 3个字节:最大16777216,表示16M 4个字节:最大4294967296,表示4G 依次类推 这个时候是不是很纠结,最大的当然是最保险的,但是真的有必要选择最大的吗,其实如果你稍微了解一点UTF-8的编码方式(字符编码后续会写,敬请期待),那么你就应该能想到为什么一定要固定表示长度字节的长度呢,我们可以使用变长方式来表示长度的表示,比如: 第一个字节首位为0:即0XXXXXXX,表示长度就一个字节,最大128,表示128B 第一个字节首位为110,那么附带后面一个字节表示长度:即110XXXXX 10XXXXXX,最大2048,表示2K 第一个字节首位为1110,那么附带后面二个字节表示长度:即110XXXXX 10XXXXXX 10XXXXXX,最大131072,表示128K 依次类推 上面提到的这种用法适合高富帅的程序员使用,一般呢,如果用作命名发送,两个字节就够了,如果还不放心4个字节基本就能满足你的所有要求,下面的例子我们将采用2个字节表示长度,目的只是给你一种思路,让你知道有这种方式来获取消息的结尾: 服务端程序: public class SocketServer { public static void main(String[] args) throws Exception { // 监听指定的端口 int port = 55533; ServerSocket server = new ServerSocket(port); // server将一直等待连接的到来 System.out.println("server将一直等待连接的到来"); Socket socket = server.accept(); // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取 InputStream inputStream = socket.getInputStream(); byte[] bytes; // 因为可以复用Socket且能判断长度,所以可以一个Socket用到底 while (true) { // 首先读取两个字节表示的长度 int first = inputStream.read(); //如果读取的值为-1 说明到了流的末尾,Socket已经被关闭了,此时将不能再去读取 if(first==-1){ break; } int second = inputStream.read(); int length = (first << 8) + second; // 然后构造一个指定长的byte数组 bytes = new byte[length]; // 然后读取指定长度的消息即可 inputStream.read(bytes); System.out.println("get message from client: " + new String(bytes, "UTF-8")); } inputStream.close(); socket.close(); server.close(); } } 此处的读取步骤为,先读取两个字节的长度,然后读取消息,客户端为: public class SocketClient { public static void main(String args[]) throws Exception { // 要连接的服务端IP地址和端口 String host = "127.0.0.1"; int port = 55533; // 与服务端建立连接 Socket socket = new Socket(host, port); // 建立连接后获得输出流 OutputStream outputStream = socket.getOutputStream(); String message = "你好 yiwangzhibujian"; //首先需要计算得知消息的长度 byte[] sendBytes = message.getBytes("UTF-8"); //然后将消息的长度优先发送出去 outputStream.write(sendBytes.length >>8); outputStream.write(sendBytes.length); //然后将消息再次发送出去 outputStream.write(sendBytes); outputStream.flush(); //==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法 message = "第二条消息"; sendBytes = message.getBytes("UTF-8"); outputStream.write(sendBytes.length >>8); outputStream.write(sendBytes.length); outputStream.write(sendBytes); outputStream.flush(); //==========此处重复发送一次,实际项目中为多个命名,此处只为展示用法 message = "the third message!"; sendBytes = message.getBytes("UTF-8"); outputStream.write(sendBytes.length >>8); outputStream.write(sendBytes.length); outputStream.write(sendBytes); outputStream.close(); socket.close(); } }