IO(一)

IO(Input Output)流概述:

IO流特点:

  • IO流(数据流)用来处理设备间的数据传输。
  • Java对数据的操作是通过流的方式。
  • Java用于操作流的对象都在IO包中。
  • 流按操作数据分为两种:字节流和字符流。
  • 流按流向分为:输入流和输出流。

IO流的抽象基流:

字节流的抽象基流:InputStream和OutputStream

字符流的抽象基流:Reader和Writer


此四个类派生出来的子类名称都是以父类名作为子类名的后缀,以前缀为其功能;

如InputStream子类FileInputStream

字符流:

既然IO流是用于操作数据的,那么数据的最常见体现形式是文件。

/* 
 
需求:在硬盘上,创建一个文件,并写入文字数据。 
 
找到一个专门用于操作文件的Writer子类对象。FileWriter  后缀名是父类名,前缀名是该流对象的功能 
*/  
import java.io.*;  
class FileWriteDemo  
{  
   public static void main(String []args) throws IOException  
   {  
     //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件  
     //而且该文件会被创建到指定的目录下。如果该目录下已有同名文件,将被覆盖  
     //其实该步就是在明确数据要存放的目的地。  
     FileWriter fw =new FileWriter("C:/demo.txt");  
      
     fw.write("abcde");  
     //刷新流对象中缓冲中的数据  
     //将数据刷到目的地中  
     fw.flush();  
      
     //关闭流资源,但是关闭之前会刷新一次缓冲中的数据  
     //讲数据刷到目的地中,flush刷新后,流可以继续使用,close刷新后,会将流关闭。  
     fw.close();  
   }  
     
}  

IO异常的处理方式:

import java.io.*;  
  
class FileWriteDemo2  
{  
   public static void main(String []args)  
   {  
   //在外面建立引用,在try内初始化  
   FileWriter fw=null;  
   try{  
     
       //try里面定义的变量在外面访问不到  
       //FileWriter fw=new FileWriter("demo.txt");  
         
       //向磁盘中写入文件  
       fw=new FileWriter("c:\\demo.txt");  
       //向文件中写入内容  
       fw.write("abcdefg");  
      
      
   }catch(IOException e)  
   {  
     System.out.println("catch:"+e.toString());  
     //finally内关闭资源,一定会被执行的代码往里面放入  
   }finally{  
     
         try{  
         // 对流对象进行判断,如果不为空就关闭,为空时不能调用close()
          if(fw!=null)  
          {  
             fw.close();  //流必须关闭,因此写入到finally中
          }  
                 
                 
          }catch(IOException e)  
          {  
             System.out.println(e.toString());  
          }  
          
   }  
      
   }     
}  

文件的续写:

 //传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据的续写  
  fw=new FileWriter("c:\\demo.txt",true);  

文本文件读取方式1:

/*第一种方式:一次读取一个字符*/import java.io.*;  
  
class FileReaderDemo  
{  
   public static void main(String []args) throws IOException  
   {   
       //创建一个文件读流对象,和指定名称的文件相关联  
       //要保证该文件时已经存在的,如果不存在,会发生异常FileNotFoundException  
       FileReader fr=new FileReader("C:/demo.txt");  
       //调用读取流对象的read方法  
       //raed()方法一次读入一个字符,而且会自动往下读。  
       /* 
       int ch=fr.read(); 
        
       System.out.println("ch="+(char)ch); 
        
       int ch1=fr.read(); 
        
       System.out.println("ch="+(char)ch1); 
        
       */  
       //read方法作为整数读取的字符,范围在0到65535之间,如果达到流的末尾,则返回-1  
         
       /* 
       while(true) 
       { 
          int ch=fr.read(); 
          if(ch==-1) 
             break; 
          System.out.println("ch="+(char)ch); 
       } 
       fr.close(); 
       */  
       int ch=0;  
         
       while((ch=fr.read())!=-1)  
       {  
         System.out.println("ch="+(char)ch);   
       }  
   }  
}  

文本文件读取方式2:

/* 
第二种方式,通过字符数组进行读取。 
 
这种读取方式最有效 
*/  
  
import java.io.*;  
  
class FileReaderDemo2  
{  
   public static void main(String []args) throws IOException  
   {   
     FileReader fr=new FileReader("C:/demo.txt");  
       
     //定义一个字符数组。用于存储读到字符  
     //该read(char[])返回的是读到的字符个数  
       
     char [] buf=new char[1024];  
     /* 
     int num=fr.read(buf); 
      
     System.out.println("num="+num+"..."+new String(buf)); 
      
     int num1=fr.read(buf); 
      
     System.out.println("num1="+num1+"..."+new String(buf)); 
      
     int num2=fr.read(buf); 
      
     System.out.println("num2="+num2+"..."+new String(buf,0,1)); 
        */   
    int num=0;  
    while((num=fr.read(buf))!=-1)  
    {  
      System.out.println(new String(buf,0,num));  
    }  
    fr.close();   
   }  
}  
拷贝文本文件:
步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。

import java.io.*;  
  
class CopyText   
{  
    public static void main(String[] args) throws IOException  
    {  
        copy_2();  
    }  
  
  
    public static void copy_2()  
    {  
        FileWriter fw = null;  
        FileReader fr = null;  
        try  
        {  
            fw = new FileWriter("SystemDemo_copy.txt");  
            fr = new FileReader("SystemDemo.java");  
  
            char[] buf = new char[1024];  
  
            int len = 0;  
            while((len=fr.read(buf))!=-1)  
            {  
                fw.write(buf,0,len);  
            }  
        }  
        catch (IOException e)  
        {  
            throw new RuntimeException("读写失败");  
  
        }  
        finally  
        {  
            if(fr!=null)  
                try  
                {  
                    fr.close();  
                }  
                catch (IOException e)  
                {  
                }  
            if(fw!=null)  
                try  
                {  
                    fw.close();  
                }  
                catch (IOException e)  
                {  
                }  
        }  
    }  
  
    //从C盘读一个字符,就往D盘写一个字符。  
    public static void copy_1()throws IOException  
    {  
        //创建目的地。  
        FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");  
  
        //与已有文件关联。  
        FileReader fr = new FileReader("RuntimeDemo.java");  
  
        int ch = 0;  
  
        while((ch=fr.read())!=-1)  
        {  
            fw.write(ch);  
        }  
          
        fw.close();  
        fr.close();  
  
    }  
}  

BufferedWriter和BufferedReader:字符流缓冲区

  1. 缓冲区的出现:提高了流的读写效率,所以在缓冲区创建前,要先创建流对象
  2.  该缓冲区中提供了一个跨平台的换行符:newLine()。
  3. 该缓冲区提供了一个一次读一行的方法readLine(),方便与对文本数据的获取,
        当返回null时,表示读到文件末尾。

     //bufw.write("abcde");  
     //bufw .write("\r\n");  

    //LineNumberReader继承BufferedReader是带行号的缓冲区

/* 
字符读取流缓冲区: 
 
该缓冲区提供了一个一次读一行的方法readLine,方便于对文本数据的获取。 
当返回null时,表示读到文件末尾。 
*/  
import java.io.*;  
class BufferedReaderDemo  
{  
   public static void main(String []args) throws IOException  
   {   
     //创建一个读取流对象和文件相关联  
     FileReader fr=new FileReader("buf.txt");  
     //为了提高效率,加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数  
     BufferedReader bufr=new BufferedReader(fr);  
       
     String line=null;  
     while((line=bufr.readLine())!=null)  
     {  
        System.out.println(line);  
     }  
     /* 
    String s1=bufr.readLine(); 
      
    System.out.println("s1:"+s1); 
     
    String s2=bufr.readLine(); 
      
    System.out.println("s2:"+s2); 
    */  
    bufr.close();  
   }  
     
}  

自定义BufferedReader

/* 
明白了BufferedReader类中特有方法readLine的原理后, 
可以自定义一个类中包含一个功能和readline一致的方法 
来模拟一下BufferedReader 
*/  
import java.io.*;  
  
class MyBufferedReader extends Reader  
{  
    
  //装饰设计模式  
   private Reader r=null;  
     
   MyBufferedReader(Reader r)  
   {  
      this.r=r;  
   }  
   //可以一次读一行数据的方法  
   public String myReadLine() throws IOException  
   {  
     //定义一个临时容器,员BufferedReader封装的是字符数组  
     //为了演示方便,定义一个StringBulilder容器,因为最终还是要将数据变成字符串。  
     StringBuilder sb=new StringBuilder();  
     int ch=0;  
     while((ch=r.read())!=-1)  
     {  
       if(ch=='\r')  
       continue;  
       if(ch=='\n')  
        return sb.toString();  
       else  
       sb.append((char)ch);  
     }  
     //如果没有遇到\n,sb中而且有数据的话也要返回  
      if(sb.length()!=0)  
        return sb.toString();  
     return null;  
   }  
  /* 
  覆盖类中的抽象方法 
  */  
  public int read(char[] cbuf,int off,int len)throws IOException  
  {  
    return r.read(cbuf,off,len);  
  }  
    
  public void close() throws IOException  
  {  
      r.close();  
  }  
    
  public void myClose() throws IOException  
  {  
      r.close();   
  }  
}  
  
  
  
class MyBufferedReaderDemo  
{  
   public static void main(String[] args) throws IOException  
   {  
      FileReader fr=new FileReader("buf.txt");  
        
      MyBufferedReader myBuf=new MyBufferedReader(fr);  
     
      String line=null;  
        
      while((line=myBuf.myReadLine())!=null)  
      {  
        System.out.println(line);  
      }  
        
      myBuf.myClose();  
   }  
     
}  
装饰设计模式:

  1. 当想要对已有的对象进行功能增强时,
  2. 可以定义一个类,将已有对象传入,基于已有的功能,并提供加强功能
  3. 那么自定义的该类称为装饰类
  4. 装饰类通常会通过构造方法接受被装饰的对象
  5. 并基于被装饰的对象的功能,提供更详细的功能。

装饰和继承的区别:

1·装饰模式比继承要灵活,通过避免了继承体系的臃肿,且降低了类与类间的关系。

2·装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。

3·从继承结构转为组合结构。

class Person  
{  
   public void chifan()  
   {  
      System.out.println("吃饭");  
   }  
}  
class SuperPerson  
{  
  
  private Person p;  
  SuperPerson(Person p)  
  {  
    this.p=p;  
  }  
  public void superChifan()  
  {  
     System.out.println("开胃酒");  
     p.chifan();  
     System.out.println("甜点");  
     System.out.println("吸根烟");  
  }  
    
}  
class PersonDemo  
{  
   public static void main(String[] args)  
   {  
       Person p=new Person();  
     //  p.chifan();  
     SuperPerson sp=new SuperPerson(p);  
       
     sp.superChifan();  
   }  
     
}  

字节流:

由于媒体数据中都是以字节存储的,所以,字节流对象可直接对媒体进行操作,可以不用再进行刷新流的动作。

不用进行刷新流的动作的原因:

      因为字节流操作的是字节,即数据的最小单位,不需要像字符流一样要进行转换为字节。可直接将字节写入到指定文件中,但是需要在写代码的时候,如果有字符串,要将字符串转为字节数组再进行操作。

int available() --->  放回数据字节的长度,包含终止符

     在定义字节数组长度的时候,可以用到这个方法:byte[] = new byte[fos.available()] fos为字节流对象)

但是,对于这个方法要慎用,如果字节过大,比如一部电影(几个G),那么如此大的数组就会损坏内存,超过jvm所承受的大小(指定内存为64M)。

import java.io.*;  
class FileStream{  
    public static void main(String []args) throws IOException  
   {   
      // writeFile();  
      // readFile_1();  
      // readFile_2();  
      readFile_3();  
   }  
   public static void readFile_1() throws IOException  
   {  
     FileInputStream fis=new FileInputStream("fos.txt");  
       
     int ch=0;  
     while((ch=fis.read())!=-1)  
     {  
        System.out.println((char)ch);  
     }  
     fis.close();  
   }  
     
    public static void readFile_2() throws IOException  
   {  
     FileInputStream fis=new FileInputStream("fos.txt");  
        
      //以这种方式为主,这是最好,最优化的方式  
     byte[] buf=new byte[1024];  
     int len=0;  
      while((len=fis.read(buf))!=-1)  
      {  
       System.out.println(new String(buf,0,len));  
      }  
      
     fis.close();  
   }  
     
    public static void readFile_3() throws IOException  
   {  
     FileInputStream fis=new FileInputStream("fos.txt");  
        
    // int num=fis.available();  
      
    //这种方式要慎用,数据不是太大的话,可以这样使用  
    byte[] buf=new byte[fis.available()];//定义一个刚刚好的缓冲区,不用再循环了  
        
     fis.read(buf);  
       
    // System.out.println("num="+num);  
     System.out.println(new String(buf));  
       
      
     fis.close();  
   }  
     
   public static void writeFile() throws IOException  
   {  
      FileOutputStream fos=new FileOutputStream("fos.txt");  
        
      //将字符串变为字节数组  
      fos.write("abcde".getBytes());  
        
      fos.close();  
        
   }  
}  

字节流缓冲区:

read():会将字节byte型值提升为int型值

write():会将int型强转为byte型,即保留二进制数的最后八位。

/* 
通过缓冲区,演示Mp3的复制 
 
BufferedOutputStream 
BufferedInputStream 
*/  
import java.io.*;  
class CopyMp3{  
    public static void main(String []args) throws IOException  
   {   
      long start=System.currentTimeMillis();  
      //copy_1();  
      copy_2();  
      long end=System.currentTimeMillis();  
        
      System.out.println((end-start)+"毫秒");  
   }  
     
   //通过字节流的缓冲区,完成复制  
   public static void copy_1() throws IOException  
   {  
       //缓冲区里已经定义了数组  
       BufferedInputStream  bufis=new BufferedInputStream(new FileInputStream("C:\\0.mp3"));  
       BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\1.mp3"));  
         
       int by=0;  
         
      
         
       while((by=bufis.read())!=-1)  
       {  
         bufos.write(by);  
       }  
       bufos.close();  
       bufis.close();  
   }  
     
   public static void copy_2() throws IOException  
   {  
       MyBufferedInputStream bufis=new  MyBufferedInputStream(new FileInputStream("C:\\0.mp3"));  
       BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("C:\\2.mp3"));  
         
       int by=0;  
         
       //读了一次没有写出去  
      // System.out.println("第一个字节:"+bufis.myRead());  
         
       while((by=bufis.myRead())!=-1)  
       {  
         bufos.write(by);  
       }  
       bufos.close();  
       bufis.myClose();  
   }  
}  

自定义字节流缓冲区:

  1. 取出的是byte型,返回的是int型,这里存在提升的动作,
  2. 当byte中的八位全为1的时候是byte的-1,提升为int类型,就变为int型的-1,,read循环条件就结束了
   变为-1的原因是由于在提升时,将byte的八位前都补的是1,即32位的数都是1,即为int型的-1了。

/* 
11111111 -->提升了一个int类型,那不还是-1,吗?是-1的原因是因为在8个1的前面补得的是1导致的 
那么我只要在前面补0,既可以保留原字节数据不变,又可以避免-1的出现,那么怎,补0呢 
                            
 11111111 11111111 11111111 11111111 
&00000000 00000000 00000000 11111111 
------------------------------------- 
 00000000 00000000 00000000 11111111 
  
 这样就可以避免-1的发生 
 byte:-1  ---->int:-1 
 read方法在提升,write方法将指定的字节写入此缓冲的输出流(强制转换,取最低的8位) 
*/  
  
import java.io.*;  
class MyBufferedInputStream{  
   private InputStream in;  
     
   private byte[] buf=new byte[1024*4];  
     
   private int pos=0;  
     
   private int count=0;  
   MyBufferedInputStream(InputStream in)  
   {  
     this.in=in;  
   }  
     
   //一次读一个字节,从缓冲区(字节数组)获取  
   public int myRead() throws IOException  
   {  
      //通过in对象,读取硬盘上的数据,并存储到buf中  
      if(count==0)  
      {  
        
      count= in.read(buf);  
      if(count<0)  
        return -1;  
      pos = 0;  
      //取数组第一个元素pos=0;  
      byte b=buf[pos];  
        
      count--;  
      pos++;  
     //b与255进行与操作,用十六进制表示就是0xff  
      return b&255;  
      }else if(count>0)  
      {  
      byte b=buf[pos];  
        
      count--;  
      pos++;  
      //b与255进行与操作,用十六进制表示就是0xff  
      return b&255;  
      }  
        
      return -1;  
   }  
   public void myClose()throws IOException  
   {  
      in.close();  
   }  
   
}  
读取键盘录入
/* 
需求: 
通过键盘录入数据,当录入一行数据后就进行打印。 
如果当录入的数据时over,那么停止录入 
 
Dos下键盘录入操作终止可以使用Ctrl+C操作 
*/  
  
import java.io.*;  
  
class  ReadIn  
{  
  public static void main(String[] args) throws IOException  
  {  
    InputStream in=System.in;  
    StringBuilder sb=new StringBuilder();  
    /* 
    int ch=0; 
    while((ch=in.read())!=-1) 
    { 
     System.out.println(ch); 
    }    
    */  
    while(true)  
    {  
        int ch=in.read();  
        if(ch=='\r')  
         continue;  
        if(ch=='\n')  
        {  
           String s=sb.toString();  
           if("over".equals(s))  
            break;  
           System.out.println(s.toUpperCase());  
           //sb=new StringBuilder();  
             
           sb.delete(0,sb.length());  //清除缓冲区里的内容,不然录入的数据会一直在缓冲区中,结束标记失效。
        }  
        else  
        sb.append((char)ch);  
    }  
      
      
    in.close();  
    //数据类型转换  
    System.out.println('\r'+0);  
    System.out.println('\n'+0);  
    /* 
    int by=in.read(); 
    int by1=in.read(); 
    int by2=in.read(); 
     
     
    System.out.println(by); 
    System.out.println(by1); 
    System.out.println(by2); 
    */  
  }  
}  

           ----------- java培训、java技术博客、期待与您交流! ------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值