java.io包中最重要的是五个类和一个接口:File、OutputStream、InputStream、Writer、Reader和Serializable。
《开实》P399
我们可以用FileInputStream(文件字符流)或FileReader(文件字节流)来读文件,这两个类可以让我们分别以字符和字节的方式来读取文件内容,但是它们都有一个不足之处,就是只能从文件头开始读,然后读到文件结束。但是有时候我们只希望读取文件的一部分,或者是说随机的读取文件,那么我们就可以利用RandomAccessFile。RandomAccessFile提供了seek()
方法,用来定位将要读写文件的指针位置,我们也可以通过调用getFilePointer()
方法来获取当前指针的位置
其中,字节流:OutputStream、InputStream。字符流:Writer、Reader。
File file=new File("d:"+File.separator+"test.txt"); String str="Hello"; byte[] b1=str.getBytes(); byte[] b2=new byte[1024]; OutputStream out=new FileOutputStream(file); InputStream in=new FileInputStream(file); out.write(b1);//将数组b1中内容写到到输出流 int len=in.read(b2);//将输入流中内容读到到b2数组中
File file=new File("d:"+File.separator+"test.txt"); String str="Hello"; char[] c=new char[1024]; Writer w=new FileWriter(file); Reader r=new FileReader(file); w.write(str);//将字符串中内容写到到输出流 int len=r.read(c);//将输入流中内容读到到char数组中
1.Reader和Writer要解决的,最主要的问题就是国际化。原先的I/O类库只支持8位的字节流,因此不可能很好地处理16位的Unicode字符流。Unicode是国际化的字符集(更何况Java内置的char就是16位的Unicode字符),这样加了Reader和Writer之后,所有的I/O就都支持Unicode了。此外新类库的性能也比旧的好。
但是,Read和Write并不是取代InputStream和OutputStream,有时,你还必须同时使用"基于byte的类"和"基于字符的类"。为此,它还提供了两个"适配器(adapter)"类。InputStreamReader负责将InputStream转化成Reader,而OutputStreamWriter则将OutputStream转化成Writer。
2.字节流在使用时直接对文件进行读写,而字符流会用到缓冲区(内存),通过缓冲区对文件进行操作。假如在分别使用字符流和字节流写文件之后都不关闭输出流,会发现,使用字节流时,文件中已存在要写入的内容;而使用字符流时,文件中是空的,这是因为在关闭输出流时会强制输出缓冲区的内容,所以关闭后文件中才会有字符(强制输出也可以用flush())。
计算机访问外部设备,要比直接访问内存慢得多,如果我们每一次 write 方法的调用都直接写到外部设备(如直接写入硬盘文件), CPU 就要花费更多的时间等待外部设备;如果我们开辟一个内存缓冲区,程序的每一次write 方法都是写到这个内存缓冲区中,只有这个缓冲区被装满后,系统才将这个缓冲区的内容一次集中写到外部设备。使用内存缓冲区有两个方面的好处,一是有效地提高了 CPU 的使用率,二是 write 并没有马上真正写入到外设,我们还有机会回滚部分写入的数据。使用缓冲区,能提高整个计算机系统的效率,但也会降低单个程序自身的效率,由于有这么一个中间缓冲区,数据并没有马上写入到目标中去,例如在网络流中,就会造成一些滞后。
3.文本文件、内存-->字符,图片声音音频文件、硬盘、传输-->字节。所以字节流使用更为广泛
ByteArrayInputStream:向内存中写入数据。ByteArrayOutputStream:将内存中的数据读出
内存操作流一般在生成一些临时信息时使用,而如果把这些临时信息保存在文件,则执行完成后还要删除文件。
使用实例:
String str="Hello"; ByteArrayInputStream bis=null; ByteArrayOutputStream bos=null; bis=new ByteArrayInputStream(str.getBytes());<span style="white-space:pre"> </span>//向内存中输出(写入)内容 bos=new ByteArrayOutputStream(); int temp=0; while((temp=bis.read())!=-1){<span style="white-space:pre"> </span>//bis是InputStream的子类,所以可以使用read() <span style="white-space:pre"> </span>char c=(char) temp;<span style="white-space:pre"> </span>//将读取的数字变成字符 <span style="white-space:pre"> </span>bos.write(Character.toLowerCase(c));<span style="white-space:pre"> </span>//变成小写 } String s=bos.toString();<span style="white-space:pre"> </span>//取出内容,可以发现大写都变成了小写,而所有的操作都在内存中完成
DataInputStream:与平台无关的数据操作,继承自FilterInputStream类,同时实现了DataInput接口,在此接口中定义了一系列读入各种数据的方法readXXX(),如readInt()、readFloat()、readChar()。
Writer out; out=new OutputStreamWriter(FileOutputStream(file));//输出到文件,要用字节流 out.write("Hello");//内存中的数据是字符,所以用Writer注意:FileOutputStream是OutputStream的子类,但 FileWriter不是Writer的子类而是OutputStreamWriter的子类。
BufferedReader br=null; br=new BufferedReader(new InputStreamReader(System.in)); String s=null; s=br.readLine();//将System.in变成字符流放入BufferedReader之后,通过readLine()等待用户输入readLine():一次性将数据从缓冲区全部读取出来。上例中会一直等待用户输入,属于阻塞操作
Java IO 的一般使用原则 :
一、按数据来源(去向)分类:
1 、是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )
2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 )
3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )
4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )
5 、网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )
二、按是否格式化输出分:
1 、要格式化输出: PrintStream, PrintWriter
三、按是否要缓冲分:
1 、要缓冲: BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 )
四、按数据格式分:
1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类
2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类
五、按输入输出分:
1 、输入: Reader, InputStream 类型的子类
2 、输出: Writer, OutputStream 类型的子类
六、特殊需要:
1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter
2 、对象输入输出: ObjectInputStream, ObjectOutputStream
3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4 、合并输入: SequenceInputStream
5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader