Java高级基础

IO流

IO流​是一种实现数据交换技术的核心,比较常见的流的使用在于:文件操作,网络数据传输等;流由两大核心部分构成:1.Input(输入),2.Output(输出)。

流的分类

​按流向分为:输入流和输出流, 按类型分为:字节流和字符流,按功能分为:节点流和处理流。​字节流一般用于对于一些二进制文件(图片,音频,视频等)进行读写操作,java中的字节流都是来自以下两个抽象类:InputStream(字节输入流)OutputStream(字节输出流)。字符流主要用于文本输入输出。​java中所有的字符流都从以下两个抽象类继承:Reader 字符输入流 ,Writer 字符输出流。
​在实际开发中有些需求可能会涉及到需要将字节流转换为字符流,或者将字符流转换为字节流等一些转换操作;另外也有可能需要将这些低级的节点流提高读取和写入效率,因此还需要一些高级流来进行处理,因此这些高级流也被称之为处理流,比如:转换流,缓冲流,打印流等。IO流基本是成对出现,因此在应用是注意相对应。

IO流经典实例:文件目录拷贝

public class FileCopyUtils {

	/**
	 * 将一个源file对象拷贝到另一个目标file
	 * @param source  源文件(可能是目录)
	 * @param target  目标目录
	 * @throws IOException 
	 */
	public static void copy(File source,File targetDir) throws IOException{
		//判断当前需要被拷贝对象是目录还是标准文件
		if(source.isDirectory()){
			//在目录中创建子目录(不存在)
			targetDir = new File(targetDir,source.getName());
			if(!targetDir.exists()){
				//如果目录不存在则试图创建
				if(!targetDir.mkdirs()){
					throw new FileNotFoundException("目录创建失败,请检查权限");
				}
			}
			//读取目录
			File[] files = source.listFiles();
			if(Objects.nonNull(files)){				
				for (int i = 0; i < files.length; i++) {
					copy(files[i],targetDir);
				}
			}
		}else{
			//文件拷贝
			copyFile(source,targetDir);
		}
		
	}

	private static void copyFile(File source, File targetDir) throws IOException {
		BufferedInputStream bis = null;
		BufferedOutputStream bow = null;
		try{
			//获取源文件的输入流并包装为缓冲流
			bis = new BufferedInputStream(new FileInputStream(source));
			//根据源文件文件名组合目标目录成为新文件对象
			File target = new File(targetDir,source.getName());
			//获取目标文件的输出流
			bow = new BufferedOutputStream(new FileOutputStream(target));
			//声明字节缓冲区,缓存读取的字节数据
			byte[] b = new byte[1024];
			int len = 0;
			//循环读写
			while((len = bis.read(b)) != -1){
				bow.write(b, 0, len);
			}
		}finally{			
			//关闭资源
			if(bow != null)bow.close();
			if(bis != null)bis.close();
		}
	}
}


public class TestCopy {
	public static void main(String[] args) throws IOException {	
		//源file
		File f1 = new File("D:/javacode"); 
		//目标file
		File f2 = new File("C:/Users/mrchai/Desktop"); 
		//拷贝
		FileCopyUtils.copy(f1, f2);
	}
}

线程

进程就像是正在执行的任务,线程就像其中的一条路径。每一条线程都有各自的生命周期,并且线程对象都存在以下几种状态:初始,就绪,运行,阻塞,销毁。

线程创建

java中创建线程包含四种方式,但 实现Runnable接口和 继承Thread类是最基本也是最常用的创建方式。实现Runnable接口更灵活,类还能在实现其他接口或继承其他类,但是线程的创建和启动依然需要Thread类完成。继承Thread类,相对第一种更简单,可以直接创建子类对象并启动线程,但是耦合度较高,子类不能再对其他类继承。线程的启动:必须通过调用Thread类的start方法完成,不能直接通过线程对象调用run方法(实际还是单线程的执行方法:普通方法调用)。

线程中断

java多线程编程中,线程的中断包含以下几种方式:

  1. 标记中断法
  2. 异常中断法
    线程同步时使用synchronizad关键字将对象锁定,此时,如果对象被一个线程锁定,则其他线程无法在操作当前对象,只有等待拥有该对象锁的线程释放锁之后,其他线程才能使用该对象。
    wait和notify(notifyAll)是Object类中的方法,wait和notify在调用时,当前线程对象必须拥有该对象的对象锁。 sleep是Thread类中提供一个用于让当前线程休眠的方法,里面需要一个毫秒数作为参数,当sleep执行后,当前线程会进入休眠状态(让出cup的时间片),当休眠时间到达后,线程会自动唤醒继续执行,sleep不需要当前线程拥有任何对象的对象监视器(对象锁)。
    wait是来之Object类中的一个方法,可以让一个线程进入等待状态,并且这种等待状态不能自动唤醒,需要其他线程通过调用该对象的notify或notifyAll来手动唤醒,wait必须要求当前线程拥有该对象的对想想监视器(对象锁),并且wait一旦执行,该线程就会释放在对象上的监视器。

例:多线程实现文件修改监听

public class FileLinstener2 implements Runnable{

	private File file;
	
	public FileLinstener2(File file) {
		this.file = file;
	}
	
	@Override
	public void run() {
		//获取当前文件最后修改时间
		long time = file.lastModified();
		while(true){
			try {
				long now = file.lastModified();
				if(now != time){
					//文件被修改
					System.out.println(file.getName()+" file changed,"+getTime(now)); 
					//将原来的时间设置为最新时间
					time = now;
				}
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}		
	}
	/**格式化日期*/
	public String getTime(long time){
		DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date d = new Date(time);
		return fmt.format(d);
	}
	
	public static void main(String[] args) {
        //目标目录
		File file = new File("C:\\Users\\mrchai\\Desktop\\tempfile");
		//获取目录中所有子文件
		File[] files = file.listFiles();
		for (File f : files) {
            //为每一个File对象启动一条监听线程
			FileLinstener2 lis = new FileLinstener2(f);
			Thread t = new Thread(lis);
			t.start();
		}
		
	}
}

网络编程

基于TCP/IP的Socket通信:

TCP/IP是一个安全可靠的传输协议,需要保证两个通信端点之间的稳定连接,并且也能保证数据传输的完整性还有顺序,Java中基于TCP/IP编程主要通过以下两个类完成:- java.net.ServerSocket 用于表示服务端套接字; java.net.Socket 用户表示客户端套接字。

Socket通信实例-文件传输

服务器端:
public class FileServer2 extends Thread{

	private Socket s;
	private File source;
	
	public FileServer2(Socket s, File source) {
		super();
		this.s = s;
		this.source = source;
	}

	@Override
	public void run() {
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			//获取源文件的输入流
			bis = new BufferedInputStream(new FileInputStream(source));
			//获取socket的输出流并包装
			bos = new BufferedOutputStream(s.getOutputStream());
			
			byte[] b = new byte[1024];
			int len = 0;
			System.out.println("向 "+s.getInetAddress().getHostAddress()+"开始传输....");
			while((len = bis.read(b)) != -1){
				bos.write(b, 0, len);
			}
			System.out.println("向 "+s.getInetAddress().getHostAddress()+"传输完成!");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				if(bos != null)bos.close();
				if(bis != null)bis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(6666);
		System.out.println("SOFEEM文件服务器已启动,等待连接...");
		//准备需要传输的文件对象
		File source = new File("D:\\素材\\视频\\larva搞笑虫子\\1.mp4");
		//循环监听
		while(true){
			//等待客户端连接
			Socket s = server.accept();
			System.out.println(s.getInetAddress().getHostAddress()+"进入服务器,准备传输...");
			//根据每一个连接的客户端启动一条子线程
			new FileServer2(s, source).start();
		}
	}
	
}


客户端:
public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		//建立连接
		Socket s = new Socket("192.168.4.198",6789);
		//获取socket的输入流
		InputStream is = s.getInputStream();
		DataInputStream dis = new DataInputStream(is);
		
		//准备file对象接受socket中的数据
		File f = new File("C:\\Users\\mrchai\\Desktop\\1.mp4");
		FileOutputStream fos = new FileOutputStream(f);
	
		byte[] b = new byte[1024];
		int len = 0;
		while((len = dis.read(b)) != -1){
			fos.write(b, 0, len);
		}
		
		fos.close();
		dis.close();
		s.close();
	}
}

基于UDP协议的Socket通信:

UDP(User Datagram Protocol),用户数据报协议,不是一个基于稳定连接的协议,使用UDP协议通信不需要通信的两个端点间建立连接,通信的端点既可以作为发送端也可以作为接收端;与TCP 协议之间的不同在于, UDP 不是一种基于稳定连接的通讯协议。Java中也提供了两个用于实现UDP通信的核心类:1. java.net.DatagramPacket 2. java.net.DatagramSocket。UDP数据广播的实现是通过java.net包中的MulticastSocket类实现,该类是DatagramSocket的子类,通过该类可以实现组播(广播)数据报的发送与接收。组播地址的使用一般为D类ip地址,D类地址一般为:224.0.0.0至239.255.255.255(包含)之间。

例:

发送端
public class BroadcastSender {

	public static void main(String[] args) throws IOException {
		
		//准备需要发送的消息
		String msg = "路漫漫其修远兮";
		
		//准备组播地址(D类IP地址)
		InetAddress ip = InetAddress.getByName("228.5.6.7");
		
		//创建组播socket通道
		MulticastSocket ms = new MulticastSocket();
		//加入多播组
		ms.joinGroup(ip);
		
		//将数据打包成数据报包
		DatagramPacket dp = new DatagramPacket(
				msg.getBytes(), 
				msg.getBytes().length, 
				ip, 
				4567);
				
		ms.send(dp);

		ms.close();
	}
}


接收端
public class BroadcastReceiver {

	public static void main(String[] args) throws IOException {
		//准备组播地址(D类IP地址)
		InetAddress ip = InetAddress.getByName("228.5.6.7");
		
		//创建组播socket通道
		MulticastSocket ms = new MulticastSocket(4567);
		ms.joinGroup(ip);
		
		byte[] b = new byte[1024];
		DatagramPacket dp = new DatagramPacket(b, b.length);
		
		//接收消息
		ms.receive(dp);
		
		String s = new String(b,0,dp.getLength());
		System.out.println(s);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值