--------------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流! --------------------
1. 序列化对象
1.概述
对象被序列化后,然后存到硬盘的文件中,然后读取的时候可以方便的读取,要被存到硬盘文件中的对象类,必须实现接口Serializable接口,此接口中没有抽象方法,是为了标识类的。
ObjectOutputStream的方法writeObject()和ObjectInputStream的方法readObject(),这两个方法是成对出现的,一个是写,一个是读。
注意点:
1.当被序列化的对象存到了硬盘上后,如果原来的类更改了,那么再次读取的时候,会读取失败,因为他们的标识ID被更改了,所以要向更改后,仍可以读取的话,那么在序列化的时候,指定固定的标识ID。static final long serialVersionUID = 42L;
2.静态成员不能被序列化,因为序列化的都是在堆中,而静态的成员实在方法区中,如果非静态成员要向也不被序列化,那么由关键字:transient修饰,那么就会不被序列化。
3.当文件中存储了多个对象,那么读取的时候没调用一次readObject方法,就读取一个对象。
2.示例
用序列标识号来标识类,那么原来的类更改了一些操作,那么也可以继续使用硬盘中被序列化的文件对象。
- import java.io.Serializable;
- public class Person implements Serializable {
- static final long serialVersionUID = 42L;
- private String name;
- int age;
- public Person(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String toString() {
- return name + ":" + age;
- }
- }
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- public class SerDemo {
- public static void main(String[] args) throws Exception {
- // WritePerson();
- ReadPerson();
- }
- /* 写 */
- private static void ReadPerson() throws IOException,FileNotFoundException,
- ClassNotFoundException {
- ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
- "F:\\per.txt"));
- Person p = (Person) ois.readObject();
- System.out.println(p);
- }
- /* 读 */
- private static void WritePerson() throws IOException,FileNotFoundException {
- ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
- "F:\\per.txt"));
- oos.writeObject(new Person("zhangsan", 23));
- oos.close();
- }
- }
- 结果:
- zhangsan:23
至于静态成员和非静态成员被transient修饰,自己看以测试一下。
2. 管道流
将输入流和输出流。连接起来有两种方式:利用构造函数,或者用connect()方法。
- public class Write implements Runnable {
- private PipedOutputStream out = null;
- public Write(PipedOutputStream out) {
- super();
- this.out = out;
- }
- public void run() {
- try {
- System.out.println("开始写入数据,等待");
- Thread.sleep(4000);
- out.write("guandao".getBytes());
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- import java.io.IOException;
- import java.io.PipedInputStream;
- public class Read implements Runnable {
- private PipedInputStream in = null;
- public Read(PipedInputStream in) {
- this.in = in;
- }
- public void run() {
- try {
- System.out.println("没有数据可读");
- byte [] b=new byte[1024];
- int len=in.read(b);
- System.out.println("读到数据");
- System.out.println(new String(b,0,len));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- import java.io.IOException;
- import java.io.PipedInputStream;
- import java.io.PipedOutputStream;
- public class PideDemo {
- public static void main(String[] args)throws IOException {
- PipedOutputStream pds=new PipedOutputStream();
- PipedInputStream pis=new PipedInputStream();
- pds.connect(pis);//链接
- Write w=new Write(pds);
- Read r=new Read(pis);
- new Thread(w).start();
- new Thread(r).start();
- }
- }
- 结果:
- 开始写入数据,等待
- 没有数据可读
- 读到数据
- guandao
3. RandomAccessFile
随机访问文件,自身具备读写方法
1.特点:
不是IO包中的子类,直接继承Object但是是IO包成员,既可以读也可以写。内部封装一个数组,通过指针进行操作。
可以通过getFilePointer()和seek()方法设置指针的位置
2. 读写原理:就是内部分装了字节输入流和输出流。
3.通过构造函数知,只能操作文件。有模式:r,rw,rws,rwdbv
4. 跳过指定的字节数skipBytes(n);只能向后跳
5.如果模式是r,不会创建文件,会去读一个已经存在的文件,不存在,则抛出异常。如果模式是rw,操作文件不存在,则自动创建,要是文件存在,则不会覆盖。
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- public class RandomAccessFileDemo {
- public static void main(String[] args) throws IOException {
- RandomAccessFile raf = new RandomAccessFile(new File("F:\\demo.txt"),
- "rw");// 可读可写
- /*写*/
- raf.write("张三".getBytes());
- raf.write(23);
- raf.close();
- raf = new RandomAccessFile(new File("F:\\demo.txt"), "rw");// 可读可写
- /*读*/
- byte[] b = new byte[4];
- int l = raf.read(b);
- System.out.println(new String(b, 0, l));
- }
- }
4. DataInputStream和DataOutputStream
是用来操作基本数据类型的类。
注意点:
writeUTF方法是用来操作指定写入的编码是utf-8方式,但是他是修改版本,在此写入的文件,只能应此对象来读取,其他的对象是读取不出来的,因为是修改版的。
- public static void main(String[] args) throws IOException {
- DataWrite();
- DataRead();
- }
- public static void DataWrite() throws IOException{
- DataOutputStream out=new DataOutputStream(new FileOutputStream("F:\\data.txt"));
- out.writeInt(123);
- out.writeBoolean(true);
- out.writeDouble(34.87);
- out.writeDouble(1.1);
- out.close();
- }
- public static void DataRead() throws IOException{
- DataInputStream in=new DataInputStream(new FileInputStream("F:\\data.txt"));
- int a=in.readInt();
- boolean b=in.readBoolean() ;
- double c=in.readDouble();
- in.close();
- System.out.println(a);
- System.out.println(b);
- System.out.println(c);
- }
- 结果:
- 123
- true
- 34.87
5. ByteArrayInputStream和ByteArrayOutputStream
用于操作字节数组
这两个流对象操作的数组,没有使用系统资源(没有创建文件),所以不用关闭。
ByteArrayInputStream:不用定义数据目的,因为封装了一个可变的字节数组
在流操作的规律中:
源和目的除了:键盘和文件,还有内存,内存就是ByteArrayInputStream和ByteArrayOutputStream,就是操作字节数组流。
- public static void main(String[] args) throws IOException {
- ByteArrayInputStream in=new ByteArrayInputStream("abcd".getBytes());
- ByteArrayOutputStream out=new ByteArrayOutputStream();
- int ch=0;
- while((ch=in.read())!=-1){
- out.write(ch);
- }
- System.out.println(out.size());
- System.out.println(out.toString());
- }
|
CharArrayReader和CharArrayWriter 这两个类和ByteArrayInputStream,ByteArrayOutputStream使用一样,只是一个操作字符数组另一个操作字节数组,
StringReader与StringWriter用法也一样,只是操作的字符串
注意点:writeTo(OutputStream out)方法可以把数组中的数据直接写到流中。
6.编码表
ISO8859-1:属于单字节编码方式,主要是在0~255字符范围,只要在英语在英文上。
GBK/GBK2312:中文的编码方式,只要是标识汉字,
Unicod:使用的是16进制的编码方式。
UTF:可以是字符的长度是1-6字符,这样可以节约空间。兼容所有字符。
转换流之间的编码
编码表:就是把各个国家的文字全部用数字表示出来,应用于计算机,那么这样就形成了一个表,就是编码表
GBK:一个汉字站两个字节
UTF-8:一个汉字占三个字节
同样的编码方式要用同样的变法方式读取,否则会出现乱码
- public class Text {
- public static void main(String[] args) throws IOException {
- //writeTxt();
- readTxt();
- }
- public static void writeTxt() throws IOException{
- OutputStreamWriter writer=new OutputStreamWriter(new FileOutputStream("F:\\utf.txt"),"utf-8");
- writer.write("大家好");
- writer.close();
- }
- public static void readTxt() throws IOException{
- InputStreamReader reader=new InputStreamReader(new FileInputStream("F:\\utf.txt"),"utf-8");
- char []bu=new char[20];
- int len=reader.read(bu);
- System.out.println(new String(bu,0,len));
- reader.close();
- }
- }
7. 字符的编码和解码
编码:字符串变成字节数组String—》byte[]String.getBytes(charsetName);
解码:字节数组变成字符串byte[]->String new String(byte[],chatsename)
- public class Text {
- public static void main(String[] args) throwsUnsupportedEncodingException {
- String s1="你好";
- byte [] b1=s1.getBytes("GBK");
- System.out.println(Arrays.toString(b1));//编码表
- //假如编码方式变了
- String s2=new String(b1,"ISO8859-1");
- System.out.println(s2);
- byte [] b2=s2.getBytes("ISO8859-1");
- System.out.println(Arrays.toString(b2));//编码表
- System.out.println(new String(b1,"GBK"));
- }
- }
- 结果:
- [-60, -29, -70, -61]
- ????
- [-60, -29, -70, -61]
- 你好
注意:如果是GBK和UTF-8,之间编码方式乱了,就不能还原,因为GBK和UTF-8编码的时候,一个汉字对应的字节数不一样,所以还原后的字节数不一样,所仍然会出现乱码。
8.字符编码-联通
- 因为”联通” 用GBK存的产生的二进制和UTF-8编码方式一致(巧合) 11000001 10101010 11001101 10101000 用UTF-8存储的话,
- public class Text {
- public static void main(String[] args) throwsUnsupportedEncodingException {
- String s1="联通";
- byte [] b1=s1.getBytes("GBK");
- for(byte b:b1){
- System.out.println(Integer.toBinaryString(b&255));//将其转换成二进制,然后取后八位
- }
- }
- }
- 结果:
- 11000001
- 10101010
- 11001101
- 10101000
从结果可以看出:原本是用GBK编码,但是而进行却符合UTF-8的编码方式,所以直接用UTF-8进行解码,那么解析出来的结果当然会是乱码。
解决方式:在联通前面加任意汉字。
UTF-8编码方式字节读取个数