Java——IO流读写对象及流操作规律



IO流

概述:IO流就是用来进行数据的输入输出操作的一个缓冲区。
按操作的对象不同可分为:
   1、对字符操作
             Reader和Writer
   2、对字节操作
             InputStream和OutputStream

字符流:
   
FileWriter:是Writer的一个子类,用于进行文件的数据写入,以字符为操作单位。
首先要创建一个FileWriter对象,构造方法的参数要指定一个文件名,用来明确数据写入的位置。如:FileWriter fw = new FileWriter("demo.txt");
常用方法:
write() //将数据存储到字符流中,可以以字符串,字符,字符数组等为参数。
flush() //刷新字符流,将数据写入到目的地。
close() //刷新字符流,同时关闭字符流,调用后Writer对象不能使用。
示例:
import java.io.*;

class FileWriterDemo
{
	public static void main(String[] args) throws IOException
	{
		//创建一个FileWriter对象,该对象一被初始化,就必须要明确被操作的文件。
		//没有此文件 将创建文件,如有同名文件,将被覆盖。
		FileWriter fw = new FileWriter("demo.txt");
		//write方法将字符串写入到流中。
		fw.write("hello");
		//刷新缓冲区中数据,写入目的地中。
		//fw.flush();
		//关闭流,并刷新一次缓冲中的数据。 
		fw.close();
		
	}
}


字符流读取方法
以FileReader为例:
常用方法:
    read() //读取一个字符,返回字符对应的ACSII码
    close() //关闭读取流
读取文件示例:
 

import java.io.*;

class FileReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		//第一种读取方式:单个字符读取
		FileReader fr = new FileReader("demo.txt");
		
		while(true)
		{
			 int c = fr.read();
			 if(c == -1)
				break;
			 System.out.print((char)c);
		}
			
		fr.close(); 
		//第二种方式:通过字符数组进行读取。
		//read(char[])返回的是读到的字符个数 
		FileReader fr2 = new FileReader("demo.txt");
		char[] buf = new char[1024];
		int num = 0;
		while((num = fr2.read(buf)) != -1)
			 System.out.print(new String(buf, 0, num));

		fr2.close();
	}
}


带缓冲区的字符读取和写入流:
BufferedReader和BufferedWriter:
这两个类封装了定义缓冲区的操作,在读取和写入时定义了字符数组作为缓冲区,避免了单个字符操作的低效率。建立对象时,需要传入对应的Reader和Writer对象作为参数。
    BufferedWriter:
    建立对象时格式应如:
          FileWriter fw = new FileWriter("test.txt");
          BufferedWriter bufw = new BufferedWriter(fw);
    特有方法:
          newLine() //添加一个换行符,自动通过系统获取,可以跨平台。
          BufferedReader:
    建立对象和上面方法类似。
    特有方法:
          readLine() //返回一个字符串,内容是读取一行字符的内容,到文本末尾返回null。
示例:
import java.io.*;

class BufferedReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("test.java");
		BufferedReader bufr = new BufferedReader(fr);
		
		String s = null;
		while((s = bufr.readLine()) != null)
		{
			System.out.println(s);
		}
	}
}
	
	
class BufferedWriterDemo
{
	public static void main(String[] args) throws IOException
	{
		FileWriter fw = new FileWriter("buf.txt");
		BufferedWriter bufw = new BufferedWriter(fw);
		
		bufw.write("abcde");
		bufw.flush();
		
		bufw.close();//关闭缓冲区也直接关闭了FileWriter对象;
	}
} 



装饰模式:
这种对原有Reader和Writer功能进行增强的设计模式成为装饰设计模式。
方法是在遇到一个定义好的类,并需要对其进行改进时,定义一个新类,将其作为新类的成员,并定义新方法,内部使用原有需要改进的方法,并加入新的代码。

这种设计模式的好处在于:
装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
自定义BufferedReader:
下面用这种设计模式 自定义一个BufferedReader,主要以自定义的readLine()方法为例:
import java.io.*;
//自定义BufferedReader类
class MyBufferedReader extends Reader
{
	private Reader r;
	MyBufferedReader(Reader r)
	{
		this.r = r;
	}
	//一次读一行数据的方法
	public String myReadLine()throws IOException
	{
		//定义一个临时容器,原BufferedReader使用的是字符数组,
		//这里为了方便使用StringBuilder,
		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);
		}
		if(sb.length() != 0)
		{
			return sb.toString();
		}
		return null;
	}
	
	public void close()throws IOException
	{
		r.close();
	}
	
	public int read(char[] cbuf, int off, int len)throws IOException
	{
		return r.read(cbuf, off, len);
	}
}

class MyBufferedReaderDemo
{
	public static void main(String[] args)throws IOException
	{
		FileReader fr = new FileReader("test.java");
		MyBufferedReader mbufr = new MyBufferedReader(fr);
		
		FileWriter fw = new FileWriter("buf.txt");
		BufferedWriter bufw = new BufferedWriter(fw);
		
		String buf = null;
		while((buf = mbufr.myReadLine()) != null)
		{
			fw.write(buf);
			bufw.newLine();
			bufw.flush();
		}
		
		mbufr.close();
		fw.close();
	}
}



字节流:
字节流是直接针对字节进行操作的,所以字节流可以直接对非文本文件进行读写。

读写方法与字符流类似,只是自定义的缓冲区缓存byte数组就可以了。
以拷贝图片为例:
import java.io.*;

class CopyPic
{
	public static void picCopy()
	{
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try
		{
			fos = new FileOutputStream("buf.jpg");
			fis = new FileInputStream("logo.jpg");
			
			byte[] buf = new byte[1024];
			int len = 0;
			while((len = fis.read(buf)) != -1)
			{
				fos.write(buf, 0, len);
			}
		}
		catch(IOException e)
		{
			System.out.println("pic copy failed");
		}
		finally
		{
			try
			{
				if(fos != null)
					fos.close();
			}
			catch(IOException e)
			{
				System.out.println("output close failed");
			}
			try
			{
				if(fos != null)
					fos.close();
			}
			catch(IOException e)
			{
				System.out.println("input close failed");
			}
		}
	}
	
	public static void main(String[] args)
	{
		picCopy();
	}
}



字节流也有对应的带有缓冲区的加强类:BufferedInputStream和BufferedOutputStream
调用read()方法时应注意,它会把读到的byte类型数据提升为int类型并返回,数据前自动补齐-1,这样在遇到连续8位是1的数据时,再补齐-1就会被当做结束标记,
自定义read()方法时,应注意在提升byte为int时,要在前面补0,也就是将数据和255做与运算。
自定义BufferedInputStream如下:
import java.io.*;

class MyBufferedInputStream
{
	private InputStream in;
	private byte[] buf = new byte[1024];//缓冲区
	private int pos = 0, count = 0;//定义指针,计数器
	MyBufferedInputStream(InputStream in)
	{
		this.in = in;
	}
	//一次读一个字节,从缓冲区——字节数组中读
	public int myRead()throws IOException
	{
		if(count == 0)//数组是否取空
		{

			count = in.read(buf);//通过in对象读取硬盘上的数据 并存储到缓冲区buf中,
			if(count < 0)
			{
				return -1;
			}
			pos = 0;
			byte b = buf[pos];//第一次从缓冲区中取一个字节
			
			count --;
			pos ++;
			return b & 0xff;//补0
		}else if(count > 0)
		{
			byte b = buf[pos];//一次从缓冲区中取一个字节
			count --;
			pos ++;
			return b & 255;//补0
		}
		return -1;
	}
	
	public void close()throws IOException
	{
		in.close();
	}
}
	
/* byte型提升为int型后,8位数据提升为32位,前面系统自动补1,如果独到8个1,补位后
 * 还是-1,就会中断读数据循环,所以要手动补0。就和255与运算。
 * 
 */



字符流与字节流转换流:
最简单的应用例子就是,在获取键盘录入时,希望提高效率,避免输入一个读取一个,改为输入一行,然后整行读取到缓冲区,而readLine()方法又是字符流的方法,
这时就可以使用转换流,将InputStream对象传入InputStreamReader构造函数中,再通过BufferedReader对象来使用readLine()方法。

代码如下:
import java.io.*;

class TransStreamDemo
{
	public static void main(String[] args)throws IOException
	{
		//获取键盘录入对象
//		InputStream in = System.in;
//		//将字节流转换成字符流,使用转换流
//		InputStreamReader isr = new InputStreamReader(in);
//		BufferedReader br = new BufferedReader(isr);
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				
//		OutputStream out = System.out;
//		OutputStreamWriter osw = new OutputStreamWriter(out);
//		BufferedWriter bw = new BufferedWriter(osw);
		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		String buf = null;
		while((buf = br.readLine()) != null)
		{
			if("over".equals(buf))
				break;
			bw.write(buf.toUpperCase());
			bw.newLine();
			bw.flush();
		}
		
		br.close();
		br.close();
		bw.close();
	}
}




流操作规律:
下面总结一下流操作规律,以便明确数据操作时用哪个流对象。
通过明确以下几点就可以确定:
1、   源:输入流:InputStream Reader
         目的:输出流:OutputStream Writer
2、操作的是否为纯文本:
          是:字符流对象
          否:字节流对象
3、通过设备来确定具体对象:
          硬盘上文件:Filexxxx
          标准输入输出设备(键盘,控制台):System.xx 这里可以通过System.setxx()来设置默认设备。

再通过是否需要提高效率决定是否用Bufferedxxx。
示例:
需求:想要将一个文件的数据打印在控制台上。
源:文件
目的:控制台
代码如下:
import java.io.*;

class TransStreamDemo
{
	public static void main(String[] args)throws IOException
	{
		//获取键盘录入对象
//		InputStream in = System.in;
//		//将字节流转换成字符流,使用转换流
//		InputStreamReader isr = new InputStreamReader(in);
//		BufferedReader br = new BufferedReader(isr);
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				
//		OutputStream out = System.out;
//		OutputStreamWriter osw = new OutputStreamWriter(out);
//		BufferedWriter bw = new BufferedWriter(osw);
		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		String buf = null;
		while((buf = br.readLine()) != null)
		{
			if("over".equals(buf))
				break;
			bw.write(buf.toUpperCase());
			bw.newLine();
			bw.flush();
		}
		
		br.close();
		br.close();
		bw.close();
	}
}

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值