JAVASE学习笔记第21天

本文详细介绍了Java中对象序列化的基本概念、序列化类的注意事项、使用序列化进行文件持久化的方法,以及如何利用管道流(PipedInputStream和PipedOutputStream)进行高效的数据传输。此外,还探讨了RandomAccessFile的随机访问特性及其在多线程读写场景的应用,以及操作基本数据类型的流对象(DataInputStream和DataOutputStream)的特点和用法。文章最后总结了ByteArrayInputStream和ByteArrayOutputStream等字节流操作数组的方法,并讨论了字符编码转换的实现。通过丰富的实例代码,旨在帮助读者深入理解并掌握这些高级IO流技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IO流(对象的序列化)

1、一般要序列化的类:

a)       实现Serializable 以启用其序列化功能

b)       在该类中定义固定的序列号:

 static final longserialVersionUID = 42L;

注意:序列号的作用就是给类一个标识

 

2、静态不能被序列化

被transient 修饰的变量也不能被序列化

 

3、ObjectInputStream和 ObjectOutputStream是成对使用的

 

4、操作对象:

ObjectInputStream和 ObjectOutputStream

被操作的对象需要实现Serializable接口,(标记接口)

 

5、一般保存之后文件名的后缀为.object

 

例子:

/**

调用序列化的类

*/

import java.io.*;

 

class Demo1

{

       publicstatic void main(String[] args)throws Exception

       {

              readObj();

       }

 

       //存文件

       publicstatic void writeObj()throws IOException

       {

              FileOutputStreamfos = new FileOutputStream("demo1.object");

              ObjectOutputStreamoos = new ObjectOutputStream(fos);

 

              oos.writeObject(newPerson("lili",20));

 

              oos.close();         

       }

 

       //读文件

       publicstatic void readObj()throws Exception

       {

              FileInputStreamfis = new FileInputStream("demo1.object");

              ObjectInputStreamois = new ObjectInputStream(fis);

 

              Personp =(Person)ois.readObject();

 

              System.out.println(p);

 

              ois.close();

       }

}

 

IO流(管道流)

1、PipedInputStream和 PipedOutputStream

输入输出可以直接进行连接,通过结合线程使用。

 

2、注意:要先把管道接上,接上管道的方法有两种

l  构造函数:

PipedOutputStream(PipedInputStreamsnk)throws IOExcepiton

PipedInputStream(PipedOutputStreamsrc)throws IOException

 

 
public void connect(PipedInputStream snk)

l               throws IOException

 

 

public void connect(PipedOutputStream src)

             throws IOException

 

 

示例:

import java.io.*;

 

//描述一个写入类

class Write implements Runnable 

{

      //写入管道

      private PipedOutputStreampos;

      Write(PipedOutputStreampos)

      {

             this.pos=pos;

      }

      public void run() //记住这里的run方法不能够抛出异常,因为父类没有抛出

      {

             try

             {

                    //写入

                    pos.write("xierulai le ".getBytes());

                    pos.flush();

                    pos.close();                       

             }

             catch (IOExceptione)

             {

                    throw newRuntimeException("写入失败");

             }            

      }

}

 

//描述一个读取类

class Read implements Runnable

{

      //读取管道

      private PipedInputStreampis;

      Read(PipedInputStreampis)

      {

             this.pis=pis;

      }

      public void run()

      {

             try

             {

                    //读取数据

                    byte[]buf=new byte[1024];

                    int len =pis.read(buf); //记住这个方法返回的是int型的

                   

                    String s=new String(buf,0,len); //记住这个

 

                    System.out.println(s);

 

                    pis.close();

                   

             }

             catch (IOExceptione)

             {

                    throw newRuntimeException("读取失败");

             }     

      }

}

 

class Demo2

{

      public static voidmain(String[] args)throws Exception

      {

             PipedInputStreampis = new PipedInputStream();

             PipedOutputStreampos =new PipedOutputStream();

             //先要把流接上

             pos.connect(pis);

 

             Read read = newRead(pis);

             Write write = newWrite(pos);

 

             newThread(read).start();

             newThread(write).start();

      }

}

IO流(RandomAccessFile)

1、随机访问文件,自身具备读写的方法

通过skipBytes(int x) 或者seek(int x)来达到随即访问。

 

2、特点:

l  该类不算是IO体系中子类,而是直接集成Object。

 

l  但是他是IO包中成员,因为它具有读写的功能,内部封装了一个字节型数组,可以通过指针对数组中的元素进行操作。通过getFilePointer获取指针的位置;通过seek该指针的位置。

 

l  其实完成读写的原理就是内部封装了字节输入流和字节输出流

 

l  通过构造函数,可知,该类只能操文件,而且操作的文件还有模式:

只读:r  或者 读写:rw

如果模式为只读(r),不会创建文件,会读取一个已经存在的文件,如果文件不存在,则会出现异常

 

如果模式为读写(rw),如果文件存在,不会覆盖原文件,如果文件不存在,会创建文件。

 

3、用处:可以实现数据的多线程读写。

       把要操作的数据分段,然后分别分装在不同的线程中,通过控制指针,实现同时分段的操作,而且这样的数据是连续的。

 

4、对操作的数据的要求:数据的格式是一致,例如:前两个字节存名字,后四个字节存姓名。(格式为:(2,4))

 

5、举例:

      

       importjava.io.*;

 

class Demo3

{

       publicstatic void main(String[] args)throws IOException

       {

              //wirteFile();

              readFile();

       }

 

       //写

       publicstatic void wirteFile()throws IOException

       {            

              RandomAccessFileraf = new RandomAccessFile("ran.txt","rw");

              raf.write("李四".getBytes());

              raf.writeInt(97);

 

              raf.write("王五".getBytes());

              raf.writeInt(98);

 

              raf.close();          

       }

 

       //读

       publicstatic void readFile()throws IOException

       {

              RandomAccessFileraf = new RandomAccessFile("ran.txt","r");    

             

              //改变指针位置

              //raf.seek(8);

              //raf.skipBytes(8*0);

 

              byte[]buf =new byte[4];

 

              raf.read(buf);  //读取四个字节放在字节数组中

             

              //将字节数组转换为字符串

              Stringname = new String(buf);

              intage=raf.readInt(); //接着读取4个字节

 

              System.out.println(name+",....."+age);

       }

}

 

      

IO流(操作基本数据类型的流对象)

1、操作基本数据类型:

       DataInputStream和 DataOutputStream

3、如果使用了utf-8修改版编码写入的数据,只能够用对应的读取进行读取

4、示例:

 

import java.io.*;

 

class Demo4

{

       public static voidmain(String[] args)throws IOException

       {

              //write();

              //read();

              //writeUTF8();

               readUTF8();

       }

 

//写

       public static voidwrite()throws IOException

       {

              DataOutputStreamdis =

                     newDataOutputStream(new FileOutputStream("data.txt"));

 

              dis.writeChar('a');

              dis.writeInt(23);

 

              dis.close();

       }

 

//读

       public static voidread()throws IOException

       {

              DataInputStreamdis =

                     newDataInputStream(new FileInputStream("data.txt"));

             

              System.out.println(dis.readChar());

              System.out.println(dis.readInt());

 

              dis.close();

       }

 

       //utf-8修改版写,只是针对中文

       public static voidwriteUTF8()throws IOException

       {

              DataOutputStreamdos =

                     newDataOutputStream(new FileOutputStream("data1.txt"));             

 

              dos.writeUTF("你好");

 

              dos.close();

       }

 

       //utf-8修改版读,只是针对中文

       public static voidreadUTF8()throws IOException

       {

              DataInputStream dis =

                     newDataInputStream(new FileInputStream("data1.txt"));            

 

              System.out.println(dis.readUTF());

 

              dis.close();

       }

}

 

IO流(ByteArrayStrea)

 

 

 

1、操作字节的数组:

ByteInputStream 和 ByteOutputStream

2、操作字符的数组:

CharReader 和 CharWriter

3、操作字符串的数组:

StringReader 和 StringWriter

 

4、用于操作字节数组的流对象:

l  ByteArrayInputStream:在构造的时候需要源,而且源是一个字节数组

l  ByteArrayOutputStream: 在构造的时候不需要定义目的,因为该对象的内部已经封装了可变长度的字节数组,而这个数组就是数据的目的。

l   

注意:因为这两个流对象操作的都是数组,并没有使用系统的资源,所以不用关闭。

 

l  在流操作的讲解时:

²  源设备:

键盘(System.in)、硬盘(File)、内存(ArrayStream)

 

²  目的:

键盘(System.out)、硬盘(File)、内存(ArrayStream)

 

  作用:可以用流操作的思想来操作数组

 

5、例子:

import java.io.*;

 

class Demo5

{

       public static voidmain(String[] args)

       {

              ByteArrayMethod();

       }

 

       public static voidByteArrayMethod()

       {

              //源

              ByteArrayInputStreambais =

                     newByteArrayInputStream("abdcdde".getBytes());

 

              //目的

              ByteArrayOutputStreambaos =

                     newByteArrayOutputStream();

 

              int len =0;

 

              while((len=bais.read())!=-1)

              {

                     baos.write(len);

              }

 

              System.out.println(baos.size());

              System.out.println(baos.toString());

       }

}

IO流(转换流的字符编码)

1、字符流的出现是为了方便操作字符,更重要的是加入了编码转换。

2、字符流的编码转换:InputStreamReader和 OutputStreamWriter

3、在两个对象进行构造的时候,可以加入字符集

4、编码表:将各国的文字和数字一一对应,形成了一表,叫做编码表。

5.、各种编码表,其中常用的是gbk,utf-8,iso8859-1(服务器)

 

 

 

 

 

 

 

例子:

 

import java.io.*;

 

class Demo6

{

       publicstatic void main(String[] args)throws IOException

       {

              //write();

              read();

       }

      

       //写

       publicstatic void write()throws IOException

       {

              OutputStreamWriterosw =

                     newOutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");

 

              osw.write("你好");

              osw.close();

       }

 

       //读

       publicstatic void read()throws IOException

       {

              InputStreamReaderisr=

                     newInputStreamReader(new FileInputStream("gbk.txt"),"gbk");

 

              char[]buf=new char[10];

              intlen=isr.read(buf);

 

              Stringstr =new String(buf,0,len);

 

              System.out.println(str);

 

              isr.close();

       }

}

 

 

IO流(字符编码)

1、编码:将字符串变为字节数组

String----byte[] :   str.getBytes(编码名);

 

2、解码:将自己数组编程了字符串

byte[]----String:   new String(byte[],编码名);

 

3、在编码、解码的过程中,第一次编码编对了,但是在第一次解码的时候,解错了。这个时候,我们采取的措施就是,按照错误的解码,再对其进行一次编码,然后按照第一次编码中的编码表进行解码。这种现象常会使用在服务器上。

 

 

 

 

示例:

 

 

 

import java.io.*;

import java.util.*;  //Arrays是util包中的

 

class Demo7

{

       public static voidmain(String[] args)throws Exception

       {

              demo();

       }

 

       public static voiddemo()throws Exception

       {

              //字符串

              String str ="你好";

              //编码,正确

              byte[] by1=str.getBytes("GBK");

              //打印字节数组,查看

              System.out.println(Arrays.toString(by1));

 

              //第一次解码,错误

              String str1= newString(by1,"ISO8859-1");

              System.out.println(str1);

 

              //对str1进行编码

              byte[] by2 =str1.getBytes("iso8859-1");

              System.out.println(Arrays.toString(by2));

 

              //对by2进行解码

              String str2 = newString(by2,"gbk");

              System.out.println(str2);         

       }

}

 

IO流(字符编码—联通)

 

/**

一个有趣的现象:

当我们在记事本中顶头写“联通”保存之后,再次打开的时候,发生了乱码的现象

 

原因:

我们输入的时候,使用的是gbk,

但是由于“联通”这两个字的编码形式符合utf-8,

所以当我们再次使用记事本打开的时候,记事本会默认按照utf-8的读取形式进行读取。

 

代码模拟:

*/

 

class Demo8

{

       public  static void main(String[] args)throwsException

       {

              demo();

       }

 

       //模拟

       public static voiddemo()throws Exception

       {

              String str ="联通";

 

              //编码,按照gbk

              byte[] by=str.getBytes("gbk");

 

              for(byte b : by)

              {            

                     System.out.println(Integer.toBinaryString(b&255));

                     /*

                     11000001

                     10101010

                     11001101

                     10101000

 

                     这个格式符合utf-8的读取形式。

                     */

              }

       }

}

 

 

 

1、在描述类的时候,要覆盖hashCode、public boolean equals(Object obj)、toString()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值