以下内容若有误,欢迎私信我或在下方留言,谢谢^_−
目录
IO流(二)
1.特殊操作流
1.1 标准流
public static final InputStream in
:标准输入流,一般用于键盘输入、主机环境或用户指定另一输入源。public static final PrintStream out
:标准输出流,一般用于显示输出、主机环境或用户指定另一输出源。
看了上面两个,也许会感觉很陌生,但其实一点都不陌生!比如获取键盘输入的
Scanner scanner = new Scanner(System.in);
,还有打印输出的System.out.println();
1.2 打印流
public class PrintStream
:字节打印流public class PrintWriter
:字符打印流
/**
* 使用字符打印流实现复制文件
*/
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
// 创建字符输入流对象
BufferedReader br = new BufferedReader(new FileReader("test.txt"));
// 创建字符打印流对象,第二个参数代表打开自动刷新(flush())
PrintWriter pw = new PrintWriter(new FileWriter("test2.txt"), true);
// 读写数据,复制文件
String line;
while ((line = br.readLine()) != null) {
pw.println(line);
}
// 释放资源
pw.close();
br.close();
}
}
1.3 对象序列化流
(1)什么是序列化?
百度百科说:“序列化是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。”
看不懂上面的天文,emmm,没关系!这里简单打个比方,假如你去山上打山泉水,但这水你总得有个瓶瓶罐罐来装吧,所以你就把水装进了瓶子里面,这可以理解为就是一个序列化过程;而当你需要这些水的时候,你就把它们给倒出来,这就可以理解为是一个反序列化过程。
而对象序列化就是将一个对象转换为一串序列,反之,则是对象反序列化。
(2)分类
ObjectOutputStream
:对象序列化流ObjectInputStream
:对象反序列化流
/**
* 演示对象序列化流和对象反序列化流
*/
public class ObjectStreamDemo {
public static void main(String[] args) throws Exception {
// 序列化
// ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.txt"));
// 创建对象
Student student = new Student("爪哇", 20);
// void writeObject(Object obj):将指定的对象写入ObjectOutputStream
oos.writeObject(student);
// 释放资源
oos.close();
// 反序列化
// ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.txt"));
// Object readObject():从ObjectInputStream读取一个对象
Object object = ois.readObject();
// 向下转型
Student s = (Student) object;
System.out.println(s.getName() + "\t" + s.getAge());
// 释放资源
ois.close();
}
}
/**
* 学生类
* 注意:
* 一个对象被序列化,必须实现Serializable接口
* Serializable是一个标记接口,实现该接口,不需要重写任何方法
*/
class Student implements Serializable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
(3)InvalidClassException异常
当用对象序列化流对一个对象进行序列化后,假如对所属的类文件进行了修改,然后再读取数据时,会抛出InvalidClassException异常。
如何处理该异常?只需在所属类中添加一个serialVersionUID,具体代码如下:
private static final long serialVersionUID = 42L;
如果一个对象中的某个成员变量的值不想被序列化,那可以给该成员变量添加transient
关键字修饰,标记该成员变量不参与序列化。
1.4 Properties
(1)概述
- Properties是一个Map体系的集合类,继承自Hashtable,是线程安全的。
- Properties可以保存到流中或从流中加载。
(2)特有方法
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) | 设置集合的键和值,都是String类型,底层调用Hashtable的put()方法 |
String getProperty(String key) | 从属性列表中查找指定键的值 |
Set< String> stringPropertyNames() | 从属性列表中返回一个不可修改的键集,其中键及其值都是字符串 |
(3)与IO流结合的方法
方法名 | 说明 |
---|---|
void load(InputStream inStream) | 从输入字节流读取属性列表(键和元素对) |
void load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
void store(OutputStream out, String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(InputStream)方法加载到 Properties表中的格式输出流。 |
void store(Writer writer, String comments) | 将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式输出到输出字符流。 |
拓展1:比较字节流和字节缓冲流的效率
/*
比较四种方式实现复制音乐的速度:
1.基本字节流一次读写一个字节 共耗时56049毫秒。
2.基本字节流一次读写一个字节数组 共耗时72毫秒。
3.字节缓冲流一次读写一个字节 共耗时240毫秒。
4.字节缓冲流一次读写一个字节数组 共耗时14毫秒。
*/
import java.io.*;
public class CopyMusic {
public static void main(String[] args) throws Exception {
// 记录开始时间
long startTime = System.currentTimeMillis();
// 复制音乐
// method1();
// method2();
// method3();
method4();
// 记录结束时间
long endTime = System.currentTimeMillis();
// 打印复制所耗费的时间
System.out.println("共耗时" + (endTime - startTime) + "毫秒。");
}
/**
* 1.基本字节流一次读写一个字节
*/
private static void method1() throws Exception {
FileInputStream fis = new FileInputStream("E:\\KuGou\\梦然 - 少年.mp3");
FileOutputStream fos = new FileOutputStream("梦然 - 少年.mp3");
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 释放资源
fos.close();
fis.close();
}
/**
* 2.基本字节流一次读写一个字节数组
*/
private static void method2() throws Exception {
FileInputStream fis = new FileInputStream("E:\\KuGou\\梦然 - 少年.mp3");
FileOutputStream fos = new FileOutputStream("梦然 - 少年.mp3");
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
// 释放资源
fos.close();
fis.close();
}
/**
* 3.字节缓冲流一次读写一个字节
*/
private static void method3() throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\KuGou\\梦然 - 少年.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("梦然 - 少年.mp3"));
int by;
while ((by = bis.read()) != -1) {
bos.write(by);
}
// 释放资源
bos.close();
bis.close();
}
/**
* 4.字节缓冲流一次读写一个字节数组
*/
private static void method4() throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\KuGou\\梦然 - 少年.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("梦然 - 少年.mp3"));
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
// 释放资源
bos.close();
bis.close();
}
}
拓展2:编码表
(1)计算机中任何存储的信息都是采用二进制表示的。
(2)编码:按照某种规则,将字符转换为二进制数并存储到计算机中。
(3)解码:按照某种规则,将存储在计算机中的二进制数解析显示出来。
编码和解码使用的编码格式必须相同,否则会出现乱码。
(4)字符编码:字符编码就是一套自然语言的字符与二进制数之间的对应规则,比如ASCII码中A→65、a→97等。
(5)字符集:字符集是一个系统支持的所有字符的集合,包括各个国家的文字、数字、标点符号、图形符号等。常见字符集有ASCII、GBK、UTF-8、Unicode等。
拓展3:String、StringBuffer、StringBuilder的区别
(1)String
String的值是不可变的,即每次对String的操作都会生成新的String对象。不仅效率低,而且会浪费大量有限的内存空间。
(2)StringBuffer
StringBuffer是可变的,即每次对StringBuffer的操作都不会产生新的对象,而是在原来的对象上进行修改。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量;当字符串大小超过容量时,会自动增加容量。StringBuffer是线程安全的,常用于多线程操作字符串缓冲区。
(3)StringBuilder
与StringBuffer一样,StringBuilder也是可变的。然而,它是线程不安全的,但其速度更快,常用于单线程操作字符串缓冲区。
【程序员养成之路】Java基础篇 2-初学Java必知的基础语法
【程序员养成之路】Java基础篇 3-反手就能写个冒泡排序的数组
【程序员养成之路】Java基础篇 5-从异常机制认识常见bug
【程序员养成之路】Java基础篇 7-流进流出的IO流(一)
【程序员养成之路】Java基础篇 9-认识一下类加载器与反射