IO流3

来源:互联网 发布:网络伤感情歌对唱 编辑:程序博客网 时间:2024/05/16 04:51


一、ObjectinputStream与ObjectOutputStream  操作对象

1、对象的序列化

ObjectinputStream与ObjectOutputStream

被操作的对象需要实现Serializable(标记接口)
类通过实现 java.io.Serializable 接口以启用其序列化功能。

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。

2、注意:

1)、静态不能被序列化
2)、实现Serializable后,根据成员数据标识创建UID号。
3)、若想使成员不被序列化,可以自定义UID号。例:static final long serialVersionUID = 42L;

例1
import java.io.*;class Person implements Serializable//实现该接口,相当于打上了被序列化的标识{public static final long serialVersionUID=42L;//自定义UID号private String name;transient int age;//非静态成员不想被序列化,需要transient关键字标识static String country="cn";//静态成员不能被序列化Person(String name,int age,String country){this.name=name;this.age=age;this.country=country;}public String toString(){return name+":"+age+":"+country;}}

import java.io.*;class ObjectStreamDemo{public static void main(String[] args)throws Exception{//writeObj();readObj();}public static void readObj()throws Exception//后读{ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.txt"));//读取文件Person p=(Person)ois.readObject();//强转System.out.println(p);ois.close();//关流}public static void writeObj()throws IOException//先写{ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("obj.txt"));//写入数据oos.writeObject(new Person("lisi",39,"cn"));写入数据oos.close();//关流}}
结果输出:

二、管道流

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

例1
import java.io.*;class Read implements Runnable{private PipedInputStream in;Read(PipedInputStream in){this.in=in;}public void run(){try{byte[] buf=new byte[1024];//数组容器System.out.println("读取前..没有数据阻塞");int len=in.read(buf);//数据搬运工System.out.println("读到数据..阻塞结束");String s=new String(buf,0,len);//用字符串变量s记录数据System.out.println(s);in.close();//关流}catch (IOException e){throw new RuntimeException("管道读取流失败");}}}class Write implements Runnable{private PipedOutputStream out;Write(PipedOutputStream out){this.out=out;}public void run(){try{System.out.println("6秒后输送数据");Thread.sleep(6000);//线程休眠6秒out.write("piped lai la".getBytes());//因为是字节流读取,需转换类型out.close();//关流}catch (Exception e){throw new RuntimeException("管道输出流失败");}}}class PipedStreamDemo{public static void main(String[] args)throws IOException{PipedInputStream in=new PipedInputStream();//读取管道PipedOutputStream out=new PipedOutputStream();//输出管道in.connect(out);//两管道相互关联,接通Read r=new Read(in);//函数与对应管道关联Write w=new Write(out);new Thread(r).start();//开启负责对应函数的线程new Thread(w).start();}}
结果输出:

三、RandomAccessFile

RandomAccessFile
a、随机访问文件,自身具备读写的方法
b、通过skipBytes(int x),seek(int x)来达到随机访问

该类不算是IO体系中子类。
而是直接继承自Object。

但是它是IO包中成员,因为它具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置。

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

通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw等。

如果模式为只读r,不会创建文件,会去读取一个已存在文件。如果该文件不存在,则会出现异常。
如果模式rw,操作的文件不存在,会自动创建。如果存在,则不会覆盖。


例1
import java.io.*;class RandomAccessFileDemo{public static void main(String[] args)throws IOException{//writeFile_2();readFile();//System.out.println(Integer.toBinaryString(258));}public static void readFile()throws IOException{RandomAccessFile raf=new RandomAccessFile("ran.txt","r");//只开启读取模式,读取文件//调整对象中指针。//raf.seek(8*1);它可以前后任跳//跳过指定的字节数,但是它只能从前往后跳,不能倒回来raf.skipBytes(8);byte[] buf=new byte[4];raf.read(buf);String name=new String(buf);//字符变量表示数组中的元素int age=raf.readInt();System.out.println("name="+name);System.out.print("age="+age);raf.close();}public static void writeFile_2()throws IOException{RandomAccessFile raf=new RandomAccessFile("ran.txt","rw");//用读写模式,创建写入文件raf.seek(8*0);//因为8字节为一组,选择在第一组覆盖raf.write("周期".getBytes());//转换为字节raf.writeInt(103);//按四个字节将 int 写入该文件raf.close();//关流}public static void writeFile()throws IOException{RandomAccessFile raf=new RandomAccessFile("ran.txt","rw");//用读写模式,创建写入文件raf.write("李四".getBytes());//转换为字节raf.writeInt(97);//按四个字节将 int 写入该文件raf.write("王五".getBytes());raf.writeInt(99);raf.close();//关流}}
结果输出:

四、DateInputStream与DateOutputStream

1、概述

可以用于操作基本数据类型的数据的流对象。

数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。 

数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。


例1

/*DateInputStream与DateOutputStream可以用于操作基本数据类型的数据的流对象。*/import java.io.*;class DataStreamDemo{public static void main(String[] args)throws IOException{readData();}public static void readData()throws IOException{DataInputStream dis=new DataInputStream(new FileInputStream("hahaa.txt"));//与流关联,读取文件数据int num=dis.readInt();//操作基本数据类型boolean b=dis.readBoolean();double d=dis.readDouble();System.out.println("num="+num);System.out.println("b="+b);System.out.println("d="+d);dis.close();//关流}public static void writeData()throws IOException{DataOutputStream dos=new DataOutputStream(new FileOutputStream("hahaa.txt"));//与流关联,创建写入文件dos.writeInt(234);//操作基本数据类型dos.writeBoolean(true);dos.writeDouble(9887.543);dos.close();//关流}public static void readUTFdemo()throws IOException//以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。{DataInputStream dis=new DataInputStream(new FileInputStream("utfdate.txt"));String s=dis.readUTF();System.out.println(s);dis.close();}public static void writeUTFDemo()throws IOException//以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。{DataOutputStream dos=new DataOutputStream(new FileOutputStream("utfdate.txt"));dos.writeUTF("您好");dos.close();}}
结果输出:


五、ByteArrayInputStream与ByteArrayOutputStream

用于操作字节数组的流对象。

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

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

在流操作规律讲解时:

源设备:
键盘 System.in 硬盘 FileStream 内存 ArrayStream
目的设备:
控制台 System.out 硬盘 FileStream neicun ArraStream

用流的读写思想来操作数据。

例1

import java.io.*;class ByteArrayStream{public static void main(String[] args){//数据源ByteArrayInputStream bis=new ByteArrayInputStream("ABCDFG".getBytes());//转换为字节//数据目的ByteArrayOutputStream bos=new ByteArrayOutputStream();int by=0;//搬运工while((by=bis.read())!=-1)//遍历数组{bos.write(by);}System.out.println(bos.size());//求容量System.out.println(bos.toString());//以字符串形式打印//bos.writeTo(new FileOutputStream("a.txt"));写入到文件中}}
结果输出:


六、CharArrayReader与CharArrayWrite;StringReader 与 StringWriter

l操作字符数组
CharArrayReader与CharArrayWrite
l操作字符串
StringReader 与 StringWriter

它们的操作方式类似于ByteArrayInputStream与ByteArrayOutputStream,
就是操作对象不同。

七、字符编码

1、概述

1)字符流的出现为了方便操作字符。
2)更重要是的加入了编码转换。
3)通过子类转换流来完成。
4)InputStreamReaderOutputStreamWriter在两个对象进行构造的时候可以加入字符集

2、编码表的由来

计算机只能识别二进制数据,早期由来是电信号。
为了方便应用计算机,让它可以识别各个国家的文字。
就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

3、常见的编码表

ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。

4、转换流的编码应用

可以将字符以指定编码格式存储。
可以对文本数据指定编码格式来解读。
指定编码表的动作由构造函数完成。

字符编码
编码:字符串-->字节数组
解码:字节数组-->字符串

注意1:因为GBK和UTF—8都识别中文,但GBK2个字节为一个字符,UTF3个字节为一个字符。
编码(GBK)-->解码(UTF-8)-->编码(UTF-8).-->解码(GBK)运行后是看不懂的字符。
GBK与其他编码表可以转换。

注意2:在记事本中输入:"联通",关闭后打开,出现了看不懂的信息。
是因为咱们默认编码是GBK没错,但是“联通”的二进制形式恰好符合UTF-8的标识头的格式,
所以读的是UTF-8的表。
 
解决方案:不仅仅写“联通“这两字,前面加上其他中文字符即可识别。(加英文字符仍不能识别)

例1
import java.io.*;class EncodeDemo{public static void main(String[] args)throws Exception{String s="你好";byte[] b1=s.getBytes("GBK");System.out.println(Array.toString(b1));String s1=new String(b1,"ISO8859-1");System.out.println("s1="+s1);//对s1进行iso8859-1编码byte[] b2=s1.getBytes("iso8859-1");System.out.println(Arrays.toString(b2));String s2=new String(b2,"gbk");System.out.println("s2="+s2);}}

小练习:

package study;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.util.Collections;import java.util.Comparator;import java.util.Set;import java.util.TreeSet;/*有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩),输入的格式,如:zhangsan,30,40,60计算出总成绩,并把学生的信息和计算出的总分数高低顺序存放在磁盘文件“stud.txt”中。1、描述学生对象。2、定义一个可操作学生对象的工具类。思想:1、通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。2、因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。所以可以使用TreeSet。3、将集合的信息写入到一个文件中。 1。创建学生类,使其具备比较特性 2.覆写equals、toString、compareTo方法 3、定义一个操作学生对象的工具类 4、通过键盘读取数据 5、用,切割,并添加到TreeSet数组中来 6、用操作集工具类的方法反转比较器*///实现此接口具备比较功能class Student implements Comparable<Student>{private String name;private int ma,cn,en;private int sum;//构造函数初始化Student(String name,int ma,int cn,int en){this.name=name;this.ma=ma;this.cn=cn;this.en=en;sum=ma+cn+en;}//覆写compareTo方法public int compareTo(Student s){int num=new Integer(this.sum).compareTo(new Integer(s.sum));//先比较总分if(num==0)return this.name.compareTo(s.name);//总分相等则比较名字return num;}//获取名字方法public String getName(){return name;}//获取总分方法public int getSum(){return sum;}//给定一个哈希值public int hashCode(){return name.hashCode()+sum*78;}//覆写equals方法public boolean equals(Object obj){if(!(obj instanceof Student))//如果传入的对象不属于学生类型throw new ClassCastException("类型不匹配");//强转Student s=(Student)obj;return this.name.equals(s.name) && this.sum==s.sum;}//返回字符串形式public String toString(){return "student["+name+", "+ma+", "+cn+", "+en+"]";}}class StudentInfoTool{//调用不带比较器的方法public static Set<Student> getStudents()throws IOException{return getStudents(null);}//带比较器的方法public static Set<Student> getStudents(Comparator<Student> cmp)throws IOException{//带缓冲区的控制台读取BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));String line=null;//定义行读取容器Set<Student> stus=null;//定义为成员变量方便调用if(cmp==null)stus=new TreeSet<Student>();elsestus=new TreeSet<Student>(cmp);//循环读写while((line=bufr.readLine())!=null){if("over".equals(line))//此行输入over结束break;String[] info=line.split(",");//以逗号切割//切割后的得到的Student对象Student stu=new Student(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[3]));//把切割得到的对象添加到集合中stus.add(stu);}bufr.close();//关流return stus;}//写入到文件的方法public static void writeFile(Set<Student> stus)throws IOException{BufferedWriter bufw=new BufferedWriter(new FileWrite("111111111111.txt"));//增强for循环遍历写入for(Student stu:stus){bufw.write(stu.toString()+"\t");//带着制表符以字符串形式输出bufw.write(stu.getSum()+"");//转为字符串形式写入bufw.newLine();//换行bufw.flush();//刷新}bufw.close();//关流}}class StudentInfoTest{public static void main(String[] args) throws IOException{//逆转TreeSet自然排列顺序Comparator<Student> cmp=Collections.reverseOrder();//获取Set学生对象Set<Student> stus=StudentInfoTool.getStudents();StudentInfoTool.writeFile(stus);}}
结果输出:








0 0
原创粉丝点击