IO流


1、IO流
         IO流,用来处理设备间的数据传输,Java中对数据的操作是通过流的方式
         java.io包中包含了流式I/O所需要的所有类。在java.io包中有四个基本类:InputStream、OutputStream及Reader、Writer类,它们分别处理字节流字符流
            
2、字符流Writer/Reader
      Java中字符是采用Unicode标准一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。
(1)字符输出流 Writer
        Writer写入字符流的抽象类。子类必须实现的方法仅有write(char[], int, int)、flush() 和 close()
  [1]熟悉Writer中write,flush,close方法
public class FileWriterDemo {

	public static void main(String[] args) throws IOException {

		// 创建一个FileWriter对象
		FileWriter fw = new FileWriter("FileWriterDemo.txt");
		// 调用write方法,将字符串写到流中
		fw.write("hello wrold!");

	}
}
当执行上述代码时,FileWriterDemo.txt文件上并没有任何字符。原因:FileWriter对象其实先把数据写入到了缓冲区中,所以需要使用flush()方法,或

者close()方法,把缓冲区的数据刷新到目的地上。
  // 刷新流对象中的缓冲中的数据
		// fw.flush();
		// 关闭流资源,关闭前会刷新一次内部的缓冲数据
		fw.close();
      flush()方法与close()方法区别:flush刷新后,流还可以使用;close刷新后,流关闭

   FileWriter还有一个特点:创建一个FileWriter对象,该类对象一被初始化就必须要明确被操作的文件;而且该文件会被创建到指定目录下,如

果该目录下已有同名文件,将被覆盖.所以向一个已经数据的文件添加数据又该如何?如果按照之前的方法,该文件将会被覆盖。

   FileWriter(File file, boolean append)提供这个方法,当第二个参数为true,则将字节写入文件末尾处,而不是写入文件开始处。

(1)字符输入流 Reader
      用于读取字符流的抽象类。子类必须实现的方法只有read(char[], int, int) 和 close()
   读取的字符输入流FileReader:两种方法读取文本
       实例代码:
/*
 * 第一种方式:通过每次取出一个字符的方式读取 
 * read()返回的字符的10进制数字. 
 */
public class FileReaderDemo {

	public static void main(String[] args) {
		FileReader fr = null;
		try {
			// 创建一个文件读取流对象,和指定名称的文件相关联.
			fr = new FileReader("FileWriterDemo.txt");
			int ch = -1;
			while ((ch = fr.read()) != -1) {
				System.out.println((char) ch);
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally {
			try {
				if (fr != null)
					fr.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
// 第二种方式:通过字符数组进行读取.
		fr = new FileReader("FileWriterDemo.txt");
		// 定义一个字符数组,用于存储读取到的字符
		// 该read(char[])返回的是读到的字符个数
		char[] ch = new char[1024];
		int num = 0;
		while ((num = fr.read(ch)) != -1) {
			System.out.println(new String(ch, 0, num));
		}
综合使用字符输出输出流:
// 从一个文件中读取出里面所有数据,然后写入另一个文件中
		FileReader fr = new FileReader("demo.txt");
		FileWriter fw = new FileWriter("demo2.txt");
		char[] buf = new char[1024];
		int len = 0;
		while ((len = fr.read(buf)) != -1) {
			fw.write(new String(buf, 0, len));
		}
		fw.close();
		fr.close();
为了提高对流的操作效率,使用了字符的缓冲区。
原理:其实就是将数组进行封装。在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,所以在建立缓冲区对象时,要先有流对象存在。
字符流分别提供了两个类:BufferedReader:带缓冲区的字符输入流;BufferedWriter:带缓冲区的字符输出流。
这时我们可以对上面这个例子进行带缓冲的改造,从而提高操作效率:

其中:

readLine()方法的原理:

其实缓冲区中的该方法,用的还是与缓冲区关联的流对象的read方法。只不过,每一次读到一个字符,先不进行具体操作,先进行临时存储。当读取到回车标记时,将临时容器中存储的数据一次性返回

注意:带缓冲区的输出流需要刷新,其实在close()时就会刷新缓冲区,但是当输出比较大的数据时,有可能缓冲区大小不够这时就需要刷新否则缓冲区的内容将会被覆盖
3、字节流OutputStream/InputStream
字节流和字符流操作基本上都一致下面拿一个复制MP3的例子来说明:
// 复制方法1:
	public static void copy_1() throws IOException {
		FileInputStream fis = new FileInputStream("D:\\0.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\1.mp3");
		byte[] buf = new byte[1024];
		int len = 0;
		while ((len = fis.read(buf)) != -1) {
			fos.write(buf, 0, len);
		}
		fos.close();
		fis.close();
	}

	// 方法2:已经用了缓冲流就不用再用缓冲区byte[] buf 了
	public static void copy_2() throws IOException {
		FileInputStream fis = new FileInputStream("D:\\0.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\2.mp3");
		BufferedInputStream bufis = new BufferedInputStream(fis);
		BufferedOutputStream bufos = new BufferedOutputStream(fos);
		int ch = 0;
		while ((ch = bufis.read()) != -1) {
			bufos.write(ch);
		}
		bufos.close();
		bufis.close();
	}

	// 方法3: 不建议,fis.available() 把一个文件大小都读进来了,如果文件过大,内存会用完
	public static void copy_3() throws IOException {
		FileInputStream fis = new FileInputStream("D:\\0.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\3.mp3");
		byte[] buf = new byte[fis.available()];
		fis.read(buf);
		fos.write(buf);
		fos.close();
		fis.close();
	}

	// 方法4:读一个写一个,效率很差!
	public static void copy_4() throws IOException {
		FileInputStream fis = new FileInputStream("D:\\0.mp3");
		FileOutputStream fos = new FileOutputStream("D:\\4.mp3");
		int ch = 0;
		while ((ch = fis.read()) != -1) {
			fos.write(ch);
		}
		fos.close();
		fis.close();
	}
其中:字节流可以处理所有类型数据,如图片,mp3,avi。如果是处理纯文本数据,就要优先考虑使用字符流
3、(重点)流操作的基本规律

1.   明确源和目的

源:输入流,Reader、InputStream

目的:输出流,Writer、OutputStream

2.   操作的数据是否是纯文本

是:字符流

不是:字节流

3.   当体系明确后,在明确要使用哪个具体对象

通过设备来区分:

源设备:内存,硬盘,键盘

目的设备:内存,硬盘,控制台

范例 . 将键盘录入的数据保存到一个文件中 .
  源 :输入流,Reader、InputStream
 是不是纯文本 ?    是! 用Reader

  设备:键盘,对应的对象是System.in

  不是选择Reader? System.in对应的不是字节流InputStream?

  为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的.所以既然明确了Reader,那么就将System.in转成Reader.

 Reader体系中的读取转换流InputStreamReader

  是否需要提高效率用到Reader体系中的BufferedReader.

  InputStream in = System.in;

  InputStreamReader isr = new InputStreamReader(in);

  BufferedReader br = new BufferedReader(isr);


 目的:输出流,Writer、OutputStream

 是不是纯文本! 用Writer

  设备:硬盘,txt文件.使用FileWriter

  是否需要提高效率用到Writer体系中的BufferedWriter

   FileWriter fw = new FileWriter("xxx.txt");

   BufferedWriter bw = new BufferedWriter(fw);

4、流操作的基本规律

Reader和Writer各有一个子类:

                         |--InputStreamReader:读取转换流

                         |--OutputStreamWriter:写入转换流

(1) InputStreamReader: 读取转换流

字节流读取的时候用的是一个一个字节的读取方式或者是字节数组的读取方式,

字符流中读取的时候,除了有一个一个字符的读取方式和数组 的读取 方式外 ,在缓冲技术里面有一行一行的读取,这个方法在读取的时候很好用也很方便,那么我们就可以把字节流的转换成字符流,然后利用缓冲对象来使用读取一行的方法。

(2) OutputStreamWriter: 读取转换流
     OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的charset 将要写入流中的字符编码成字节
代码:
public static void main(String[] args) throws IOException {
		// 获取键盘录入对象
		// InputStream in = System.in;
		// 将字节流对象转成字符流对象,使用转换流InputStreamReader
		// InputStreamReader isr = new InputStreamReader(in);
		// 为了提高效率,将字符串进行缓冲区技术高效操作.使用BufferedReader
		// BufferedReader br = new BufferedReader(isr);
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
				System.out));

		String s = null;
		while ((s = br.readLine()) != null) {
			if (s.equals("over"))
				break;
			bw.write(s);
			bw.newLine();
			bw.flush();
		}
	}
当想要把录入的数据按照指定的编码表 (utf-8) 将数据存储到文件中 ,而指定的表码表只有转换流可以指定。
OutputStreamWriter(OutputStream out,String charsetName)
个人理解:通常涉及到字符编码转换时 ,需要用到转换流
public static void main(String[] args) throws IOException {
		// 源
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		FileOutputStream fos = new FileOutputStream("demo.txt");
		// 默认的编码是jbk,这时指定编码为UTF-8
		OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
		BufferedWriter bw = new BufferedWriter(osw);

		String s = null;
		while ((s = br.readLine()) != null) {
			if (s.equals("over"))
				break;
			bw.write(s);
			bw.newLine();
			bw.flush();
		}
	}

5、IO异常处理方式
以例子说明:
public static void main(String[] args) {
		// 建立并初始化流
		FileReader fr = null;
		try {
			fr = new FileReader("demo.txt");
			// 定义一个字符数组,用于存储读取到的字符
			// 该read(char[])返回的是读到的字符个数
			char[] ch = new char[1024];
			int num = 0;
			while ((num = fr.read(ch)) != -1) {
				System.out.println(new String(ch, 0, num));
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally {
			try {
				/*
				 * 防止出现null异常,先判断fw是否为null,当还有其他流时, 
				 * 也应该像这样try_catch,再关闭流
				 */
				if (fr != null)
					fr.close();
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		}
	}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值