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

一、字符流—读取文件

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

              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 stub
		
		BufferedReader 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,说明底层流对象读到结尾,那么直接返回-1
				return -1;
			
		}
		if(count > 0){        //如果count>0说明数组里有数据,直接取就可以
			byte b = buf[pos];
			count--;    //每获取一个,计数器就-1
			pos++;      //每获取一个,指针就向后移动1
			
			return 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 stub
		InputStream 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());//每次读取完,清空缓冲区中的内容,以便下次使用
				
			}
			else
			sb.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"));//传入一个打印流,记录数据
	}


posted @ 2012-11-21 17:10  积小流,成江海  阅读(332)  评论(0编辑  收藏  举报