java基础--IO流之字节、字符和转换流

来源:互联网 发布:js星空效果 编辑:程序博客网 时间:2024/05/16 19:31

一、字符流—读取文件

       建立一个流对象,将已存放的一个文件加载进流

              FileReader  fr  = new FileReader(“Test.tex”);

       创建一个临时存放数据的数组,用于缓冲

              Char[]ch = new char[1024];

       调用流对象的读取方式将流中的数据读入到数组中

              fr.read(ch);


文件的拷贝示例代码:

package cn.xushuai.io;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class copyfileDemo {public static void main(String[] args){FileReader fr = null;FileWriter fw = null;try{fr = new FileReader("WriterDemo.txt");fw = new FileWriter("readerDemo.txt",true);int ch = 0;int len = 0;char[] buf = new char[1024];while(( len =fr.read(buf))!=-1){fw.write((char)ch);fw.write(buf,0,len);fw.flush();}}catch(IOException e){System.out.println("文件读写失败");}finally{if(fr!=null)try { fr.close();} catch (IOException e) {System.out.println("读取流关闭失败!");}if(fw!=null)try {fw.close();} catch (IOException e) {System.out.println("写入流关闭失败!");}}}}

字符流缓冲区:

    1、缓冲区的出现提高了对数据的读写效率。

对应类:BufferedWriter

           BufferedReader

   

    2、缓冲区要结合流才可以使用。

    在流的基础上对流的功能进行了增强。

   

   3、字符读取流缓冲区:

    该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。

    当返回null时,表示读到文件末尾。

  

   4、readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符,

    所以应该手动换行:println或者newLine()。


字符流缓冲区对象使用演示代码:

说明:基本操作与字符流类相同,但它不仅可以操作字符,还可以操作其他媒体文件

package cn.xushuai.io;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class copyTextByBuf {public static void main(String[] args) {// TODO Auto-generated method stubBufferedReader bufr = null;BufferedWriter bufw = null;try { bufr = new BufferedReader(new FileReader("readerDemo.txt")); bufw = new BufferedWriter(new FileWriter("writerDemo.txt",true));int ch = 0;String str = null;while((str = bufr.readLine())!=null){bufw.write(str);bufw.newLine();bufw.flush();//System.out.print((char)ch);}} catch (IOException e) {System.out.println("文件读取失败!");}finally{try {if(bufr!=null)bufr.close();} catch (IOException e) {System.out.println("读取关闭失败!");}try {if(bufw!=null)bufw.close();} catch (IOException e) {System.out.println("写入关闭失败!");}}}}



二、字节流读写文件

import java.io.*;class  FileStream{public static void main(String[] args) throws IOException{readFile_3();}//使用缓冲区读取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(new String(buf));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_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 writeFile()throws IOException{FileOutputStream fos = new FileOutputStream("fos.txt");fos.write("abcde".getBytes());fos.close();}}

练习:使用字节流复制图片

复制一个图片

思路:

1,用字节读取流对象和图片关联。

2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。

3,通过循环读写,完成数据的存储。

4,关闭资源。

 

import java.io.*;class  CopyPic{public static void main(String[] args) {FileOutputStream fos = null;FileInputStream fis = null;try{fos = new FileOutputStream("c:\\2.bmp");fis = new FileInputStream("c:\\1.bmp");byte[] buf = new byte[1024];int len = 0;while((len=fis.read(buf))!=-1){fos.write(buf,0,len);}}catch (IOException e){throw new RuntimeException("复制文件失败");}finally{try{if(fis!=null)fis.close();}catch (IOException e){throw new RuntimeException("读取关闭失败");}try{if(fos!=null)fos.close();}catch (IOException e){throw new RuntimeException("写入关闭失败");}}}}

自定义字节流缓冲区

要求:定义一个字节缓冲区


原理:

    自定义一个数组,用于存储数据,底层是通过inputStream的read(byte[ ] )方法进行读取,每次读取

    后返回数组长度的字节,然后由缓冲区流对象BufferedInputStream的read()往外读取,每读取一个

    字节指针向后移动1位,字节数减1,直到读取到数组的最后,计数器为0,重新read(byte[ ])


步骤:

       定义一个数组,用于临时存放数据

       定义一个指针,用于操作数据

       定义一个计数器,用于确定数组是否为空

 

  关键:在myRead的返回值上,为了避免连续8个1的出现导致读取结束,

  因此将byte提升至int,然后保留最低8位,即可

 

自定义缓冲区示例代码:

package cn.xushuai.io;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;public class MyBufferedInputStream {private InputStream in;byte[] buf = new byte[1024];private int pos,count;MyBufferedInputStream(InputStream in){this.in = in ;}public int myRead() throws IOException{if(count==0){      //当计数器为0,即取完之后,进行下一次读取pos = 0;   //每次取完之后,指针要回到起始点count = in.read(buf);if(count<0)     //如果count小于0,说明底层流对象读到结尾,那么直接返回-1return -1;}if(count > 0){        //如果count>0说明数组里有数据,直接取就可以byte b = buf[pos];count--;    //每获取一个,计数器就-1pos++;      //每获取一个,指针就向后移动1return b&0xff;    //取int的最低4位,返回读取到的一个字节}return -1;}public void myClose() throws IOException{in.close();}}

read( )返回值类型

字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。

因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.

那么就会导致数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。

所以,为了避免这种情况将读到的字节进行int类型的提升,


byte的-1 被提升为int后的-1:

11111111 11111111 11111111 11111111

&

00000000 00000000 00000000 11111111       (int的最低8位,255)

-------------------------------------------------------------

00000000 00000000 00000000 11111111 


并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值255,不再是-1。

而在写入数据时,只写该int类型数据的最低8位。

 

三、读取键盘录入

介绍了键盘录入的读取并进而引入转换流

 System.out:对应的是标准输出设备,控制台。

System.in:对应的标准输入设备:键盘。


读取键盘录入练习

需求:

通过键盘录入数据。

当录入一行数据后,就将该行数据进行打印。

如果录入的数据是over,那么停止录入。


示例代码

package cn.xushuai.io;import java.io.IOException;import java.io.InputStream;//键盘录入public class ReadIn {public static void main(String[] args) throws IOException {// TODO Auto-generated method stubInputStream in = System.in;int ch = 0;StringBuilder sb = new StringBuilder();while(true){ch = in.read();if(ch=='\r')continue;if(ch=='\n'){String s = sb.toString();if(s.equals("over"))break;//程序结束,不再读取System.out.println(s.toUpperCase());sb.delete(0, sb.length());//每次读取完,清空缓冲区中的内容,以便下次使用}elsesb.append((char)ch);}}}

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。

readLine方法是字符流BufferedReader类中的方法。

而键盘录入的read方法是字节流InputStream的方法,也就是readLine方法。

那么能不能将字节流转成字符流在使用字符流缓冲去的readLine方法呢?

所以就出现了转换流:

       InputStreamReader :     

       OutputStreamWriter      


四:转换流

 

1.、InputStreamReader:将字节流转换为字符流                              

为了提高键盘录入的效率。通过转换流,使字节流转化为字符流,然后使用字符流的方法操作,为了一次可以读取一行,所以用BufferedReader包装。

键盘录入:BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in));

 

2、 OutputStreamWriter :将字符流转换为字节流

因为写入时字符输出流利用了字节缓冲区,所以需要刷新,同时希望换行,所以希望用 跨平台的newLine方法,又因为newLine方法属于BuffereWriter,,所以用BufferedWriter 进行包装。

标准输出:BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(System.out));

 

转换流的使用示例代码:

import java.io.*;class  TransStreamDemo{public static void main(String[] args) throws IOException{//字节转向字符,提高操作效率//获取键盘录入对象。//InputStream in = System.in;//将字节流对象转成字符流对象,使用转换流。InputStreamReader//InputStreamReader isr = new InputStreamReader(in);//为了提高效率,可以一次读取一行,将字符串进行缓冲区技术高效操作。使用BufferedReader//BufferedReader bufr = new BufferedReader(isr);//键盘的最常见写法。BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//字符通向字节的桥梁,将字符数据以字节的方式写出//OutputStream out = System.out;//OutputStreamWriter osw = new OutputStreamWriter(out);//BufferedWriter bufw = new BufferedWriter(osw);//增强写入,因为newLine是缓冲区的方法BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));String line = null;while((line=bufr.readLine())!=null){if("over".equals(line))break;bufw.write(line.toUpperCase());bufw.newLine();bufw.flush();}bufr.close();}}

转换流的使用总结:

需求:想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

      

分析:

              目的:OutputStream  Writer

              是否是存文本?是!Writer。

              设备:硬盘。一个文件。使用 FileWriter。

              但是FileWriter是使用的默认编码表:GBK.

      

       而存储时,需要加入指定编码表utf-8,而指定的编码表只有转换流可以指定。

       所以要使用的对象是OutputStreamWriter。

       而该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流。

       FileOutputStream   OutputStreamWriterosw = new OutputStreamWriter(newFileOutputStream("d.txt"),"UTF-8");

 

       需要高效吗?需要。

       BufferedOutputStream  bos  = new BufferedOutputStream(osw);

 

       转换流使用场合:

字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。


五、创建日志信息

示例说明:主要是使用System.setOut来重定向输出流,并使用到了Date 和SimpleDateFormat来获得指定格式的日期


import java.io.*;import java.util.*;import java.text.*;//使用System.setOut 创建日志信息class  ExceptionInfo{public static void main(String[] args)throws IOException {try{int[] arr = new int[2];System.out.println(arr[3]);}catch (Exception e){try{Date d = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(d);PrintStream ps = new PrintStream("c:\\exeception.log");ps.println(s);System.setOut(ps);//将标准输出重新定向为一个文件}catch (IOException ex){throw new RuntimeException("日志文件创建失败");}e.printStackTrace(System.out);}}}

六、使用properties来获取系统信息

import java.util.*;import java.io.*;class  SystemInfo{public static void main(String[] args) throws IOException{Properties prop = System.getProperties();//获取系统信息//System.out.println(prop);prop.list(new PrintStream("sysinfo.txt"));//传入一个打印流,记录数据}


原创粉丝点击