Java基础视频教程第21天_IO流之其他流对象、字符编码

来源:互联网 发布:ubuntu 关闭休眠 编辑:程序博客网 时间:2024/06/04 18:54

一、IO流——对象的序列化 

java.lang.Object -java.io.InputStream -java.io.ObjectInputStream public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants java.lang.Object -java.io.OutputStream -java.io.ObjectOutputStream public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants java.io.Serializable public interface Serializable 操作对象ObjectInputStream ObjectOutputStream 被操作的对象需要实现 Serializable(标记接口)。
构造方法:ObjectInputStream(InputStream in) :创建从指定 InputStream 读取的 ObjectInputStream。ObjectOutputStream(OutputStream out) :创建写入指定 OutputStream 的 ObjectOutputStream。
特有方法:ObjectInputStream 中:  Object readObject() 从 ObjectInputStream 读取对象。 ObjectOutputStream 中: void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream 。 
=====对象的持久化、对象的序列化、对象的可串行性。=====没有方法的接口,通常称为标记接口。=====类中的静态成员不可以被序列化。(可以将堆内存中的数据序列化,却不可以将方法区中的数据序列化)=====如果不需要将非静态成员序列化,可以用 transient 修饰该成员。=====序列化的对象一般不存成 .txt文件,而是存成 .object ;例如:person.object 代码:
import java.io.*;class ObjectStreamDemo {public static void main(String[] args) throws Exception {//writeObj();readObj();}public static void writeObj() throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));oos.writeObject(new Person("wangwu",18));oos.close();}public static void readObj() throws Exception {ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));Person p = (Person)ois.readObject();System.out.println(p);}}import java.io.*;class Person implements Serializable{static final long serialVersionUID = 42L;String name;int age;Person(String name, int age){this.name = name;this.age = age;}public String toString(){return name+":"+age;}}

二、IO流——管道流 

java.lang.Object 
-java.io.InputStream 
-java.io.PipedInputStream 

java.lang.Object 
-java.io.OutputStream 
-java.io.PipedOutputStream 

IO包中的其他类

管道流:
PipedInputStream 和 PipedOutputStream 
输入输出可以直接进行连接,通过结合线程使用。
该类都分别有两个构造方法,一个是空参数的构造方法,另一个需要传入管道流对象;空参数的构造方法表示创建时尚未建立连接,传入对象的构造方法则在创建时连接到指定的管道流。注意:如果创建尚未连接的管道流,需要调用connect方法进行连接,以下两个任选一个即可:PipedInputStream 类中的方法: void connect(PipedOutputStream src) 使此管道输入流连接到管道输出流 src。 PipedOutputStream 类中的方法: void connect(PipedInputStream snk) 将此管道输出流连接到接收者。 代码:
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);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秒后开始写入数据......");try{Thread.sleep(6000);}catch(Exception e){}out.write("piped aaaa bb".getBytes());out.close();}catch (IOException 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();}}

三、IO流—— RandomAccessFile 

java.lang.Object 
-java.io.RandomAccessFile 

public class RandomAccessFile extends Object implements DataOutput, DataInput, Closeable 

IO包中的其他类
RandomAccessFile: 
随机访问文件,自身具备读写的方法;
通过skipBytes(int x);seek(int x)来达到随机访问。

构造方法摘要:
RandomAccessFile(File file, String mode) :创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 
RandomAccessFile(String name, String mode) :创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
其他特点:1、该类不算是IO体系中的子类,而是直接继承 Object 。2、它是IO包中的成员,具备读写功能。3、内部封装了一个数组,而且通过指针对数组中的元素进行操作:可以通过getFilePointer 获取指针的位置;也可以通过seek改变指针的位置。4、其实完成读写的原理就是内部封装了字节输入流和输出流。5、通过构造函数可以看出,该类只能操作文件,而且还需指定模式: 只读 r ; 读写 rw 。6、如果模式为读写rw,该对象的构造函数要操作的文件不存在时,会自动创建,如果存在则不会覆盖。7、如果模式为只读r,不会创建文件,会去读取一个已存在的文件;如果该文件不存在,则会出现异常。8、该类中的方法可以直接写入和读取基本数据类型。代码:
import java.io.*;class RandomAccessFileDemo {public static void main(String[] args) throws IOException {writeFile_2();//readFile();}public static void readFile() throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","r");//调整数组中的指针//raf.seek(8*0);//跳过指定的字节数,只可以往下跳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.println("age="+age);raf.close();}public static void writeFile() throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");raf.write("李四".getBytes());//raf.write(258);raf.writeInt(97);raf.write("王五".getBytes());raf.writeInt(99);raf.close();}public static void writeFile_2() throws IOException {RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");raf.seek(8*3);raf.write("周七".getBytes());raf.writeInt(103);raf.close();}}

四、操作基本数据类型的流对象DataStream 

java.lang.Object 
-java.io.OutputStream 
-java.io.FilterOutputStream 
-java.io.DataOutputStream 
public class DataOutputStream extends FilterOutputStream implements DataOutput 

java.lang.Object 
-java.io.InputStream 
-java.io.FilterInputStream 
-java.io.DataInputStream 
public class DataInputStream extends FilterInputStream implements DataInput 

操作基本数据类型
DataInputStream 与 DataOutputStream 

代码:
import java.io.*;class DataStreamDemo {public static void main(String[] args) throws IOException {//writeData();//readData();//writeUTFDemo();readUTFDemo();}public static void writeData() throws IOException {DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));dos.writeInt(234);dos.writeBoolean(true);dos.writeDouble(9887.543);dos.close();}public static void readData() throws IOException {DataInputStream dis = new DataInputStream(new FileInputStream("data.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 writeUTFDemo() throws IOException {DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdata.txt"));dos.writeUTF("你好");dos.close();}public static void readUTFDemo() throws IOException {DataInputStream dis = new DataInputStream(new FileInputStream("utfdata.txt"));String s = dis.readUTF();System.out.println(s);dis.close();}}

五、IO流 —— ByteArrayStream 

java.lang.Object 
-java.io.InputStream 
-java.io.ByteArrayInputStream 

java.lang.Object 
-java.io.OutputStream 
-java.io.ByteArrayOutputStream 

操作字节数组
ByteArrayInputStream 与 ByteArrayOutputStream 

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

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

在操作流规律讲解时,源设备和目的设备的补充定义:
源设备:
键盘:System.in  硬盘:FileStream  内存:ArrayStream 
目的设备:
控制台:System.out  硬盘:FileStream  内存:ArrayStream

===这两个对象的出现可以用流的思想操作数组。对数组的操作只有设置值和获取值,反映到IO流中就是写和读。

ByteArrayOutputStream 类中还有一个特殊的方法: 
void writeTo(OutputStream out) :将此 byte 数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。 

操作字符数组
CharArrayReader 与 CharArrayWriter 

操作字符串
StringReader 与 StringWriter 

操作字节数组代码:
import java.io.*;class ByteArrayStream {public static void main(String[] args) throws IOException {//数据源ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".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("bos.txt"));}}

六、IO流——转换流的字符编码

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

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

常见编码表:
ASCII:美国标准信息交换码;
用一个字节的7位可以表示。

ISO8859-1:拉丁码表,欧洲码表;
用一个字节的8位表示。

GB2312:中国的中文编码表。

GBK:中国的中文编码表升级,融合了更多的中文文字符号。

Unicode:国际标准码,融合了多种文字。

UTF-8:最多用三个字节来表示一个字符。

代码:
import java.io.*;class EncodeStream{public static void main(String[] args) throws IOException{//writeText();readText();}public static void writeText() throws IOException{//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"));OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");osw.write("你好");osw.close();}public static void readText() throws IOException{//InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"UTF-8");InputStreamReader isr = new InputStreamReader(new FileInputStream("UTF.TXT"),"GBK");char[] buf = new char[10];int len = isr.read(buf);String str = new String(buf,0,len);System.out.println(str);isr.close();}}

七、字符编码

编码:字符串变成字节数组。

解码:字节数组变成字符串。

String-->byte[] : str.getBytes();
 str.getBytes(String charsetName);

byte[]-->String : new String(byte[]);
 new String(byte[], String charsetName);

代码:
import java.util.*;import java.io.*;class EncodeDemo  {public static void main(String[] args) throws IOException {String s = "你好";//编码byte[] b1 = s.getBytes();System.out.println(Arrays.toString(b1));//[-60, -29, -70, -61]//解码String s1 = new String(b1,"GBK");System.out.println("s1="+s1);//编码byte[] b2 = s.getBytes("UTF-8");System.out.println(Arrays.toString(b2));//[-28, -67, -96, -27, -91, -67]//解码String s2 = new String(b2,"UTF-8");System.out.println("s2="+s2);//解码错误时,解决办法:再编一次然后再解码(此法不适用于GBK与UTF-8之间的转换)String s3 = new String(b1,"ISO8859-1");System.out.println("s3="+s3);//s3=????byte[] b3 = s3.getBytes("ISO8859-1");//再次编码System.out.println(Arrays.toString(b3));//[-60, -29, -70, -61]String s4 = new String(b3,"GBK");//再次解码System.out.println(s4);//你好}}

八、字符编码——联通 

当我们新建一个txt文件,并在文件中存入“联通”两个字,然后保存。
第二次再次打开时,显示的不是“联通”两个子,而是两个乱码。

这是因为:
我们操作系统默认的是使用GBK的编码,所以在保存“联通”两个字时,就使用GBK编码将“联通”保存四个字节;
但是这四个字节用二进制表示出的结果符合UTF-8读取的标准;
所以,我们再次打开这个文件是,使用的是UTF-8解码;
这样就导致了编码和解码所使用的编码表不一致,所以出现了乱码。

当使用默认编码表解码时,到底使用什么编码表是根据标识头来决定的,如果符合UTF-8的标识头则使用UTF-8解码;如果不符合则使用GBK解码。


UTF-8标识头信息表:


“联通”用GBK编码后的二进制表现形式如下:
11000001
10101010
11001101
10101000
第一个字节和第二个字节符合UTF-8读取两个字节的标识头,第三个字节和第四个字节也符合UTF-8读取两个字节的标识头。
那么系统在对该文件进行解码时,就会默认的使用UTF-8解码。
最终导致了编码和解码的不一致。

解决办法:
如果只是保存这两个字,那么则在保存时选择UTF-8保存,就可以解决问题。


验证代码:

import java.util.*;class EncodeDemo2 {public static void main(String[] args) throws Exception {String s = "联通";byte[] b1 = s.getBytes("GBK");System.out.println(Arrays.toString(b1));//[-63, -86, -51, -88]for (byte b : b1){System.out.println(Integer.toBinaryString(b&255));/*11000001101010101100110110101000*/}}}

九、练习

有五个学生,每个学生有3门课的成绩;
从键盘输入以上数据(包括姓名,三门课成绩);
输入的格式:如:zhangsan,30,40,60 计算出总成绩;
并把学生的信息和计算出的总分数按高低顺序存放在磁盘文件“stud.txt”中。

步骤:
1、描述学生对象;
2、定义一个可以操作学生对象的工具类;

思路:
1、通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象;
2、使用TreeSet集合对学生进行存储;
3、将集合中的信息写入到文件中。
代码:
import java.io.*;import java.util.*;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;}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 hashCoede(){return name.hashCode()+sum*71;}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 "studentt["+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))break;String[] info = line.split(",");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 write2File(Set<Student> stus) throws IOException{BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt"));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 {Comparator<Student> cmp = Collections.reverseOrder();Set<Student> stus = StudentInfoTool.getStudents(cmp);StudentInfoTool.write2File(stus);}}
0 0