Java学习IO流

Posted 低调的小孩儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习IO流相关的知识,希望对你有一定的参考价值。

 

字节流复制文件

原理:读取一个已有的数据,并将这些读取到的数据写到另一个文件中

字节流通过单字节复制字节数组赋值

package com.oracle.demo01;

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

public class CopyDemo {
	public static void main(String[] args) throws IOException {
		//CopyDemo();
		Copy_2();
	}
    //字节流复制文件
	// 用字节去复制文件
	public static void CopyDemo() throws IOException {
		// 运行前获取系统毫秒值
		long s = System.currentTimeMillis();
		// 数据源 往Java程序中读数据
		FileInputStream fis = new FileInputStream("e:\\\\test\\\\a.jpg");
		// 目的地 从Java程序中往目的地复制,写入
		FileOutputStream fos = new FileOutputStream("e:\\\\test\\\\a\\\\a.jpg");
		// 先获取数据源信息read()
		int len = 0;
		while ((len = fis.read()) != -1) {
			// 读取一个字节,就往目的地写入一个字节
			fos.write(len);
		}
		fis.close();
		fos.close();
		// 运行后获取系统毫秒值
		long v = System.currentTimeMillis();
		// 获取运行的时间
		System.out.println(v - s);
	}

	// 用字节数组去复制文件
	public static void Copy_2() throws IOException {
		long s = System.currentTimeMillis();
		FileInputStream fis = new FileInputStream("e:\\\\test\\\\src.zip");
		// 目的地 从Java程序中往目的地复制,写入
		FileOutputStream fos = new FileOutputStream("e:\\\\test\\\\a\\\\src.zip");
		// 先获取数据源信息read()
		int len = 0;
		byte[] b = new byte[1024*1024];
		while ((len = fis.read(b)) != -1) {
			fos.write(b, 0, len);
		}
		fis.close();
		fos.close();
		long v = System.currentTimeMillis();
		System.out.println(v - s);
	}
}

字符流

通过字节流可以对数据进行读写操作,但是一旦数据中出现中文,就需要用到字符流通过字符编码表对数据进行编码与解码

编码表:其实就是生活中字符和计算机二进制的对应关系表。

           1ascii: 一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx

           2iso-8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx  负数。

           3GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节第一个字节是负数,第二个字节可能是正数

                 GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0

                GB18030:最新的中文码表,目前还没有正式使用。

          4、unicode:国际标准码表:无论是什么文字,都用两个字节存储。

                Java中的char类型用的就是这个码表。char c = \'a\';占两个字节。

               Java中的字符串是按照系统默认码表来解析的。简体中文版 字符串默认的码表是GBK。

         5UTF-8:基于unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)

         能识别中文的码表:GBKUTF-8;正因为识别中文码表不唯一,涉及到了编码解码问题。

对于我们开发而言;常见的编码 GBK  UTF-8  ISO-8859-1

文字--->(数字) :编码 “abc”.getBytes()  byte[]

(数字)--->文字  : 解码 byte[] b={97,98,99}  new String(b) 

字符输入流Reader

Reader,读取字符流的抽象超类

常用方法:

l read():读取单个字符并返回

l read(char[]):将数据读取到数组中,并返回读取的个数。

 Reader类之FileReader子类

构造方法:

字符输出流Writer

Writer是写入字符流的超类

常用的方法:

Writer类之FileWriter子类

构造方法:

package com.oracle.demo01;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/*
 * 字符流,专门针对于文本文件
 * 文本文件:就是用记事本打开这个文件,你能看懂的就叫文本文件
 * 除了文本文件,你都可以用字节流
 * 
 * 区分字节流和字符流
 * 类名中带reader和writer都是字符流
 * 类名中带Stream的都是字节流
 * */
public class WriteDemo {
	public static void main(String[] args) throws IOException {
		// read();
		// read2();
		// writer();
		copy();
	}

	public static void read() throws IOException {
		FileReader fr = new FileReader("e:\\\\test\\\\wenjian.txt");
		int len = 0;
		// read()方法一次只能读一个字符,读到末尾就返回-1
		while ((len = fr.read()) != -1) {
			System.out.print((char) len);
		}
		fr.close();
	}

	public static void read2() throws IOException {
		FileReader fr = new FileReader("e:\\\\test\\\\wenjian.txt");
		int len = 0;
		char[] ch = new char[1024];
		while ((len = fr.read(ch)) != -1) {
			System.out.print(new String(ch, 0, len));
		}
		fr.close();
	}

	public static void writer() throws IOException {
		FileWriter fw = new FileWriter("e:\\\\test\\\\wenjian.txt", true);
		// writer(int a)
		fw.write(100);
		fw.flush();// 刷新,调用write方法后,要刷新才能把字符刷进去
		fw.write("HelloWorld");
		fw.flush();// 刷新后,流还可以继续使用
		char[] ch = { \'L\', \'o\', \'v\', \'e\', \'j\' };
		fw.write(ch);
		fw.close();// 具有刷新一次的功能,然后再关闭
	}

	public static void copy() throws IOException {
		// 数据源 读取数据到Java程序
		FileReader fr = new FileReader("e:\\\\test\\\\wenjian.txt");
		// 目的地 从Java程序写入目的地
		FileWriter fw = new FileWriter("e:\\\\test\\\\a\\\\wenjian.txt");
		int len = 0;
		char[] ch = new char[1024];
		while ((len = fr.read(ch)) != -1) {
			fw.write(ch, 0, len);
			fw.flush();
		}
		fr.close();
		fw.close();
	}
}

flush()close()的区别

flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用

close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。

转换流

字符流对应的有字符编码表,当需要指定编码格式和缓冲区大小时,就需要用到转换流InputStreamReader或者OutputStreamWriter

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节

它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去

 

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符

它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

package com.oracle.demo02;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class OutputStreamWriterDemo {
	public static void main(String[] args) throws IOException {
		method2();
	}

	// 转换流的输出流
	public static void method() throws IOException {
		FileOutputStream fos = new FileOutputStream("e:\\\\test\\\\d.txt",true);
		OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
		osw.write("你好");
		// 关闭流的时候,只要关闭最外一层就好了
		osw.close();
	}
	//转换流的输入流
	public static void method2() throws IOException{
		FileInputStream fis=new FileInputStream("e:\\\\test\\\\d.txt");
		InputStreamReader isr=new InputStreamReader(fis,"GBK");
		char[] ch=new char[1024];
		int len=0;
		while((len=isr.read(ch))!=-1){
			System.out.println(new String(ch,0,len));
		}
		isr.close();
	}
}

OutputStreamWriter流对象,它到底如何把字符转成字节输出的呢?

   其实在OutputStreamWriter流中会有自己的缓冲区,当我们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。

 转换流和子类的区别

发现有如下继承关系:

OutputStreamWriter:

|--FileWriter:

InputStreamReader:

|--FileReader;

父类和子类的功能有什么区别呢?

OutputStreamWriterInputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流+编码表

FileWriterFileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。

FileReader fr = new FileReader("a.txt");

这三句代码的功能是一样的,其中第三句最为便捷。

注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。什么时候用子类呢?

条件:

1、操作的是文件。2、使用默认编码。

总结:

字节--->字符 : 看不懂的--->看的懂的。  需要读。输入流。 InputStreamReader

字符--->字节 : 看的懂的--->看不懂的。  需要写。输出流。 OutputStreamWriter

 缓冲流

 缓冲流的存在就是为了读取大量的数据

字节缓冲流

1、写入数据到流中,字节缓冲输出流 BufferedOutputStream

2、读取流中的数据,字节缓冲输入流 BufferedInputStream

 它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度

字节缓冲输出流BufferedOutputStream

构造方法

public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

字节缓冲输入流BufferedInputStream

构造方法

public BufferedInputStream(InputStream in)创建一个新的缓冲输入流,读取流中的数据

package com.oracle.demo03;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferDemo {
	public static void main(String[] args) throws IOException {
		read();
	}

	public static void write() throws IOException {
		long s = System.currentTimeMillis();
		// 字节输出流
		FileOutputStream fos = new FileOutputStream("e:\\\\test\\\\java.txt");
		// 缓冲字节输出流
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		bos.write(100);
		bos.close();
		long a = System.currentTimeMillis();
		System.out.println(a - s);
	}

	public static void read() throws IOException {
		long s = System.currentTimeMillis();
		// 字节输出流
		FileInputStream fis = new FileInputStream("e:\\\\test\\\\java.txt");
		// 缓冲字节输出流
		BufferedInputStream bis = new BufferedInputStream(fis);
		int len = 0;
		byte[] b = new byte[1024];
		while ((len = bis.read(b)) != -1) {
			System.out.println(new String(b, 0, len));
		}
		bis.close();
		long a = System.currentTimeMillis();
		System.out.println(a - s);
	}
}

 使用四种方式复制文件

package com.oracle.demo03;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo {
	public static void main(String[] args) throws IOException {
		// 数据源
		FileInputStream fis = new FileInputStream("d:\\\\eclipse.zip");
		// 目的地
		FileOutputStream fos = new FileOutputStream("e:\\\\test\\\\eclipse.zip");
		//copy1(fis, fos);
		//copy2(fis, fos);
		//copy3(fis, fos);
		copy4(fis, fos);

	}

	// 单个字节的复制
	public static void copy1(FileInputStream fis, FileOutputStream fos) throws IOException {
		long s = System.currentTimeMillis();
		// 获取数据
		int len = 0;
		while ((len = fis.read()) != -1) {
			fos.write(len);
		}
		fis.close();
		fos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}

	// 字节数组的复制
	public static void copy2(FileInputStream fis, FileOutputStream fos) throws IOException {
		long s = System.currentTimeMillis();
		int len = 0;
		byte[] b = new byte[1024];
		while ((len = fis.read(b)) != -1) {
			fos.write(b, 0, len);
		}
		fis.close();
		fos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}

	// 字节缓冲流
	public static void copy3(FileInputStream fis, FileOutputStream fos) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		long s = System.currentTimeMillis();
		int len = 0;
		while ((len = bis.read()) != -1) {
			bos.write(len);
			bos.flush();
		}
		bis.close();
		bos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}
    //字节数组缓冲流
	public static void copy4(FileInputStream fis, FileOutputStream fos) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		long s = System.currentTimeMillis();
		int len = 0;
		byte[] b = new byte[1024 * 1024];
		while ((len = bis.read(b)) != -1) {
			bos.write(b, 0, len);
			bos.flush();
		}
		bis.close();
		bos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}
}

字符缓冲流

1、 字符缓冲输入流 BufferedReader

2、字符缓冲输出流 BufferedWriter

完成文本数据的高效的写入与读取的操作

 字符缓冲输入流BufferedReader

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

方法:void newLine() 根据当前的系统,写入一个换行符

 字符缓冲输出流BufferedWriter

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

方法:public String readLine() 读取一个文本行包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

/*
 * BufferedReader 字符缓冲输入流
 * 
 * 方法:
 * 	String readLine() 
 * 需求:从文件中读取数据,并显示数据
 */
public class BufferedReaderDemo {
	public static void main(String[] args) throws IOException {
		//1,创建流
		BufferedReader in = new BufferedReader(new FileReader("file.txt"));
		//2,读数据
		//一次一个字符
		//一次一个字符数组
		//一次读取文本中一行的字符串内容
		String line = null;
		while( (line = in.readLine()) != null ){
			System.out.println(line);
		}
		
		//3,关闭流
		in.close();
	}
}

使用字符缓冲流进行文本文件的复制

package com.oracle.demo03;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo02 {
	public static void main(String[] args) throws IOException {
		copy4();

	}

	public static void copy1() throws IOException {
		// 数据源
		FileReader fr = new FileReader("d:\\\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\\\test\\\\eclipse.zip");
		int len = 0;
		while ((len = fr.read()) != -1) {
			fw.write(len);
			fw.flush();
		}
		fw.close();
		fr.close();
	}

	public static void copy2() throws IOException {
		// 数据源
		FileReader fr = new FileReader("d:\\\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\\\test\\\\eclipse.zip");
		int len = 0;
		char[] ch = new char[1024 * 1024];
		while ((len = fr.read(ch)) != -1) {
			fw.write(ch, 0, len);
			fw.flush();
		}
		fw.close();
		fr.close();
	}

	public static void copy3() throws IOException {
		// 数据源
		FileReader fr = new FileReader("d:\\\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\\\test\\\\eclipse.zip");
		BufferedReader br = new BufferedReader(fr);
		BufferedWriter bw = new BufferedWriter(fw);
		int len = 0;
		while ((len = br.read()) != -1) {
			bw.write(len);
			bw.flush();
		}
		bw.close();
		br.close();
	}

	public static void copy4() throws IOException {
		long s = System.currentTimeMillis();
		// 数据源
		FileReader fr = new FileReader("d:\\\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\\\test\\\\eclipse.zip");
		BufferedReader br = new BufferedReader(fr);
		BufferedWriter bw = new BufferedWriter(fw);
		// int len = 0;
		// char[] ch = new char[1024 * 1024];
		// while ((len = br.read(ch)) != -1) {
		// bw.write(ch, 0, len);
		// bw.flush();
		// }

		String len = null;
		while ((len = br.readLine()) != null) {
			bw.write(len);
			bw.flush();
		}
		bw.close();
		br.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}
}

流的操作规律

IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?  

IO流进行了规律的总结(四个明确)

l 明确一:要操作的数据是数据源还是数据目的。

源:InputStream    Reader

目的:OutputStream Writer

先根据需求明确要读,还是要写。

l 明确二:要操作的数据是字节还是文本呢?

源:

字节:InputStream

文本:Reader

目的:

字节:OutputStream

文本:Writer

已经明确到了具体的体系上。

l 明确三:明确数据所在的具体设备。

源设备:

硬盘:文件  File开头。

内存:数组,字符串。

键盘:System.in;

网络:Socket

目的设备:

硬盘:文件  File开头。

内存:数组,字符串。

屏幕:System.out

网络:Socket

完全可以明确具体要使用哪个流对象。

l 明确四:是否需要额外功能呢?

额外功能:

转换吗?转换流。InputStreamReader OutputStreamWriter

高效吗?缓冲区对象。BufferedXXX

     InputStream

       FileInputStream

       BufferedInputStream 

OuputStream

   FileOutputStream

   BufferedOuputStream

Writer

  OutputStreamWriter

     FileWriter

      BufferedWriter

Reader

  InputStreamReader

     FileReader

 BufferedReader

以上是关于Java学习IO流的主要内容,如果未能解决你的问题,请参考以下文章

Java IO流基础总结

Java-IO流学习

java IO流学习总结

Java 学习笔记 - IO篇:常见的IO流Stream以及相互关系

Java IO流学习

Java学习17(IO流)