1、IO流-对象序列化
需求:想要将封装了数据的对象进行持久化。当写入的对象很多,对象会按照顺序排列,也称之为对象的序列化。
1、先有对象
2、往硬盘上写数据进行持久化需要IO技术。输出流。FileOutputStream
3、在字节输出流的api中找到一个子类ObjectOutputStream
4、在基础流对象上使用额外功能。
方法:writeObject(Object obj); //将指定对象写入ObjectOutputStream,对象的类、类的签名、以及类的所有超类型的非瞬态和非静态字段的值都将被写入。
注意:类需要实现Serializable接口才能启动其序列化功能。
这个接口没有方法,叫做标记接口。
package IO_other;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException {
writeObj();
}
private static void writeObj() throws IOException {
Person p = new Person("leo", 24);
FileOutputStream fos = new FileOutputStream("F:\\javatest\\obj.object");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.close();
}
}
2、对象反序列化-ObjectInputStream
有一个对应的对象,叫ObjectinputStream用于读取存储对象的文件
package IO_other;
import java.io.*;
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//writeObj();
readObj();
}
private static void readObj() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("F:\\javatest\\obj.object");
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
System.out.println(obj);
}
private static void writeObj() throws IOException {
Person p = new Person("leo", 24);
FileOutputStream fos = new FileOutputStream("F:\\javatest\\obj.object");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.close();
}
}
前提:得有Person.class,没有这个都是白扯,得发class文件和object文件都发过来。
如果接收者加载的该对象的类的serialVersionUID与对应的发送者的类的版本号不同,则反序列化则会导致InvalidClassException异常。
3、序列化接口-Serilizable的作用
没有方法,不需要覆盖,是一个标记接口,为了启动一个序列化功能。
唯一作用:给每一个需要序列化的类都分配一个序列版本号。UID。
这个版本号和该类相关联,这就是这个接口的作用。
版本号的作用:验证用的。在序列化时,会将这个序列号也以同保存在文件中。在反序列化时,会读取这个序列号和本类的序列号进行匹配,如果不匹配,会抛出异常。
有默认UID,但是强烈建议所有可序列化类都显式声明serialVersionUID值,原因是计算默认的会因为编译器的不同可能千差万别。
ANY-ACCESS-MODIFIER static final long seriaVersionUID = 42L;
package IO_other;
import java.io.Serializable;
public class Person implements Serializable{
public static final long seriaVersionUID = 42L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name = " + name + ",age = " + age + "]";
}
}
3、瞬态关键字transient
静态数据是不会被序列化的,因为在静态区的方法区中,不在对象中。
对于一个非静态的数据也不想序列化(比如用户名的密码),那么就需要一个关键字来修饰,就是这个transient。
4、printStream&printWriter打印流
缺点:没有读,只有写
字节流和字符流已经掌握了很多对象。
需要关注:
1、IO流的基础流对象。直接调用底层资源操作数据的对象。File开头的流对象。
2、根据IO流的学习规律。后面出现的流对象无非是在增加一些额外功能。
继续提供一些功能。
需求:写一个数据(整数)到文件中。
package IO_other;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class printStreamDemo {
//需求:写一个整数,到目的地整数的表现形式不变。
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream(new File("F:\\javatest\\tempfile\\int.txt"));
//fos.write(353); //00000000 00000000 00000001 01100001 在字节流的write方法只将一个整数的最低字节写入到目的地中。不满足需求。
fos.write(Integer.toString(353).getBytes()); //这个解决方法可以,将整数转成字符串再写入到目的地
fos.close();
}
}
之前学习过输出语句,发现要输出的内容都是原样不变的体现出来。
输出语句的对象为printStream
package IO_other;
import java.io.*;
public class printStreamDemo {
//需求:写一个整数,到目的地整数的表现形式不变。
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("F:\\javatest\\tempfile\\ini.txt");
PrintStream ps = new PrintStream(fos);
ps.print(97);
ps.close();
}
}
这个对象提供了很多打印的方法,好处在于可以保证数据值的表现形式。
printWriter为字符打印流。
package IO_other;
import java.io.*;
public class printWriterDemo {
/*
读取键盘录入,将录入的数据转称大写保存到文件中
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter("F:\\javatest\\tempfile\\testPrintWriter.txt");
String line = null;
while ((line = br.readLine())!=null){
if("over".equals(line)){
break;
}
out.println(line.toUpperCase());
out.flush();
}
out.close();
}
}
package IO_other;
import java.io.*;
public class printWriterDemo {
/*
读取键盘录入,将录入的数据转称大写保存到文件中
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out,true); //自动刷新
String line = null;
while ((line = br.readLine())!=null){
if("over".equals(line)){
break;
}
out.println(line.toUpperCase());
//out.flush();
}
out.close();
}
}
想要将数据打印到 文件中,并自动刷新
PrintWriter out = new PrintWriter(new FileWriter("tempfile.txt"),true);
5、基本类型数据流-dataoutputStream&datainputStream
另一个需求:保证数据的值的字节原样性不变
例如:写一个整数,源为四个字节,希望目的也是四个字节。
需要一个可以读也可以写的操作基本类型数值的对象
DataoutputStream-数据输入流(用于读取)
DataOutputStream-数据输出流
package IO_other;
import java.io.*;
public class dataStreamDemo {
public static void main(String[] args) throws IOException {
//writedata();
readdata();
}
private static void readdata() throws IOException {
FileInputStream fis = new FileInputStream("F:\\javatest\\datastream.txt");
DataInputStream dis = new DataInputStream(fis);
int count = dis.readInt();
System.out.println(count);
dis.close();
}
private static void writedata() throws IOException {
FileOutputStream fos = new FileOutputStream("F:\\javatest\\datastream.txt");
//需要额外功能吗。需要,可以写一个基本数值的原字节不变
DataOutputStream dos = new DataOutputStream(fos);
dos.writeInt(97); //00000000 00000000 00000000 01100001 三个空白一个a
dos.close();
}
}
6、用于操作数组和字符串的流对象
类 ByteArrayOutputStream
此类实现了一个输出流,其中的数据被写入一个byte数组。缓冲区会随着数据的不断写入而自动增长。可使用toByteArray()和toString()获取数据。
源和目的都是内存的流对象
字节流:ByteArrayInputStream BytearrayoutputStream
字符流:chararrayreader chararraywriter stringreader stringwriter
原理:通过流的read,write方法对数组以及字符串进行操作。
关闭这些流都是无效的,因为本来就是在内存中操作,并未调用系统资源,不需要抛出IO异常。
package IO_other;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
public class ByteArrayStreamDemo {
public static void main(String[] args) {
//源和目的都是内存的读写过程
//源
ByteArrayInputStream bis = new ByteArrayInputStream("abcde".getBytes()); //用流的读写思想操作数组中的数据
//目的
ByteArrayOutputStream bos = new ByteArrayOutputStream(); //内部有一个可自动增长的数组
//不断读写
int ch = 0;
while ((ch = bis.read()) != -1) {
bos.write(ch);
}
//因为没有调用底层资源,所以不需要关闭,即使调用了close也没有任何效果,不会抛出IO异常。
System.out.println(bos.toString());
}
}
7、IO流-RandomAccessFile
需求:对文件进行读或者写的操作,不从头开始,想从哪里读/写,就从哪里读/写。
本身不是流对象,此类的实例支持对随机访问文件的读取和写入。
只能操作文件。
这个对象既能读,又能写。
package IO_other;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class randomaccessFiledemo {
public static void main(String[] args) throws IOException {
//randomaccessfile
//1、实现随机访问
//2、操作的是随机文件
//3、既可以读,又可以写
//4、内部维护了用于存储数据的byte数组
//5、提供了一个对数组操作的文件指针
//6、文件指针可以通过getFilePointer方法读取,通过seek方法设置
//7、随机读写,数据需要有规律
writeFile();
}
private static void writeFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("F:\\javatest\\randomaccessfile.txt","rw");
/* //写一些字符信息
raf.write("张三".getBytes());
raf.writeInt(97); //保证字节的原样性
raf.write("李四".getBytes());
raf.writeInt(99); //保证字节的原样性*/
raf.seek(8); //从第八个字节开始写
raf.write("刘栋".getBytes());
raf.writeInt(102);
System.out.println(raf.getFilePointer()); //打印指针位置
raf.close();
}
}
可以结合多线程实现数据的同时写入,可以用于多线程的下载。
随机读:
package IO_other;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class randomaccessFiledemo {
public static void main(String[] args) throws IOException {
//randomaccessfile
//1、实现随机访问
//2、操作的是随机文件
//3、既可以读,又可以写
//4、内部维护了用于存储数据的byte数组
//5、提供了一个对数组操作的文件指针
//6、文件指针可以通过getFilePointer方法读取,通过seek方法设置
//7、随机读写,数据需要有规律
//writeFile();
readFile();
}
private static void readFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("F:\\javatest\\randomaccessfile.txt","r");
//改变其指针的位置,想读谁就读谁。
raf.seek(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
System.out.println("name = " + name);
int age = raf.readInt();
System.out.println("age = " + age);
}
private static void writeFile() throws IOException {
RandomAccessFile raf = new RandomAccessFile("F:\\javatest\\randomaccessfile.txt","rw");
/* //写一些字符信息
raf.write("张三".getBytes());
raf.writeInt(97); //保证字节的原样性
raf.write("李四".getBytes());
raf.writeInt(99); //保证字节的原样性*/
raf.seek(8); //从第八个字节开始写
raf.write("刘栋".getBytes());
raf.writeInt(102);
System.out.println(raf.getFilePointer()); //打印指针位置
raf.close();
}
}
局限性:
1、只能操作文件
优势:
把数据存储到数组中看,IO包中的一个工具类。