java io 呕心沥血的学习 学了就忘

感觉io的知识,需要学以致用,否则学了就忘,忘了再学.........

看整体结构图,哇,sb了,是不是有这种感觉,其实无所谓,用的时候找api文档嘛,英文不行,找度娘嘛,别找我就行~




学习几个常用的吧,希望不会再忘!

1、FileInputStream  和  FileOutputStream

package IO_TEST;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileOutputStream_test {
    public static void main(String[] args) {  
        byte[] buffer=new byte[512];   //一次取出的字节数大小,缓冲区大小  
        int numberRead=0;  
        InputStream input=null;  
        OutputStream out =null;  
        try {  
           input = new FileInputStream("/Users/zhengchao/cctv/File_test.txt");  
           out = new FileOutputStream("/Users/zhengchao/cctv/File_test_out.txt"); //如果文件不存在会自动创建  
           //每次从INPUT中读取buffer大小的数据到buffer中
           while ((numberRead=input.read(buffer))!=-1) {  //numberRead的目的在于防止最后一次读取的字节小于buffer长度,  
              out.write(buffer, 0, numberRead);           //否则会自动被填充0  
           }  
        } catch (final IOException e) {  
            e.printStackTrace();  
        }finally{  
           try {  
              input.close();  
              out.close();  
           } catch (IOException e) {  
              e.printStackTrace();  
           }  
        }  
    }  
}

这两个类居然是很多流泪(流类)的父类哦,想都搞清楚,估计真得流泪了,如下:

FileOutputStream直接已知子类:

BufferedOutputStream, CheckedOutputStream, CipherOutputStream, DataOutputStream, DeflaterOutputStream, DigestOutputStream, InflaterOutputStream, PrintStream

FileInputStream直接已知子类:

BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream, DeflaterInputStream, DigestInputStream, InflaterInputStream, LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream


2、PipedOutputStream  和  PipedintputStream

Java里的管道输入流PipedInputStream与管道输出流PipedOutputStream实现了类似管道的功能,用于不同线程之间的相互通信

Java的管道输入与输出实际上使用的是一个循环缓冲数组来实现,这个数组默认大小为1024字节。输入流PipedInputStream从这个循环缓冲数组中读数据,输出流

PipedOutputStream往这个循环缓冲数组中写入数据。当这个缓冲数组已满的时候,输出流PipedOutputStream所在的线程将阻塞;当这个缓冲数组首次为空的时候,输入流

PipedInputStream所在的线程将阻塞。Java在它的jdk文档中提到不要在一个线程中同时使用PipeInpuStream和PipeOutputStream,这会造成死锁。

下面的例子:一个管道输出流的线程WriteThread,一个输入流的线程ReadThread,加一个测试案例Demo。

package IO_TEST;

import java.io.PipedOutputStream;

class WriteThread implements Runnable {  
    private PipedOutputStream pout;  

    WriteThread(PipedOutputStream pout){  
      this.pout=  pout;  
    }  

    @Override
    public void run(){  
        try {  
          System.out.println("W:开始将数据写入:但等个5秒让我们观察...");  
          Thread.sleep(5000);  //释放cpu执行权5秒  
          pout.write("writePiped 数据...".getBytes());  //管道输出流  
          pout.close();  
        } catch(Exception e) {  
          throw new RuntimeException("W:WriteThread写入失败...");  
        }  
    }  
}  
package IO_TEST;
import java.io.PipedInputStream;

class ReadThread implements Runnable {  
    
    private PipedInputStream pin;  

    ReadThread(PipedInputStream pin) {  
      this.pin=pin;  
    }  

    @Override
    public void run() {  //由于必须要覆盖run方法,所以这里不能抛,只能try  
    
      try {  
            System.out.println("R:读取前没有数据,阻塞中...等待数据传过来再输出到控制台...");  
            byte[] buf = new byte[1024];  
            int len = pin.read(buf);  //read阻塞  
            System.out.println("R:读取数据成功,阻塞解除...");  
            String s= new String(buf,0,len);  
            System.out.println(s);  //将读取的数据流用字符串以字符串打印出来  
            pin.close();       
      }  catch(Exception e)  {  
            throw new RuntimeException("R:管道读取流失败!");  
      }     
    }  
}  
package IO_TEST;

import java.io.PipedInputStream;
import java.io.PipedOutputStream;


public class Demo {  
    public static void main(String[] args)  throws Exception {  
      PipedInputStream pin = new PipedInputStream();  
      PipedOutputStream pout = new PipedOutputStream();  
      pin.connect(pout);  //输入流与输出流连接  

      ReadThread readTh   = new ReadThread(pin);  
      WriteThread writeTh = new WriteThread(pout);  
      new Thread(readTh).start();  
      new Thread(writeTh).start();  
    }  
}
pipe流的输入输出具体使用起来可能会让人有点混乱的感觉,需搞清楚管道的概念。

我们再看一个实际下载用的例子,一些看不懂不要紧,后面会逐步解释:(ejb  rest )

@GET
@Path("/download/{status}")
public Response download(@PathParam("status") final LoanStatus status) throws IOException {
        
        String contentDisposition = "attachment; filename*=UTF-8''" + URLEncoder.encode(status.getKey().toString().concat("_借款列表"), "UTF-8") + ".csv";
        
        final PipedOutputStream output = new PipedOutputStream();
        PipedInputStream input = new PipedInputStream(output);

        final List<Loan> loanList = loanBridge.listByStatusOrdDesc(PageInfo.ALL, status).getResults();

        Runnable writer = new Runnable() {
            @Override
            public void run() {
                //用到了装饰模式:BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(output, "GBK"));
                //字符流转换成字节流
                try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(output, "GBK"));) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("借款单标的号").append(CSV_SEPERATOR)
                            .append("借款人").append(CSV_SEPERATOR)
                            .append("工号").append(CSV_SEPERATOR)
                            .append("期限");
                    bw.append(sb.toString());
                    bw.newLine();
                    for (Loan loan : loanList) {
                        sb = new StringBuilder();
                        LoanRequest request = loan.getLoanRequest();
                        sb.append(loan.getTitle() + CSV_WRAP).append(CSV_SEPERATOR)
                                .append(appBean.getUser(request.getUserId()).getName()).append(CSV_SEPERATOR)
                                .append(appBean.getUser(request.getUserId()).getEmployeeNumber() + "\t").append(CSV_SEPERATOR)
                                .append(loan.getDuration().getShowDuration());
                        bw.append(sb.toString());
                        bw.newLine();
                    }
                    bw.flush();
                } catch (Exception ex) {
                    logger.error("Exception happened when write CSV for user list.", ex);
                }
            }
        };

        Thread thread = new Thread(writer);
        thread.start();
        return Response.ok(input, "text/csv").encoding("GBK").header("Content-Disposition", contentDisposition).build();
    }

3、BufferedInputStream  和   BufferedOutputStream

为InputStream,OutputStream类增加缓冲区功能。上面说的FileInputStream和FileOutputStream 在使用时,我们介绍了可以用byte数组作为数据读入的缓存区,以读文件为列,读取硬盘的速度远远低于读取内存的数据,为了减少对硬盘的读取,通常从文件中一次读取一定长度的数据,把数据存入缓存中,在写入的时候也是一次写入一定长度的数据,这样可以增加文件的读取效率。我们在使用FileInputStream的时候是用byte数组来做了缓存,而BufferedInputStream  and BufferedOutputStream已经为我们增加了这个缓存功能。构建BufferedInputStream实例时,需要给定一个InputStream类型的实例,实现BufferedInputStream时,实际上最后是实现InputStream实例。同样,构建BufferedOutputStream时,也需要给定一个OutputStream实例,实现BufferedOutputStream时,实际上最后是实现OutputStream实例。BufferedInputStream的数据成员buf是一个位数组,默认为2048字节。当读取数据来源时,例如文件,BufferedInputStream会尽量将buf填满。当使用read()方法时,实际上是先读取buf中的数据,而不是直接对数据来源作读取。当buf中的数据不足时,BufferedInputStream才会再实现给定的InputStream对象的read()方法,从指定的装置中提取数据。BufferedOutputStream的数据成员buf也是一个位数组,默认为512字节。当使用write()方法写入数据时实际上会先将数据写到buf中,当buf已满时才会实现给定的OutputStream对象的write()方法,将buf数据写到目的地,而不是每次都对目的地作写入的动作。

package IO_TEST;
import java.io.*;  

public class BufferOutputStream_test {
    
    public static void main(String[] args) {   
        
        try {   
            byte[] data = new byte[1];   
  
            File srcFile = new File(args[0]);   
            File desFile = new File(args[1]);   
  
            BufferedInputStream bufferedInputStream =    
                new BufferedInputStream(new FileInputStream(srcFile));   
  
            BufferedOutputStream bufferedOutputStream =    
                new BufferedOutputStream(new FileOutputStream(desFile));   
  
            System.out.println("复制文件:"+srcFile.length()+"字节");   
  
            while(bufferedInputStream.read(data)!=-1) {   
                bufferedOutputStream.write(data);   
            }   
  
            //将缓冲区中的数据全部写出   
            bufferedOutputStream.flush();   
  
            //关闭流   
            bufferedInputStream.close();   
            bufferedOutputStream.close();   
  
            System.out.println("复制完成");   
        } catch(ArrayIndexOutOfBoundsException e)  {   
            System.out.println("using:java UseFileStream src des");   
            e.printStackTrace();   
        }   catch(IOException e) {   
            e.printStackTrace();   
        }   
    }   
};  


4、上面讲的流对象都是成双成对,有输入类也有输出类,现在看一个特殊的光棍io流类(1111快到啦)

SequenceInputStream:

    合并流,将与之相连接的流集组合成一个输入流并从第一个输入流开始读取, 直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。 合并流的作用是将多个源合并合一个源。可接收枚举类所封闭的多个字节流对象。 

package IO_TEST;  
   
import java.io.*;  
import java.util.Enumeration;  
import java.util.Vector;  
   
public class NewClass {  
 
  public static void main(String[] args) {  
     doSequence();  
  }  
   
  private static void doSequence() {  
     SequenceInputStream sis = null;  // 创建一个合并流的对象  
     BufferedOutputStream bos = null;   // 创建输出流。  
     try {  
        // 构建流集合。  
        Vector<InputStream> vector = new Vector<InputStream>();  
        vector.addElement(new FileInputStream("/Users/zhengchao/cctv/File_1.txt"));  
        vector.addElement(new FileInputStream("/Users/zhengchao/cctv/File_1.txt"));  
        Enumeration<InputStream> e = vector.elements();  
        sis = new SequenceInputStream(e);  
        bos = new BufferedOutputStream(new FileOutputStream("/Users/zhengchao/cctv/File_OUT.txt"));  
        // 读写数据  
        byte[] buf = new byte[1024];  
        int len = 0;  
        while ((len = sis.read(buf)) != -1) {  
           bos.write(buf, 0, len);  
           bos.flush();  
        }  
     } catch (FileNotFoundException e1) {  
        e1.printStackTrace();  
     } catch (IOException e1) {  
        e1.printStackTrace();  
     } finally {  
        try {  
           if (sis != null)  
              sis.close();  
        } catch (IOException e) {  
           e.printStackTrace();  
        }  
        try {  
           if (bos != null)  
              bos.close();  
        } catch (IOException e) {  
           e.printStackTrace();  
        }  
     }  
  }  
}  


5、读写对象:ObjectInputStream 和ObjectOutputStream

package IO_TEST;  
  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.io.Serializable;  
public class ObjetStream_test {    
   public static void main(String[] args) {    
      ObjectOutputStream objectwriter=null;    
      ObjectInputStream objectreader=null;    
         
      try {    
         objectwriter=new ObjectOutputStream(new FileOutputStream("/Users/zhengchao/cctv/File_objectwriter_out.txt"));    
         objectwriter.writeObject(new Student("gg", 22));    
         objectwriter.writeObject(new Student("tt", 18));    
         objectwriter.writeObject(new Student("rr", 17));    
         objectreader=new ObjectInputStream(new FileInputStream("/Users/zhengchao/cctv/File_objectwriter_out.txt"));    
         for (int i = 0; i < 3; i++) {    
            System.out.println(objectreader.readObject());    
         }    
      } catch (IOException | ClassNotFoundException e) {      
         e.printStackTrace();    
      }finally{    
         try {    
            objectreader.close();    
            objectwriter.close();    
         } catch (IOException e) {     
            e.printStackTrace();    
         }    
      }    
   }    
}    
class Student implements Serializable{    
   private String name;    
   private int age;    
   public Student(String name, int age) {    
      super();    
      this.name = name;    
      this.age = age;    
   }    
   @Override    
   public String toString() {    
      return "Student [name=" + name + ", age=" + age + "]";    
   }    
}    
Student类必须实现Serializable接口,并重写toString()方法,否则 objectwriter.writeObject(new Student("gg", 22)); 执行会报错。

6、ByteArrayInputStream和ByteArrayOutputStream,

用于以IO流的方式来完成对字节数组内容的读写,来支持类似内存虚拟文件或者内存映射文件的功能

import java.io.*;  
  
public class ByteArrayStreamTest {  
    public static void main(String [] args) {  
        String str = "abcdef";  
          
        ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes());  
        ByteArrayOutputStream out = new ByteArrayOutputStream();  
          
        transform(in, out);  
          
        byte[] result = out.toByteArray();  
          
        System.out.println(out);  
        System.out.println(new String(result));  
          
        transform(System.in, System.out); // 从键盘读,输出到显示器  
    }  
      
    public static void transform(InputStream in, OutputStream out) {  
        int ch = 0;  
          
        try {  
            while ((ch = in.read()) != -1) {  
                int upperChar = Character.toUpperCase((char)ch);  
                out.write(upperChar);  
            } // close while  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}  


总结:感觉学的差不多了,总结一下,总结?好像上面说的都是字节流啊,难道?对了,这才学一半不到呢。



字符流:


 1、Writer

       写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。 其子类如下:

   

    ~BufferedWriter   :

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。


2、Reader

   用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。 子类有:

      


示例:
1、使用BufferedReader和BufferedWriter 字符处理流实现文件复制
import java.io.*;  
class IODemo {  
    public static void main(String[] args){  
        try {  
        //使用BufferedReader和BufferedWriter进行文件复制(操作的是字符,以行为单位读入字符)  
        FileReader fr=new FileReader("a.txt");  
        BufferedReader br=new BufferedReader(fr);  
        FileWriter fw=new FileWriter("d.txt");  
        BufferedWriter bw=new BufferedWriter(fw);  
  
        String s=br.readLine();  
            while(null!=s) {  
                bw.write(s);  
                //由于BufferedReader的rendLIne()是不读入换行符的,所以写入换行时须用newLine()方法  
                bw.newLine();  
                //read=fis.read(b);  
                s=br.readLine();  
            }  
            br.close();  
            bw.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }   
    }  
}  


字节字符转换:

1:字节输入流转换为字符输入流:

InputStreamReader是字节流向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符,它使用的字符集可以由名称指定或显示给定。根据InputStream的实例创建InputStreamReader的方法有4种:

InputStreamReader(InputStream in)//根据默认字符集创建

InputStreamReader(InputStream in,Charset cs)//使用给定字符集创建

InputStreamReader(InputStream in,CharsetDecoder dec)//使用给定字符集解码器创建

InputStreamReader(InputStream in,String charsetName)//使用指定字符集创建

2:字节输出流转换为字符输出流

OutputStreamWriter是字符流通向字节流的桥梁,它使用指定的charset将要写入流中的字符编码成字节,它使用的字符集可以由名称指定或显示给定,否则将接受默认的字符集:

根据根据InputStream的实例创建OutputStreamWriter的方法有4种:

OutputStreamWriter(outputstream out)//根据默认的字符集创建

OutputStreamWriter(outputstream out,charset cs)//使用给定的字符集创建

OutputStreamWriter(outputstream out,charsetDecoder dec)//使用组定字符集创建

OutputStreamWriter(outputstream out,String charsetName)//使用指定字符集创建


Java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。(这四个都是抽象类)

java中提供了专用于输入输出功能的包Java.io,其中包括:
     InputStream,OutputStream,Reader,Writer
     InputStream 和OutputStream,两个是为字节流设计的,主要用来处理字节或二进制对象,
     Reader和 Writer.两个是为字符流(一个字符占两个字节)设计的,主要用来处理字符或字符串.


字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点
     所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列

      字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以
       字节流是最基本的,所有的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的 

==================我们还可以看到:============
Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1


inputStream的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字.






  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值