《Thinking in java》-学习笔记(10)

第10章 Java IO 系统

1.输入和输出

输入有关的所有类都从InputStream继承,与输出有关的所有类都从OutputStream继承。

2.增添属性和有用的接口

利用层次化对象动态和透明地添加单个对象的能力的做法叫做“装饰器”方案。

3.本身的缺陷:RandomAccessFile

RandomAccessFile不属于InputStream或者OutputStream分层结构的一部分。只能针对

文件才能操作,不能针对数据流操作。可以在一个文件里向前或向后移动。

4.目录列表器

public interface FilenameFilter {
boolean accept(文件目录, 字串名);
}

通过实现这个接口,可以对文件名进行过滤。下面用的是匿名内部类来实现这个接口。

package exam;
import java.io.*;
public class DirList3 {
	public static void main(final String[] args){
		try{
			File path=new File(".");
			String[] list;
			if(args.length==-0)
				list=path.list();
			else
				list=path.list(
						new FilenameFilter(){
							public boolean accept(File dir,String n){
								String f=new File(n).getName();
								return f.indexOf(args[0])!=-1;
							}
						}
			    );
			for(int i=0;i<list.length;i++)
				System.out.println(list[i]);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

5.IO流的典型应用

package c10;
import java.io.*;
import oypj.tools.*;
public class IOStreamDemo {
	public static void main(String[] args){
		try{
			//1.Buffered input file
			DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream(args[0])));
			String s,s2=new String();
			while((s=in.readLine())!=null)
				s2+=s+"\n";
			in.close();
			//2.Input from memory
			StringBufferInputStream in2=new StringBufferInputStream(s2);
			int c;
			while((c=in2.read())!=-1)
				System.out.print((char)c);
			//3.Formatted memory input
			try{
				DataInputStream in3=new DataInputStream(new StringBufferInputStream(s2));
				while(true)
					System.out.print((char)in3.readByte());
			}catch(EOFException e){
				P.rintln("End of stream encountered");
			}
			//4.Line numbering & file output
			try{
				LineNumberInputStream li=new LineNumberInputStream(new StringBufferInputStream(s2));
				DataInputStream in4=new DataInputStream(li);
				PrintStream out1=new PrintStream(new BufferedOutputStream(new FileOutputStream("IOEemo.out")));
				while((s=in4.readLine())!=null)
					out1.println("Line"+li.getLineNumber()+s);
				out1.close();
			}catch(EOFException e){
				P.rintln("End of stream encountered");
			}
			//5.Storing &recovering data
			try{
				DataOutputStream out2=new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
				out2.writeBytes("Here's the value of pi:\n");
				out2.writeDouble(3.1415926);
				out2.close();
				DataInputStream in5=new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
				System.out.println(in5.readLine());
				System.out.println(in5.readDouble()); 
			}catch(EOFException e){
				System.out.println("End of stream encountered");
			}
			//6.Reading/Writing random access files
			RandomAccessFile rf=new RandomAccessFile("rtest.dat","rw");
			for(int i=0;i<10;i++)
				rf.writeDouble(i*1.414);
			rf.close();
			rf=new RandomAccessFile("rtest.dat","rw");
			rf.seek(5*8);
			rf.writeDouble(47.0001);
			rf.close();
			rf=new RandomAccessFile("rtest.dat","r");
			for(int i=0;i<10;i++)
				System.out.println("value"+i+":"+rf.readDouble());
			rf.close();
			
			//7.File inout shorthand
			InFile in6=new InFile(args[0]);
			String s3=new String();
			System.out.println("First line in file:"+in6.readLine());
			in6.close();
			//8.Formatted file output shorthand
			PrintFile out3=new PrintFile("Data2.txt");
			out3.print("Test of PrintFile");
			out3.close();
			//9.Data file output shorthand
			OutFile out4=new OutFile("Data.txt");
			out4.writeBytes("Test of outDataFile\n\r");
			out4.writeChars("Test of outDataFile\n\r");
			out4.close();
		}catch(FileNotFoundException e){
			System.out.println("File Not Found:"+args[0]);
		}catch(IOException e){
			System.out.println("IO Exception");
		}
	}
}

6.从标准的输入中读取数据

System.out和System.err已预封装成一个PrintStream对象,System.in是一个原始的InputStream。

能直接使用System.out和System.err,但是System.in要先封装,才能从中读取数据。例如:

package c10;
import java.io.*;
public class Echo {
	public static void main(String[] args){
		DataInputStream in=new DataInputStream(new BufferedInputStream(System.in));
		String s;
		try{
			while((s=in.readLine()).length()!=0)
				System.out.println(s);
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}

7.StreamTokenizer和StringTokenizer

StreamTokenizer用于将任何InputStream分割为一系列“记号”(Token),可以用来计算各个单

词在文本文件中重复出现的次数。

StringTokenizer的作用是每次返回字串内的一个记号,字串“Where is my cat?” 的记号分别是

“Where”、“is”、“my”、“cat?”

8.Java1.1的IO流

下面的例子使用了新的IO流

package c10;
import java.io.*;
public class NewIODemo {
	 public static void main(String[] args){
		 try{
			 //1.Reading input by lines:
			 BufferedReader in=new BufferedReader(new FileReader(args[0]));
			 String s,s2=new String();
			 while((s=in.readLine())!=null)
				 s2+=s+"\n";
			 in.close();
			 //1b Reading standard input:
			 BufferedReader stdin=new BufferedReader(new InputStreamReader(System.in));
			 System.out.print("Enter a line");
			 System.out.println(stdin.readLine());
			 
			 //2.Input from memory
			 StringReader in2=new StringReader(s2);
			 int c;
			 while((c=in2.read())!=-1)
				 System.out.println((char)c);
			 //3.Formatted memory input
			 try{
				 DataInputStream in3=new DataInputStream(new StringBufferInputStream(s2));
				 while(true)
					 System.out.print((char)in3.readByte());
			 }catch(EOFException e){
				 System.out.println("End of stream");
			 }
			 //4.Line numbering &file output
			 try{
				LineNumberReader li=new LineNumberReader(new StringReader(s2));
				BufferedReader in4=new BufferedReader(li);
				PrintWriter out1=new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
				while((s=in4.readLine())!=null)
					out1.println("Line"+li.getLineNumber()+s);
				out1.close();
			 }catch(EOFException e){
				 System.out.println("End of stream");
			 }
			 //5.Storing &recovering data
			 try{
				 DataOutputStream out2=new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.txt")));
				 out2.writeDouble(3.14159);
				 out2.writeBytes("That was pi");
				 out2.close();
				 DataInputStream in5=new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
				 BufferedReader in5br=new BufferedReader(new InputStreamReader(in5));
				 System.out.println(in5.readDouble());
				 System.out.println(in5br.readLine());
			 }catch(EOFException e){
				 System.out.println("End of stream");
			 }
			 
		 }catch(FileNotFoundException e){
			 System.out.println("File Not Found:"+args[1]);
		 }catch(IOException e){
			 System.out.println("IO Exception");
		 }
	 }
}

下面这个例子展示了Java 1.1本身的一个错误。在writeBytes()调用后,后面写入的其他数据都不能够

恢复。

package c10;
import java.io.*;
public class IOBug {
	public static void main(String[] args) throws Exception{
			DataOutputStream out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
			out.writeDouble(3.14159);
			out.writeBytes("That was the value of pi\n");
			out.writeBytes("That is pi/2:\n");
			out.writeDouble(3.14159/2);
			out.close();
			DataInputStream in=new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
			BufferedReader inbr=new BufferedReader(new InputStreamReader(in));
			System.out.println(in.readDouble());
			System.out.println(inbr.readLine());
			System.out.println(inbr.readLine());
			System.out.println(in.readDouble());

	}
}

输出结果: 3.14159/2的值没有恢复出来 

9. 重导向标准IO

setIn(InputStream)、setOut(PrintStream)、setErr(PrintStream),下面是使用的例子

package c10;
import java.io.*;
public class Redirecting {
	public static void main(String[] args){
		try{
			BufferedInputStream in=new BufferedInputStream(new FileInputStream("F:/javatest/exam/src/c10/Redirecting.java"));
			PrintStream out=new PrintStream(new BufferedOutputStream(new FileOutputStream("test.txt")));
			System.setIn(in);
			System.setOut(out);
			System.setErr(out);
			BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
			String s; 
			while((s=br.readLine())!=null)
				System.out.println(s);
			out.close();
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}

10.压缩

GZIP接口,适合只有单个数据流。Zip可以保存多个文件,对于要加入压缩档的每一个文件,

都必须调用putNextEntry(),对应的有getNextEntry()。

只需要将输出流封装到一个GZIPOutputStream或者ZipOutputStream内,将输入流封装到

GZIPInputStream或者ZipInputStream内即可,剩余的全部操作就是标准的io读写。

可以用ZipFile对象读取文件,该对象有entries()方法,可以为ZipEntry返回一个Enumeration.

Checksum:Adler32(速度快一些)和CRC32(慢一些,但更准确)。

ZipEntry只支持CRC接口

11.java归档(jar)实用程序

作用是将一系列文件合并到单个压缩文件里。JAR文件由一系列采用Zip压缩格式的文件构成,同时

还有一张“详情单”。

12.对象序列化

面向实现Serializeble接口的对象,可将它们转换成一系列字节,可在以后完全恢复回原来的样子。

首先要创建某些OutputStream对象,然后将其封装到ObjectOutputStream对象内,然后再调用writeObject()

就可以完成对象的序列化。相反的过程是将一个InputStream封装到ObjectInputStream内,然后调用readObject()

恢复了一个序列化的对象后,如果想对其做更多的事情,必须保证JVM能在本地类路径或者因特网的其他地方找到

相关的.class文件。

13.序列化的控制

通过实现Externalization接口,便可以控制序列化的具体过程。这个接口中有writeExternal()和readExternal()方法。

Serializable的对象完全以它保存下来的二进制位为基础恢复,不存在构建器的调用。而Externalizable对象,所有普通

的默认构建器会执行,然后调用readExternal(),所以默认构建器要设置为public。

transient(临时)关键字 ,可以用来逐个字段地关闭序列化。

Externalizable的替代方法:实现Serializable接口,并添加writeObject()和readObject()的方法。可以

调用defaultWriteObject(),从而采取默认的writeObject()行动,相反地可以调用defaultReadObject()。

private void
writeObject(ObjectOutputStream stream)
throws IOException;
private void
readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException

想序列化static值,必须亲自动手,自动序列化的时候会出错。

总结

这一章给我的感觉就是Java的输入输出非常复杂,但是采用了装饰器方案,确实可以灵活地使用各种操作。

对象的序列化给我们保存和恢复对象提供了方便,而且与平台无关。还提供了压缩类,这是我之前没有了解过的。

猜你喜欢

转载自blog.csdn.net/a614528195/article/details/81358432