IO流5(IO包中的其他类,ObjectStream,管道流,RandomAccessFile,DataStream,ByteArrayStream)
打印流:PrintWriter和PrintStream
该流提供了打印方法,可以将各种数据类型的数据都原样打印出来。
PrintStream的构造函数可以接收的参数类型为:
<1>File对象 <2>字符串路径 <3>字节输出流OutputStream
PrintWriter的构造函数可以接收的参数类型为:
<1>File对象 <2>字符串路径 <3>字节输出流OutputStream <4>字符输出流Writer
PrintWriter(OutputStream out,boolean autoFlush); 是否自动刷新,true,则println,printf,format方法自动刷新缓冲区
1: public static void main(String[] args)throws IOException
2: {
3: BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
4:
5: PrintWriter out=new PrintWriter(System.out,true);
6:
7: String line=null;
8: while((line=bufr.readLine())!=null)
9: {
10: if("over".equals(line))
11: break;
12: out.println(line.toUpperCase());
13: }
14:
15: out.close();
16: bufr.close();
17: }
合并流:SequenceInputStream
表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流末尾为止。
构造方法为:SequenceInputStream(InputStream s1,InputStream s2)按照顺序读取
SequenceInputStream(Enumeration<? extends InputStream> e)
1:
2: Vector<FileInputStream> v=new Vector<FileInputStream>();
3: v.add(new FileInputStream("c:\\1.txt"));
4: v.add(new FileInputStream("c:\\2.txt"));
5: v.add(new FileInputStream("c:\\3.txt"));
6:
7: Enumeration<FileInputStream> en=v.elements();
8: //将多个流对象合成了一个流对象
9: SequenceInputStream sis=new SequenceInputStream(en);
10:
11: /*
12: elements()方法,返回此向量的组件的枚举,返回Enumeration对象将生成此向量中的所有项
13:
14: Enumeration接口,实现Enumeration接口的对象,它生成一系列元素,一次只生成一个
15:
16: Enumeration有两个方法:1.hasMoreElements()判断此枚举中是否包含更多的元素
17: 2.nextElement()返回此枚举中的下一个元素
18:
19: */
20:
练习:
1: import java.io.*;
2: import java.util.*;
3:
4:
5: class FileDemo
6: {
7: public static void main(String[] args) throws IOException
8: {
9: //splitFile();
10:
11: addFile();
12: }
13:
14: public static void splitFile()throws IOException//切割文件
15: {
16: FileInputStream fis=new FileInputStream("IMG_0696.jpg");
17:
18: FileOutputStream fos=null;
19:
20: byte[] buf=new byte[30*1024];
21: int len=0;
22: int count=0;
23: while((len=fis.read(buf))!=-1)
24: {
25: fos=new FileOutputStream("D:\\j\\day20\\splitfiles\\"+(count++)+".part");
26: fos.write(buf,0,len);
27: fos.close();
28: }
29: fis.close();
30: }
31:
32: public static void addFile()throws IOException//合并文件
33: {
34: ArrayList<FileInputStream> al=new ArrayList<FileInputStream>();
35:
36: for(int x=0;x<3;x++)
37: {
38: al.add(new FileInputStream("D:\\j\\day20\\splitfiles\\"+x+".part"));
39: }
40:
41: //内部类访问定义在类中的局部变量时,只能访问该局部被final修饰的局部变量
42: final Iterator<FileInputStream> it=al.iterator();
43:
44: Enumeration<FileInputStream> en=new Enumeration<FileInputStream>()
45: {
46: //使用Iterator的方法来重写Enumeration的方法。
47: public boolean hasMoreElements()
48: {
49: return it.hasNext();
50: }
51:
52: public FileInputStream nextElement()
53: {
54: return it.next();
55: }
56: };
57:
58: SequenceInputStream sis=new SequenceInputStream(en);
59:
60: FileOutputStream fos=new FileOutputStream("abc.bmp");
61:
62: byte[] buf=new byte[30];
63:
64: int len=0;
65: while((len=sis.read(buf))!=-1)
66: {
67: fos.write(buf,0,len);
68: }
69:
70: fos.close();
71: sis.close();
72: }
73:
74: }
75:
ObjectStream:
直接操作对象的流,对象被存储在堆内存中,程序结束后,堆内存就会被释放,对象也就不存在了。如果存放起来,即使程序结束,对象依旧存在。
类通过实现java.io.Serializable接口以启用其序列化功能,可序列化类的所有子类本身都是可序列化的。
Serializable接口没有实际的方法,它属于标记接口。
1: import java.io.*;
2:
3: //必须实现Serializable接口,才可以被序列化
4: class Person implements Serializable
5: {
6: private String name;
7: private int age;
8:
9: Person(String name,int age)
10: {
11: this.name=name;
12: this.age=age;
13: }
14:
15: public String toString()
16: {
17: return name+"-----age is----"+age;
18: }
19: }
20:
1: import java.io.*;
2:
3: class ObjectStreamDemo
4: {
5: public static void main(String[] args) throws Exception
6: {
7: //writeObj();
8: readObj();
9: }
10:
11:
12: public static void writeObj()throws Exception
13: {
14: ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("obj.txt"));
15: //将一个Person对象存储到目标文件中去
16: oos.writeObject(new Person("zhangsan",29));
17: oos.close();
18: }
19:
20: public static void readObj()throws Exception
21: {
22: ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.txt"));
23: Person p=(Person)ois.readObject();
24: System.out.println(p);
25:
26: ois.close();
27: }
28:
29: }
30:
显示声明SerialVersionVID:
public static final long serialVersionVID=42L;即给类固定了标识,这样即使类发生了一些改变,依旧可以操作之前类序列化的对象。
静态是不可以被序列化的,因为静态变量存放在方法区中,如果将age或者name修饰成transient,例如transient int age;此时,虽然age存在在堆内存中,依旧不会被序列化,不会被存放在文件中。
管道流(PipedInputStream,PipedOutputStream):
输入输出可以直接进行连接,通过结合线程使用。其他流通过一个中转数组来进行续写。
PipedInputStream:管道输入流应该连接到管道输出流,管道输入流提供要写入管道输出流的所有数据字节,通常数据由某个线程从PipedInputStream对象读取,并且由其他线程将其写入到相应的PipedOutputStream中。
PipedInputStream和PipedOutputStream连接的方法:
<1>如果PipedInputStream()构造函数是空参数的,那么使用connect(PipedOutputStream src)方法,将其连接
<2>直接将PipedOutputStream作为参数传递给PipedInputStream的构造函数,即PipedInputStream(PipedOutputStream src)
1: import java.io.*;
2:
3: class Read implements Runnable
4: {
5: private PipedInputStream in;
6: Read(PipedInputStream in)
7: {
8: this.in=in;
9: }
10:
11: public void run()
12: {
13: try
14: {
15: byte[] buf=new byte[1024];
16: System.out.println("读取数据前,正在阻塞~");
17: int len=in.read(buf);
18: System.out.println("读取数据后,阻塞结束~");
19: String s=new String(buf,0,len);
20:
21: System.out.println(s);
22: in.close();
23:
24: }
25: catch (Exception e)
26: {
27: throw new RuntimeException("管道流读取失败~");
28: }
29: }
30:
31: }
32:
33: class Write implements Runnable
34: {
35: private PipedOutputStream out;
36: Write(PipedOutputStream out)
37: {
38: this.out=out;
39: }
40:
41: public void run()
42: {
43: try
44: {
45: System.out.println("等待六秒后,开始写入数据");
46: Thread.sleep(6000);
47:
48: out.write("piped lai la".getBytes());
49: out.close();
50:
51: }
52: catch (Exception e)
53: {
54: throw new RuntimeException("管道流写入失败");
55: }
56: }
57: }
58: /*
59: 如果读取先抢到CPU资源,此时,没有数据供读取,所以会先等待。然后写入抢到了资源,将数据写入,
60: 释放资源。然后将读取线程唤醒,进行读取。
61: */
62:
63: class PipedStreamDemo
64: {
65: public static void main(String[] args) throws IOException
66: {
67: PipedInputStream in=new PipedInputStream();
68: PipedOutputStream out=new PipedOutputStream();
69:
70: in.connect(out);
71:
72: Read r=new Read(in);
73: Write w=new Write(out);
74:
75: new Thread(r).start();
76: new Thread(w).start();
77: }
78: }
79:
RandomAccessFile:该类只能用来操作文件
此类的实例支持对随机访问文件的读取与写入,该类直接继承自Object。但是它是IO包中的成员。因为它具备读写功能,它内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和字节输出流。该类操作文件还有模式(mode),mode参数 指定用以打开文件的访问模式:
r----只读,如果调用write方法,将导致抛出IOException
rw-----读写,如果没有该文件,则进行创建
可以读基本数据类型,并且具备readLine()方法。
1: public static void write_File()throws IOException
2: {
3: RandomAccessFile raf=new RandomAccessFile("ran.txt","rw");
4: raf.write("李四".getBytes());
5: //存入文件中的为a,因为文本文件为字符流的,此时存入的97为字节流,会根据编码表将97转为字符a
6: raf.write(97);
7:
8: //存在文件中的为﹁符号。因为write方法一次只写进去8个二进制位,258的二进制表示形式为:1 0000 0010
9: //只读后八位为:0000 0010 ,根据编码表查表得上述符号
10: raf.write(258);
11:
12: //writeInt方法按四个字节将int写入该文件,先写入高字节。
13: raf.writeInt(97);//存入文件中为——————a,a前面为三个空格。
14:
15: raf.close();
16: }
1: public static void readFile()throws IOException
2: {
3: RandomAccessFile raf=new RandomAccessFile("ran.txt","r");
4: byte[] buf=new byte[4];
5: raf.read(buf);
6: String name=new String(buf);
7:
8: int age=raf.readInt();
9:
10: System.out.println("name="+name);
11: System.out.println("age="+age);
12:
13: raf.close();
14: }
15: /*
16: ran.txt文件中存储的为李四 a王五 c
17: 上述readFile()方法的打印结果为李四97
18: */
19:
如果希望打印出来王五的name和age,应该怎么做呢?
DataInputStream和DataOutputStream用来操作基本数据类型:
1:
2: public static void writeUTFDemo()throws IOException
3: {
4: DataOutputStream dos=new DataOutputStream(new FileOutputStream("utfdata.txt"));
5:
6: //wirteUTF(String str)使用modified UTF-8编码以与机器无关的方式将一个字符串写入文件
7: dos.writeUTF("你好");
8: dos.close();
9: }
ByteArrayStream,用于操作字节数组:
ByteArrayInputStream包含一个内部缓冲区,该缓冲区包含从流中读取的字节。关闭ByteArrayInputStream无效。此类中的方法在关闭此流后,仍可被调用,而且不会产生任何IOException。构造时需要接收一个数据源,而且该数据源为一个字节数组。
ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个byte数组,缓冲区会随着数据的不断写入而自动增长,可以使用toByteArray()和toString()获取数据。同样,关闭ByteArrayOutputStream无效。构造时不用定义数据的目的,因为该对象的内部已经封装了一个可变长度的字节数组。
1:
2: public static void main(String[] args)
3: {
4: ByteArrayInputStream bis=new ByteArrayInputStream("ABCDEFG".getBytes());
5: ByteArrayOutputStream bos=new ByteArrayOutputStream();
6:
7: int by=0;
8: while((by=bis.read())!=-1)
9: {
10: bos.write(by);
11: }
12:
13: System.out.println(bos.size());
14: System.out.println(bos.toString());
15:
16: }
17:
源设备:键盘 System.in 硬盘FileStream 内存ArrayStream目的设备:控制台System.out 硬盘FileStream 内存ArrayStreamByteArrayOutputStream有一个方法,writeTo(OutputStream out),将此Byte数组输出流中的全部内容写入到指定的输出流参数中去bos.writeTo(new FileOutputStream(“a.txt”));将内容写入到a.txt文件中去
字符编码:
ASCII:美国标准信息交换码,用一个字节的7位来表示
ISO8859-1:拉丁码表。欧洲码表,用一个字节的八位来表示
GBK:中文编码表,用两个字节来表示一个中文文字符号
unicode:国际标准码,融合了多种文字,所有的文字都用两个字节来表示
UTF-8:最多用三个字节来表示一个字符
编码:字符串--------字节数组。str.getBytes(String charset)按照指定的编码表
解码:字节数组---------字符串。new String(byte[], charsetName);
UTF-8的标识码:单个字节以0开头
两个字节110X XXXX 10XX XXXX
三个字节1110 XXXX 10XX XXXX 10XX XXXX
1: public static void main(String[] args)
2: {
3: String s="联通";
4: byte[] by=s.getBytes("GBK");
5: for(byte b:by)
6: {
7: System.out.println(b);
8: }
9: }
10:
11: /*
12: 得到的编码为:-63, -86, -51, -88
13: 化为二进制位1100 0001 1010 1010 1100 1101 1010 1000
14: 如果使用UTF-8进行解码,会出现问题,但是符合UTF-8的规律,所以文本文档会使用UTF-8来进行解码,会出现问题。
15:
16: */
1: /*
2: 练习:有五个学生,每个学生有三门功课的成绩,从键盘上输入以上数据,输入的格式为zhangsan,30,40,60
3: 并且计算出来总成绩,并将学生的信息和计算出来的总成绩按照总成绩的高低顺序存放在文件中。
4: */
5:
6: import java.io.*;
7: import java.util.*;
8:
9: //首先定义一个Person类用来描述学生以及其各科分数,并且让它具备比较性,如果姓名和总分一样的话,就视为同一个学生
10: class Person implements Comparable
11: {
12: private String name;
13: private String chinese;
14: private String math;
15: private String english;
16: private int count;
17:
18: Person(String name,String chinese,String math,String english)
19: {
20: this.name=name;
21: this.chinese=chinese;
22: this.math=math;
23: this.english=english;
24: this.count=Integer.parseInt(chinese)+Integer.parseInt(math)+Integer.parseInt(english);
25: }
26:
27: public int getCount()
28: {
29: return count;
30: }
31:
32: public String getName()
33: {
34: return name;
35: }
36:
37: public String getChinese()
38: {
39: return chinese;
40: }
41:
42: public String getMath()
43: {
44: return math;
45: }
46:
47: public String getEnglish()
48: {
49: return english;
50: }
51:
52: public int compareTo(Object obj)
53: {
54: if(!(obj instanceof Person))
55: System.out.println("发生错误~~");
56: Person p=(Person)obj;
57:
58: if(this.count<p.count)
59: return 1;
60: else if(this.count==p.count)
61: {
62: return this.name.compareTo(p.name);
63: }else return -1;
64: }
65:
66: }
67:
68:
69: class PersonStreamDemo
70: {
71: public static void main(String[] args) throws IOException
72: {
73: InputStreamReader isr=new InputStreamReader(System.in);
74: BufferedReader bufr=new BufferedReader(isr);
75:
76: BufferedWriter bufw=new BufferedWriter(new FileWriter("student.txt"));
77:
78: TreeSet<Person> ts=new TreeSet<Person>();
79:
80: String line=null;
81: //逐行读取信息,然后按照,分开读取到的信息,并且封装到对象中去,同时将对象存储在TreeSet中去,
82: //通过总成绩的高低,进行总分的排列
83: while((line=bufr.readLine())!=null)
84: {
85: if("over".equals(line))
86: break;
87: String[] s=line.split(",");
88: Person p=new Person(s[0],s[1],s[2],s[3]);
89: ts.add(p);
90: }
91:
92: Iterator it=ts.iterator();
93: while(it.hasNext())
94: {
95: Object obj=it.next();
96: Person per=(Person)obj;
97: bufw.write("name="+per.getName()+" chinese="+per.getChinese()+" math="+per.getMath()+" english="+per.getEnglish()+" count"+per.getCount());
98: bufw.newLine();
99: bufw.flush();
100: }
101:
102: bufw.close();
103: bufr.close();
104: }
105: }
106: