java基础知识——网络编程、IO流
字节流:处理字节数据的流对象,计算机中最小数据单元就是字节。InputStream OutputStream
字符流:字符编码问题,将字节流和编码表封装成对象就是字符流。Reader Write
读、写都会发生 IO 异常。io 异常的处理方式 :io 一定要写 finally。fw.flush();//刷新缓冲区,fw.close();//关闭流。
IO 中的使用到了一个设计模式: 装饰设计模式。 装饰设计模式解决:对一组类进行功能的增强。 包装:写一个类(包装类)对被包装对象进行包装; * 1、包装类和被包装对象要实现同样的接口; * 2、包装类要持有一个被包装对象; * 3、包装类在实现接口时,大部分方法是靠调用被包装对象来实现的,对于需要修改的方法我们自己实现;
Reader : 用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。 Writer : 写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。
InputStream、OutputStream
BufferedWriter :是给字符输出流提高效率用的,那就意味着,缓冲区对象建立时,必须要先有流对象。明 确要提高具体的流对象的效率。 FileWriter fw = new FileWriter("bufdemo.txt"); BufferedWriter bufw = new BufferedWriter(fw); // 让缓冲区和指定流相关联。 for(int x=0; x x++){ bufw.write(x+"abc"); bufw.newLine(); // 写入一个换行符,这个换行符可以依据平台的不同写入不同的换行符。 bufw.flush();//对缓冲区进行刷新,可以让数据到目的地中。 bufw.close(); // 关闭缓冲区,其实就是在关闭具体的流。 ----------------------------- BufferedReader : FileReader fr = new FileReader("bufdemo.txt"); BufferedReader bufr = new BufferedReader(fr); String line = null; while((line=bufr.readLine())!=null){ e //readLine 方法返回的时候是不带换行符的。 System.out.println(line); bufr.close(); ----------------------------- //记住,只要一读取键盘录入,就用这句话。 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));//输出到控制台 String line = null; while((line=bufr.readLine())!=null){ if("over".equals(line)) break; 51 / 65 bufw.write(line.toUpperCase());//将输入的字符转成大写字符输出 bufw.newLine(); bufw.flush(); bufw.close(); bufr.close();
流的操作规律:
1 ,明确源和目的。
数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
2 ,操作的数据是否是纯文本数据?
如果是:数据源:Reader
数据汇:Writer
如果不是:数据源:InputStream
数据汇:OutputStream
明确操作的数据设备。
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。 4 ,需要在基本操作上附加其他功能吗?比如缓冲。
如果需要就进行装饰。 File类
将文件系统中的文件和文件夹封装成了对象。提供了更多的属性和行为可以对这些文件和文件夹
进行操作。这些是流对象办不到的,因为流只操作数据。
createNewFile() 、mkdir()、getAbsolutePath()
1:一定要定义递归的条件。
2:递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出 错误。
其实递归就是在栈内存中不断的加载同一个函数。
Java递归算法的小例子 求1+2+3…+1000 和
public class Test1 { int sum=0; int a=1; public void sum() sum+=a; a++; if(a =1000) sum();//调用自身实现递归 public static void main(String[] args) { Test1 test=new Test1(); test.sum(); System.out.println("计算结果:"+test.sum+"!");
PrintStream m 可以操作目的:1:File 对象。2:字符串路径。3:字节输出流。 PrintWriter :该对象的目的地有四个:1:File 对象。2:字符串路径。3:字节输出流。4:字符输出流。 PrintWriter out = new PrintWriter( new FileWriter(“out.txt”), true);//设置 true 后自动刷新 System.in,System.out 这两个标准的输入输出流,在 jvm 启动时已经存在了。随时可以使用。当
jvm 结束了,这两个流就结束了。但是,当使用了显示的 close 方法关闭时,这两个流在提前结束了。 SequenceInputStream : 序列流
作用就是将多个读取流合并成一个读取流实现数据合并。
管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。
注意 :需要加入多线程技术,因为单线程,先执行 read,会发生死锁,因为 read 方法是阻塞式的,没有数据的
read 方法会让线程等待。
public static void main(String[] args) throws IOException{ PipedInputStream pipin = new PipedInputStream(); PipedOutputStream pipout = new PipedOutputStream(); pipin.connect(pipout); new Thread(new Input(pipin)).start(); new Thread(new Output(pipout)).start();
静态数据不能被序列化,因为静态数据不在堆内存中;用transient关键字修饰变量,可以将非静态数据不进行序列化。
Serializable :用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一
个标记接口。
ByteArrayInputStream : 源 : 内存
ByteArrayOutputStream :目的:内存。
这两个流对象不涉及底层资源调用,操作的都是内存中数组,所以不需要关闭。
端口:0-65535
//通过名称(ip 字符串 or 主机名)来获取一个 ip 对象。 InetAddress ip = InetAddress.getByName("www.baidu.com");//java.net.UnknownHostException
为网络服务提供的一种机制,通信的两端都有 Socket,网络通信其实就是 Socket 间的通信,数据在两个
Socket 间通过 IO 传输。
数据一定要封装到数据包中,数据包中包括目的地址、端口、数据等信息。将 udp 封装成对象,易于我们的使用,这个对象就是 DatagramSocket
发送端:
1,建立 udp 的 socket 服务,创建对象时如果没有明确端口,系统会自动分配一个未被使用的端口。
2,明确要发送的具体数据。
3,将数据封装成了数据包。
4,用 socket 服务的 send 方法将数据包发送出去。
5,关闭资源。
import java.net.*; class UdpSend{ public static void main(String[] args)throws Exception { // 1 1 ,建立 p udp 的 的 t socket 服务。 DatagramSocket ds = new DatagramSocket(8888);//指定发送端口,不指定系统会随机分配。 // 2 2 ,明确要发送的具体数据。 String text = "udp 传输演示 哥们来了"; byte[] buf = text.getBytes(); // 3 3 ,将数据封装成了数据包。 DatagramPacket dp = new DatagramPacket(buf, buf.length,InetAddress.getByName("10.1.31.127"),10000); // 4 4 ,用 t socket 服务的 d send 方法将数据包发送出去。 ds.send(dp); // 5 5 ,关闭资源。 ds.close();
p udp 的接收端:
1,创建 udp 的 socket 服务,必须要明确一个端口,作用在于,只有发送到这个端口的数据才是这个接收端可
以处理的数据。
2,定义数据包,用于存储接收到数据。
3,通过 socket 服务的接收方法将收到的数据存储到数据包中。
4,通过数据包的方法获取数据包中的具体数据内容,比如 ip、端口、数据等等。
5,关闭资源。
class UdpRece { public static void main(String[] args) throws Exception{ // 1 1 ,创建 p udp 的 的 t socket 服务。 DatagramSocket ds = new DatagramSocket(10000); // 2 2 ,定义数据包,用于存储接收到数据。先定义字节数组,数据包会把数据存储到字节数组中。 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); // 3 3 ,通过 t socket 服务的接收方法将收到的数据存储到数据包中。 ds.receive(dp);//该方法是阻塞式方法。 // 4 4 ,通过数据包的方法获取数据包中的具体数据内容,比如 ip ,端口,数据等等。 String ip = dp.getAddress().getHostAddress(); int port = dp.getPort(); String text = new String(dp.getData(),0,dp.getLength());//将字节数组中的有效部分转成字符串。 System.out.println(ip+":"+port+"--"+text); // 5 5 ,关闭资源。 ds.close();
两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,
称之为 socket 流。该流中既有读取,也有写入。
TCP 客户端 :
1,建立 tcp 的 socket 服务,最好明确具体的地址和端口。这个对象在创建时,就已经可以对指定 ip 和端口
进行连接(三次握手)。
2,如果连接成功,就意味着通道建立了,socket 流就已经产生了。只要获取到 socket 流中的读取流和写入
流即可,只要通过 getInputStream 和 getOutputStream 就可以获取两个流对象。
3,关闭资源。
import java.net.*; import java.io.*; //需求:客户端给服务器端发送一个数据。 class TcpClient{ public static void main(String[] args) throws Exception{ Socket s = new Socket("10.1.31.69",10002); OutputStream out = s.getOutputStream();// 获取了 t socket 流中的输出流对象。 out.write("tcp 演示,哥们又来了!".getBytes()); s.close();
TCP 服务端:
1,创建服务端 socket 服务,并监听一个端口。
2,服务端为了给客户端提供服务,获取客户端的内容,可以通过 accept 方法获取连接过来的客户端对象。
3,可以通过获取到的 socket 对象中的 socket 流和具体的客户端进行通讯。
4,如果通讯结束,关闭资源。注意:要先关客户端,再关服务端。
class TcpServer{ public static void main(String[] args) throws Exception{ 62 / 65 ServerSocket ss = new ServerSocket(10002);//建立服务端的 socket 服务 Socket s = ss.accept();//获取客户端对象 String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+".....connected"); // 可以通过获取到的 socket 对象中的 socket 流和具体的客户端进行通讯。 InputStream in = s.getInputStream();//读取客户端的数据,使用客户端对象的 socket 读取流 byte[] buf = new byte[1024]; int len = in.read(buf); String text = new String(buf,0,len); System.out.println(text); // 如果通讯结束,关闭资源。 注意:要先关客户端,在关服务端。 s.close(); ss.close();
1 、 获得 s Class 对象 ,就是获取到指定的名称的字节码文件对象 。
2 、 实例化对象, 获得类的属性、方法或构造函数。
3、访问属性、调用方法、调用构造函数创建对象 正则表达式
1,匹配:其实用的就是 String 类中的 matches 方法。
String reg = “[1-9][0-9]{4,14}”;
boolean b = qq. matches(reg);//将正则和字符串关联对字符串进行匹配。
2,切割:其实用的就是 String 类中的 split 方法。
3,替换:其实用的就是 String 类中的 replaceAll();
4,获取:
1),先要将正则表达式编译成正则对象。使用的是 Pattern 中静态方法 compile(regex);
2),通过 Pattern 对象获取 Matcher 对象。
Pattern 用于描述正则表达式,可以对正则表达式进行解析。
而将规则操作字符串,需要从新封装到匹配器对象 Matcher 中。
然后使用 Matcher 对象的方法来操作字符串。
如何获取匹配器对象呢?
通过 Pattern 对象中的 matcher 方法。该方法可以正则规则和字符串想关联。并返回匹配器对象。
3),使用 Matcher 对象中的方法即可对字符串进行各种正则操作。
Java多线程+IO流+网络编程+MySQL+JDBC编程实现多人联机版坦克大战 该项目为博主与几位伙伴的共同成果,历时1个月,由最初知识尚未掌握,到最后开发出完整项目,一途走过不少弯路,但也对个人的编程能力及对java知识的掌握更进一步,游戏逻辑主要参考【马士兵网络版坦克大战】
朱培 CSDN博客专家,大数据与云计算领域,常年活跃于Github、CSDN、开源中国等开源社区。
相关文章
- 第1章 Java基础知识
- java中split特殊符号
- Java 十进制和十六制之间的转化(负数的处理)
- Java基础知识1 java基础&jdk常用命令
- java基础知识:栈内存和堆内存
- java基础知识:构造函数
- java基础知识4-2:继承
- 精品基于java的旅游景点管理网站SSM
- Java开发基础知识总结(上)
- Java面试题,Hibernate基础知识总结
- java基础知识总结1
- Java GC 垃圾收集器(HotSpot)
- 深入理解Jvm--Java静态分配和动态分配完全解析
- 【项目精选】基于Java的银行排号系统的设计与实现
- 【JAVA】JAVA基础知识总结
- Java基础知识
- Java 基础(基础知识图解, 语言特定, 编写, 编译, 运行, 注释方法, API 文档)
- java-并发-线程间协作的两种方式:wait、notify、notifyAll和Condition
- java基础知识
- java调用C/C++写的dll(转)