黑马程序员_>

时间:2023-02-18 14:56:26

--------------------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编码方式字节读取个数

 黑马程序员_>



-------------------- ASP.Net+Android+IOS开发 .Net培训 、期待与您交流! --------------------