Java 进阶知识(三)

0 阅读9分钟
package io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * java IO(input,output) 输入与输出
 * IO是我们的程序与外界交换数据的方式。
 * java提供了一种统一的标准的方式与外界交换
 * 数据。
 * 
 * java将流按照功能划分为读和写,并用不同的方
 * 向来表示
 * 其中输入流(外界到程序的方向)用于读取数据
 * 输出流用于写出数据。
 * 
 * java将流划分为两大类:节点流,处理流
 * 节点流:也称为低级流,是实际链接程序与数据源
 * 的"管道",负责实际搬运数据。读写一定是建立在
 * 节点流的基础上进行的。
 * 
 * 处理流:也称为高级流,不能独立存在,必须链接
 * 在其他流上,目的是当数据流经当前流时对这些
 * 数据做某些处理,这样可以简化我们对数据的
 * 操作。 
 * 
 * 实际应用中,我们是链接若干高级流,并最终链接
 * 低级流,通过低级流读写数据,通过高级流对读写
 * 的数据进行某些加工处理,完成一个复杂的读写
 * 操作。这个过程称为"流链接"。这也是学习IO的
 * 精髓所在。
 * 
 * 
 * 文件流
 * 文件流是一对低级流,用于读写文件。就功能而言
 * 它们与RandomAccessFile一致。但是底层的读写
 * 方式有本质区别。
 * RAF是基于指针进行随机读写的,可任意读写文件指定
 * 位置的数据。可以做到对文件部分数据的编辑操作。
 * 
 * 流是顺序读写方式,所以不能做到任意读写指定
 * 位置数据,对此也无法做到对文件数据进行编辑的
 * 操作。但是配合高级流,可以更轻松的读写数据。
 * 
 * 
 * @author ta
 *
 */
public class FosDemo {
	public static void main(String[] args) throws IOException {
		/*
		 * 使用文件流向文件中写出字节
		 * 
		 * FileOutputStream常用构造方法:
		 * FileOutputStream(String path)
		 * FileOutputStream(File file)
		 * 以上两种方式创建时,默认为覆盖写操
		 * 作,即:若创建时发现该文件已存在,会
		 * 先将该文件所有数据清除。然后将通过
		 * 当前流写出的内容作为该文件数据。
		 *
		 * 
		 * FileOutputStream(String path,boolean append)
		 * FileOutputStream(File file,boolean append)
		 * 追加写模式,即:若指定的文件存在,那么数据全
		 * 保留,通过该流写出的数据会被追加到文件最后
		 * 
		 */
		FileOutputStream fos
			= new FileOutputStream("fos.txt",true);
		
		String line = "我们一起学猫叫,一起喵喵喵喵喵~";
		byte[] data = line.getBytes("UTF-8");
		fos.write(data);
		System.out.println("写出完毕!");
		fos.close();
	}
}
package io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 使用文件输入流读取文件数据
 * @author ta
 *
 */
public class FisDemo {
	public static void main(String[] args) throws IOException {
		FileInputStream fis
			= new FileInputStream("fos.txt");
		
		byte[] data = new byte[200];
		int len = fis.read(data);
		System.out.println("实际读取了:"+len+"个字节");
		
		String str = new String(data,0,len,"UTF-8");
		System.out.println(str);
		
		fis.close();
	}
}
package io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 使用文件流完成复制文件操作
 * @author ta
 *
 */
public class CopyDemo {
	public static void main(String[] args) throws IOException {
		/*
		 * 使用文件输入流读取原文件
		 * 使用文件输出流向复制文件写数据
		 * 
		 * 利用块读写操作顺序从原文件将数据
		 * 读取出来写入复制文件完成复制操作。
		 */
		FileInputStream src
			= new FileInputStream("music.mp3");
		FileOutputStream desc
			= new FileOutputStream("music_cp.mp3");		
		int len = -1;
		byte[] data = new byte[1024*10];		
		while((len = src.read(data))!=-1) {
			desc.write(data,0,len);
		}
		System.out.println("复制完毕!");
		src.close();
		desc.close();
	}
}
package io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 缓冲流
 * 缓冲流是一对高级流,功能是提高读写效率。
 * 链接他们以后,无论我们进行随机读写还是
 * 快读写,当经过缓冲流时都会被转换为块读写
 * 操作。
 * java.io.BufferedInputStream
 * java.io.BufferedOutputStream
 * @author ta
 *
 */
public class CopyDemo2 {
	public static void main(String[] args) throws IOException {
		FileInputStream fis
			= new FileInputStream("music.mp3");
		BufferedInputStream bis
			= new BufferedInputStream(fis);
		FileOutputStream fos
			= new FileOutputStream("music_cp.mp3");
		BufferedOutputStream bos
			= new BufferedOutputStream(fos);		
		int d = -1;
		long start = System.currentTimeMillis();
		while((d = bis.read())!=-1) {
			bos.write(d);
		}
		long end = System.currentTimeMillis();
		
		System.out.println("复制完毕,耗时:"+(end-start)+"ms");
		
		bis.close();
		bos.close();
	}
}
package io;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 缓冲输出流的缓冲区问题
 * @author ta
 *
 */
public class Bos_flushDemo {
	public static void main(String[] args) throws IOException {
		FileOutputStream fos
			= new FileOutputStream("bos.txt");
		BufferedOutputStream bos
			= new BufferedOutputStream(fos);
		
		String line = "你是隔壁的泰山,抓住爱情的藤蔓。";
		byte[] data = line.getBytes("UTF-8");
		/*
		 * 缓冲流的write方法并不是立即将数据写出,
		 * 而是先将数据存入其内部的数组中,当数组
		 * 装满时才会做一次真是写操作。(转化为块
		 * 写操作的过程)
		 */
		bos.write(data);
		/*
		 * flush方法的意义是强制将缓冲流已经缓存的
		 * 数据一次性写出。这样做可以让写出的数据
		 * 有即时性,但是频繁调用会降低写效率。
		 * 在更关注写出的即时性时应当使用该方法。
		 */
//		bos.flush();
		System.out.println("写出完毕!");
		/*
		 * close方法中会调用一次flush方法
		 */
		bos.close();
	}
}
package io;

import java.io.Serializable;
import java.util.Arrays;

/**
 * 使用当前类实例测试对象流的对象读写操作
 * 
 * 当一个类的实例希望可以被对象流进行读写,那
 * 么该类必须实现:java.io.Serializable接口
 * 与此同时,当前类中所有引用类型的属性,他们
 * 对应的类也必须实现该接口。
 * @author ta
 *
 */
public class Person implements Serializable{
	/**
	 * 当一个类实现了Serializable接口后,要求
	 * 应当定义一个常量:serialVersionUID,即:
	 * 序列化版本号
	 * 
	 * 序列化版本号影响反序列化是否成功。当对象
	 * 输入流在进行对象反序列化时会检查该对象与
	 * 当前类的版本是否一致,不一致则反序列化时
	 * 会抛出异常导致反序列化失败。
	 * 一致则可以进行反序列化,原则时对应的属性
	 * 进行还原。
	 * 
	 * 如果我们不定义该版本号,编译器会在编译当前
	 * 类时根据结构生成一个版本号,但是一旦当前类
	 * 发生改变,那么版本号一定会改变。这样以前的
	 * 对象一定是不可以反序列化了。
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String name;
	private int age;
	private String gender;
	/*
	 * transient关键字修饰的属性在对象序列化时
	 * 会被忽略。
	 * 忽略不必要的属性可以达到对象瘦身的作用。
	 * 
	 */
	private transient String[] otherInfo;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String[] getOtherInfo() {
		return otherInfo;
	}
	public void setOtherInfo(String[] otherInfo) {
		this.otherInfo = otherInfo;
	}
	
	public String toString() {
		return name+","+age+","+gender+","+
	           Arrays.toString(otherInfo);
	}
}
package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * 对象流
 * 对象流也是一对高级流,提供的功能是读写java
 * 中的任何对象。
 * 
 * 对象输出流:
 * java.io.ObjectOutputStream
 * 它可以将给定的java对象转换为一组字节然后
 * 通过其连接的流将这些字节写出。
 * @author ta
 *
 */
public class OosDemo {
	public static void main(String[] args) throws IOException {
		Person p = new Person();
		p.setName("苍老师");
		p.setAge(18);
		p.setGender("女");
		String[] otherInfo = {"是一名演员","爱好是写毛笔字","已婚","促进中日文化交流","广大男性同胞的启蒙老师"};
		p.setOtherInfo(otherInfo);
		System.out.println(p);
		
		FileOutputStream fos
			= new FileOutputStream("person.obj");
		
		ObjectOutputStream oos
			= new ObjectOutputStream(fos);
		/*
		 * 通过对象流写出对象的这个方法经历了
		 * 两个步骤:
		 * 1:对象流先将给定的对象转换为了一组
		 *   字节,这组字节包含对象本身保存的
		 *   数据信息,还包含该对象的结构信息
		 *   然后将这组字节通过其连接的流写出
		 *   
		 *   上述操作对应的术语:对象序列化
		 *   
		 *   
		 * 2:经过文件流时,文件流将这组字节写
		 *   入到了文件中
		 *   
		 *   将数据写入磁盘做长久保存的过程
		 *   对应的术语:数据持久化
		 * 
		 * 
		 */
		oos.writeObject(p);
		System.out.println("写出完毕!");
		
		oos.close();
	}
}

对象输出流.png

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * 对象输入流
 * 可以进行对象的反序列化操作。
 * 
 * 使用对象流读取的字节必须是通过对象输出流
 * 序列化的一组字节才可以。
 * @author ta
 *
 */
public class OisDemo {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		FileInputStream fis
			= new FileInputStream("person.obj");
		ObjectInputStream ois
			= new ObjectInputStream(fis);
		
		Person p = (Person)ois.readObject();
		System.out.println(p);
		
		ois.close();
		
	}
}
package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * 字符流
 * java将流按照读写单位又进行了一种划分方式
 * 字节流与字符流
 * 字节流的读写单位是字节,而字符流的读写单位
 * 是字符
 * 所以字符流只适合读写文本数据!
 * 
 * java.io.Reader,java.io.Writer
 * 这两个类也是抽象类,是所有字符输入流与
 * 字符输出流的父类,规定了读写字符的相关
 * 方法。
 * 
 * 
 * 转换流
 * java.io.InputStreamReader
 * java.io.OutputStreamWriter
 * 他们是一对常用的字符流实现类,经常在我们做
 * 字符数据读写操作中使用。并且在流链接中是
 * 非常重要的一个环节。但是我们很少直接对它
 * 做操作。
 * @author ta
 *
 */
public class OswDemo {
	public static void main(String[] args) throws IOException {
		FileOutputStream fos
			= new FileOutputStream("osw.txt");
		
		OutputStreamWriter osw
			= new OutputStreamWriter(fos,"UTF-8");	
		String line = "摩擦摩擦,在光滑的马路牙子上打出溜滑!";
		osw.write(line);		
		line = "我的滑板鞋,时尚时尚最时尚!";
		osw.write(line);
		System.out.println("写出完毕!");
		
		osw.close();
	}
}
package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 转换流
 * java.io.InputStreamReader
 * 
 * @author ta
 *
 */
public class IsrDemo {
	public static void main(String[] args) throws IOException {
		FileInputStream fis
			= new FileInputStream("osw.txt");
		
		InputStreamReader isr
			= new InputStreamReader(fis,"UTF-8");
		/*
		 * 字符流的方法:
		 * int read()
		 * 该方法是一次读取一个字符,实际读取
		 * 的字节量要根据指定的字符集决定。但
		 * 是当读取到该字符后在java中都是以一
		 * 个char形式保存(unicode)占2个字节。
		 */
//		int d = -1;
//		while((d = isr.read())!=-1) {
//			char c = (char)d;
//			System.out.print(c);
//		}
		
		char[] data = new char[100];
		int len = isr.read(data);
		String str = new String(data,0,len);
		System.out.println(str);
		isr.close();
	}
}
package io;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * java.io.PrintWriter
 * 具有自动行刷新的缓冲字符输出流
 * 开发中比较常用的字符高级流
 * 
 * 可以按行写出字符串。
 * @author ta
 *
 */
public class PwDemo1 {
	public static void main(String[] args) throws IOException {
		/*
		 * PW提供了专门针对写文件的构造方法
		 * PrintWriter(String path)
		 * PrintWriter(File file)
		 */
		PrintWriter pw 
			= new PrintWriter("pw.txt","UTF-8");
		
		pw.println("像一颗海草海草海草海草~");
		pw.println("随波飘摇~");
		
		System.out.println("写出完毕!");
		pw.close();
		
	}
}
package io;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * 在流链接中使用PW
 * @author ta
 *
 */
public class PwDemo2 {
	public static void main(String[] args) throws IOException {
		FileOutputStream fos
			= new FileOutputStream("pw.txt");
		OutputStreamWriter osw
			= new OutputStreamWriter(fos,"UTF-8");
		BufferedWriter bw
			= new BufferedWriter(osw);
		PrintWriter pw
			= new PrintWriter(bw);
		
		pw.println("你好!");
		System.out.println("写出完毕!");
		
		pw.close();
	}
}

pw.png

package io;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;

/**
 * 完成简易记事本工具
 * 
 * 程序启动后,要求用户输入文件名,然后对该
 * 文件进行写操作。
 * 之后用户输入的每一行字符串都按行写入到该
 * 文件中。
 * 创建PW时要求使用流链接模式。
 * @author ta
 *
 */
public class Test {
	public static void main(String[] args) throws IOException {
		Scanner scanner = new Scanner(System.in);
		
		System.out.println("请输入文件名:");
		String fileName = scanner.nextLine();
		
		FileOutputStream fos
			= new FileOutputStream(fileName);
		OutputStreamWriter osw
			= new OutputStreamWriter(fos,"UTF-8");
		BufferedWriter bw
			= new BufferedWriter(osw);
		/*
		 * 当在流链接当中创建PrintWriter时
		 * 允许指定第二个参数,该参数为一个
		 * boolean值,当这个值为true时,当前
		 * PW具有自动行刷新功能。
		 * 即:每当调用println方法写出一行字符串
		 * 时就会自动flush.
		 * 注意:print方法是不会自动flush的
		 */
		PrintWriter pw
			= new PrintWriter(bw,true);
		System.out.println("请开始输入内容:");
		//用来记录每次用户输入的字符串
		String line = null;
		while(true) {
			line = scanner.nextLine();
			if("exit".equals(line)) {
				break;
			}
			pw.println(line);
//			pw.flush();
		}
		System.out.println("再见!");
		pw.close();
	}
}
package io;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 缓冲字符输入流:
 * java.io.BufferedReader
 * 特点:可以按行读取字符串
 * @author ta
 *
 */
public class BrDemo {
	public static void main(String[] args) throws IOException {
		/*
		 * 将当前源代码输出到控制台
		 */
		FileInputStream fis
			= new FileInputStream(
				"src/io/BrDemo.java"
			);
		InputStreamReader isr
			= new InputStreamReader(fis);
		
		BufferedReader br
			= new BufferedReader(isr);
		/*
		 * String readLine()
		 * 读取一行字符串
		 * 顺序读取若干字符,当读取到了换行
		 * 符时停止,并将换行符之前的字符组
		 * 成一个字符串返回。返回的字符串中
		 * 是不含有最有的换行符的。
		 * 若返回值为null,说明流读取到了
		 * 末尾。
		 */
		String line = null;
		while((line = br.readLine())!=null) {
			System.out.println(line);
		}
		
		br.close();
		
	}
}

br.png