Java IO

以前学习Java,一直对Java  IO 这一块没有太过于重视,现在慢慢的接触Hadoop,觉得IO这一块还是得值得好好学学的。

学习IO首先看看这张图

Java中IO分为字符流和字节流,从字面上理解,字节流就是传输字节,字符流就是传输字符(字节(Byte),字符:计算机中使用的文字和符号):

ASCII码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。

UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。

Unicode编码中,一个英文等于两个字节,一个中文(含繁体)等于两个字节。

符号:英文标点占一个字节,中文标点占两个字节。举例:英文句号“.”占1个字节的大小,中文句号“。”占2个字节的大小。

UTF-16编码中,一个英文字母字符或一个汉字字符存储都需要2个字节(Unicode扩展区的一些汉字存储需要4个字节)。

UTF-32编码中,世界上任何字符的存储都需要4个字节。

输入流和输出流

根据数据的输入、输出方向的不同对而将流分为输入流和输出流。

1) 输入流

     程序从输入流读取数据源。数据源包括外界(键盘、文件、网络…),即是将数据源读入到程序的通信通道


    

2) 输出流

   程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络)的通信通道。

    

        

采用数据流的目的就是使得输出输入独立于设备。

输入流( Input  Stream )不关心数据源来自何种设备(键盘,文件,网络)。
输出流( Output Stream )不关心数据的目的是何种设备(键盘,文件,网络)。

3)特性

  相对于程序来说,输出流是往存储介质或数据通道写入数据,而输入流是从存储介质或数据通道中读取数据,一般来说关于流的特性有下面几点:

1、先进先出,最先写入输出流的数据最先被输入流读取到。

2、顺序存取,可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile可以从文件的任意位置进行存取(输入输出)操作

3、只读或只写,每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。 

4Java IO流对象

1.输入字节流InputStream

 

IO 中输入字节流的继承图可见上图,可以看出:

1.    InputStream是所有的输入字节流的父类,它是一个抽象类。

2.    ByteArrayInputStreamStringBufferInputStream(上图的StreamBufferInputStream)FileInputStream是三种基本的介质流,它们分别从Byte数组、StringBuffer、和本地文件中读取数据。

3.    PipedInputStream是从与其它线程共用的管道中读取数据.

4.    ObjectInputStream和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。


 

InputStream中的三个基本的读方法
      abstract int read() 
:读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。
      intread(byte[]?b) 
:将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。
      intread(byte[]?b, int?off, int?len) 
:将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。

流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时。

其它方法
      long skip(long?n)
:在输入流中跳过n个字节,并返回实际跳过的字节数。
      int available() 
:返回在不发生阻塞的情况下,可读取的字节数。
      void close() 
:关闭输入流,释放和这个流相关的系统资源。
      voidmark(int?readlimit) 
:在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。
      void reset() 
:返回到上一个标记。
      booleanmarkSupported() 
:测试当前流是否支持markreset方法。如果支持,返回true,否则返回false

2.输出字节流OutputStream



IO 中输出字节流的继承图可见上图,可以看出:

1.    OutputStream是所有的输出字节流的父类,它是一个抽象类。

2.    ByteArrayOutputStreamFileOutputStream是两种基本的介质流,它们分别向Byte数组、和本地文件中写入数据。PipedOutputStream是向与其它线程共用的管道中写入数据。

3.    ObjectOutputStream和所有FilterOutputStream的子类都是装饰流。


 

outputStream中的三个基本的写方法
   abstract void write(int?b):往输出流中写入一个字节。
     void write(byte[]?b) 
:往输出流中写入数组b中的所有字节。
     void write(byte[]?b, int?off, int?len) 
:往输出流中写入数组b中从偏移量off开始的len个字节的数据。


其它方法
   void flush() 
:刷新输出流,强制缓冲区中的输出字节被写出。
     void close() 
:关闭输出流,释放和这个流相关的系统资源。
 

3.字符输入流Reader


在上面的继承关系图中可以看出:

1.    Reader是所有的输入字符流的父类,它是一个抽象类。

2.    CharReaderStringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。

3.    BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象。

4.    FilterReader是所有自定义具体装饰流的父类,其子类PushbackReaderReader对象进行装饰,会增加一个行号。

5.    InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream转变为Reader的方法。我们可以从这个类中得到一定的技巧。Reader中各个类的用途和使用方法基本和InputStream中的类使用一致。后面会有ReaderInputStream的对应关系。



主要方法:

     (1) public int read() throws IOException; //读取一个字符,返回值为读取的字符 

     (2) public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/ 
     (3) public abstract int read(char cbuf[],int off,int len) throws IOException; 
/*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/ 

 

4.字符输出流Writer


在上面的关系图中可以看出:

1.    Writer是所有的输出字符流的父类,它是一个抽象类。

2.    CharArrayWriterStringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据,

3.    BufferedWriter是一个装饰器为Writer提供缓冲功能。

4.    PrintWriterPrintStream极其类似,功能和使用也非常相似。

5.    OutputStreamWriterOutputStreamWriter转换的桥梁,它的子类FileWriter其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream极其类似.


 

主要方法:

(1)  public void write(int c) throws IOException //将整型值c的低16位写入输出流 
(2)  public void write(char cbuf[]) throws IOException //将字符数组cbuf[]写入输出流 
(3)  public abstract void write(char cbuf[],int off,int len) throws IOException //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流 
(4)  public void write(String str) throws IOException //将字符串str中的字符写入输出流 
(5)  public void write(String str,int off,int len) throws IOException //将字符串str 中从索引off开始处的len个字符写入输出流 


5.字节流的输入与输出的对应

 

图中蓝色的为主要的对应部分,红色的部分就是不对应部分。从上面的图中可以看出JavaIO中的字节流是极其对称的。存在及合理我们看看这些字节流中不太对称的几个类吧!

 

1.    LineNumberInputStream主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入流了。

2.    PushbackInputStream的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream几乎实现相近的功能。

3.    StringBufferInputStream已经被Deprecated,本身就不应该出现在InputStream部分,主要因为String应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。

4.    SequenceInputStream可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO包中去除,还完全不影响IO包的结构,却让其更纯洁”――纯洁的Decorator模式。

5.    PrintStream也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO包!System.outSystem.out就是PrintStream的实例!

字符流的输入与输出的对应


6.字符流与字节流转换

转换流的特点:

1.    其是字符流和字节流之间的桥梁

2.    可对读取到的字节数据经过指定编码转换成字符

3.    可对读取到的字符数据经过指定编码转换成字节


何时使用转换流?

1.    当字节和字符之间有转换动作时;

2.    流操作的数据需要编码或解码时。


具体的对象体现:

转换流:在IO中还存在一类是转换流,将字节流转换为字符流,同时可以将字符流转化为字节流。

 

1.    InputStreamReader:字节到字符的桥梁

2.     OutputStreamWriter:字符到字节的桥梁

 

OutputStreamWriter(OutStreamout):将字节流以字符流输出。

InputStreamReader(InputStream in):将字节流以字符流输入。

 

这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

7.字节流和字符流的区别(重点)

字节流和字符流的区别(详细可以参见http://blog.csdn.net/qq_25184739/article/details/51203733)    


         节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。


·        读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

·        处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。


结论:只要是处理纯文本数据,就优先考虑使用字符流。除此之外都使用字节流。

 

8.非流式文件类--File


  从定义看,File类是Object的直接子类,同时它继承了Comparable接口可以进行数组的排序。

File类的操作包括文件的创建、删除、重命名、得到路径、创建时间等,以下是文件操作常用的函数。

 

File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 

File类共提供了三个不同的构造函数,以不同的参数形式灵活地接收文件和目录名信息。

构造函数:
1)File (String   pathname)   
     例:File  f1=new File("FileTest1.txt"); //创建文件对象f1,f1所指的文件是在当前目录下创建的FileTest1.txt
2)File (String  parent  ,  String child)
     例:File f2=new  File(“D:\\dir1","FileTest2.txt") ;//  注意:D:\\dir1目录事先必须存在,否则异常
3)File (File    parent  , String child)
     例:File  f4=new File("\\dir3");
          File  f5=new File(f4,"FileTest5.txt");  //在如果 \\dir3目录不存在使用f4.mkdir()先创建

        一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。    
       1)public boolean exists( ) 判断文件或目录是否存在
       2)public boolean isFile( ) 判断是文件还是目录 
       3)public boolean isDirectory( ) 判断是文件还是目录
       4)public String getName( ) 返回文件名或目录名
       5)public String getPath( ) 返回文件或目录的路径。
       6)public long length( ) 获取文件的长度 
       7)public String[ ] list ( ) 将目录中所有文件名保存在字符串数组中返回。 
       File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:
       1) public boolean renameTo( File newFile );    重命名文件
       2) public void delete( );   删除文件
       3)  public boolean mkdir( ); 创建目录

例子:

[java]  view plain  copy
  1. 1.  public class FileDemo1 {     
  2. 2.      public static void main(String[] args) {    
  3. 3.          File file = new File("D:" + File.separator + "test.txt");     
  4. 4.          if (file.exists()) {     
  5. 5.              file.delete();    
  6. 6.          } else {     
  7. 7.              try {     
  8. 8.                  file.createNewFile();    
  9. 9.              } catch (IOException e) {    
  10. 10.                 // TODO Auto-generated catch block     
  11. 11.                 e.printStackTrace();    
  12. 12.             }    
  13. 13.         }    
  14. 14.     }    
  15. 15. }    

9.RandomAccessFile


该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。该对象特点:

 

1.    该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。

2.    该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)

 

注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。


10System类对IO的支持

 针对一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,分别是:

·        System.in(标准输入),通常代表键盘输入。

·        System.out(标准输出):通常写往显示器。

·        System.err(标准错误输出):通常写往显示器。

 标准I/O
      Java程序可通过命令行参数与外界进行简短的信息交换,同时,也规定了与标准输入、输出设备,如键盘、显示器进行信息交换的方式。而通过文件可以与外界进行任意数据形式的信息交换。


1. 命令行参数

[java]  view plain  copy
  1. public class TestArgs {    
  2.     public static void main(String[] args) {    
  3.         for (int i = 0; i < args.length; i++) {    
  4.             System.out.println("args[" + i + "] is <" + args[i] + ">");    
  5.         }    
  6.     }    
  7. }    


运行命令:java Java C VB


运行结果:

[java]  view plain  copy
  1. args[0] is <Java>  
  2.   
  3.   
  4. args[1] is <C>  
  5.   
  6.   
  7. args[2] is <VB>  

2. 标准输入,输出数据流


java系统自带的标准数据流:java.lang.System:

[java]  view plain  copy
  1. java.lang.System     
  2. public final class System  extends Object{     
  3.    static  PrintStream  err;//标准错误流(输出)    
  4.    static  InputStream  in;//标准输入(键盘输入流)    
  5.    static  PrintStream  out;//标准输出流(显示器输出流)    
  6. }    

注意:
(1)System类不能创建对象,只能直接使用它的三个静态成员。
(2)每当main方法被执行时,就自动生成上述三个对象。

1) 标准输出流 System.out

   System.out向标准输出设备输出数据,其数据类型为PrintStream。方法:

      Void print(参数)
      Void println(参数)
2)标准输入流 System.in

    System.in读取标准输入设备数据(从标准输入获取数据,一般是键盘),其数 据类型为InputStream。方法:

        int read()  //返回ASCII码。若,返回值=-1,说明没有读取到任何字节读取工作结束。
        int read(byte[] b)//读入多个字节到缓冲区b中返回值是读入的字节数
例如:

[java]  view plain  copy
  1. import java.io.*;    
  2. public class StandardInputOutput {    
  3.     public static void main(String args[]) {    
  4.         int b;    
  5.         try {    
  6.             System.out.println("please Input:");    
  7.             while ((b = System.in.read()) != -1) {    
  8.                 System.out.print((char) b);    
  9.             }    
  10.         } catch (IOException e) {    
  11.             System.out.println(e.toString());    
  12.         }    
  13.     }    
  14. }    
等待键盘输入,键盘输入什么,就打印出什么:

3)标准错误流

   System.err输出标准错误,其数据类型为PrintStream。可查阅API获得详细说明。

    标准输出通过System.out调用println方法输出参数并换行,而print方法输出参数但不换行。println或print方法都通 过重载实现了输出基本数据类型的多个方法,包括输出参数类型为boolean、char、int、long、float和double。同时,也重载实现 了输出参数类型为char[]、String和Object的方法。其中,print(Object)和println(Object)方法在运行时将调 用参数Object的toString方法。
[java]  view plain  copy
  1. import java.io.BufferedReader;    
  2. import java.io.IOException;    
  3. import java.io.InputStreamReader;    
  4.     
  5. public class StandardInputOutput {    
  6.     public static void main(String args[]) {    
  7.         String s;    
  8.         // 创建缓冲区阅读器从键盘逐行读入数据    
  9.         InputStreamReader ir = new InputStreamReader(System.in);    
  10.         BufferedReader in = new BufferedReader(ir);    
  11.         System.out.println("Unix系统: ctrl-d 或 ctrl-c 退出"    
  12.                 + "\nWindows系统: ctrl-z 退出");    
  13.         try {    
  14.             // 读一行数据,并标准输出至显示器    
  15.             s = in.readLine();    
  16.             // readLine()方法运行时若发生I/O错误,将抛出IOException异常    
  17.             while (s != null) {    
  18.                 System.out.println("Read: " + s);    
  19.                 s = in.readLine();    
  20.             }    
  21.             // 关闭缓冲阅读器    
  22.             in.close();    
  23.         } catch (IOException e) { // Catch any IO exceptions.    
  24.             e.printStackTrace();    
  25.         }    
  26.     }    
  27. }    

Java语言中使用字节流和字符流的步骤基本相同,以输入流为例,首先创建一个与数据源相关的流对象,然后利用流对象的方法从流输入数据,最后执行close()方法关闭流。


附加:

 IOException异常类的子类
1.public class  EOFException :   非正常到达文件尾或输入流尾时,抛出这种类型的异常。    

      2.public class FileNotFoundException:   当文件找不到时,抛出的异常。

      3.public class InterruptedIOException: 当I/O操作被中断时,抛出这种类型的异常。

参考了大量好的博客文章,总结起来留作学习参考。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值