Java基础学习之IO流的字符流和缓冲流

一:流的含义

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。

 以参照物来衡量是输入还是输出

  流的参照物(程序)

  输出流

  程序  --->  文件(写文件使用输出流) 输出

  输入流

  文件  --->  程序(读文件使用输入流) 

首先我们来看字节流: 

字节流: 以字节为单位进行数据传输;

OutputStream(字节输出流)

InputStream (字节输入流)

以上两个类 是所有字节流的父类 并且是抽象类

写文件

public static void main(String[] args) {
	//fun1();
		
		//异常处理
		File file = new File("/Users/lanou/Desktop/afd/mingwei.txt");
		//创建一个空的引用(扩大作用域)
		FileOutputStream fos = null;
		
		try {
		  fos = new FileOutputStream(file);
			fos.write("haha".getBytes());
		} catch (FileNotFoundException e) {
			//文件找不到;再向下操作无意义
			//停止程序 让程序员修改代码
			//抛运行时异常 提示信息 停止程序;
			throw new RuntimeException("文件找不到");
		} catch (IOException e) {
			// 写入失败
			throw new RuntimeException("写入失败");
		}finally {
			
			//非空判断 fos创建成功时关闭
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭失败");
				}
			}
			//关闭资源时一定要确保关闭的代码可以执行.
			
		}
		
		
		
	}
public static void fun1() throws FileNotFoundException, IOException {
		File file = new File("/Users/lanou/Desktop/afd/mingwei.txt");
		//给输出流绑定一个输出文件
		//给出的路径 可以没有该文件(系统会帮忙创建出来)
			//创建 文件字节输出流
			FileOutputStream fos = new FileOutputStream(file);
			//写文件
			//注意:流这块 全是抛的IOException
			//传入int值得方法 是按ASCII码
			//并且一次写入一个字节
			fos.write(99);
			fos.write(48);
			fos.write(49);
			fos.write(65);
			fos.write(43);
			//创建一个字节数组
			//直接写字符串  
			//1.字符串转字节数组   getBytes();
			//2.字节数组转字符串  用的是构造方法
			fos.write("dahai".getBytes());
			byte [] b = {66,67,68,69};
			fos.write(b);
			//偏移量
			fos.write(b, 1, 2);
			//关闭资源
			fos.close();
	}

文件的写入有两种方式:

1.直接以字节一个一个的写入

2.以一个字节数组做缓冲 ,写入时以字节数组为单位.

读文件

public static void fun1() throws FileNotFoundException, IOException {
		File file = new File("/Users/lanou/Desktop/afd/mingwei.txt");
		FileInputStream fis = new FileInputStream(file);
		//读文件
		int num= fis.read();
		System.out.println((char)num);
		num = fis.read();
		System.out.println((char)num);
		num = fis.read();
		System.out.println((char)num);
		num = fis.read();
		System.out.println((char)num);
		num = fis.read();
		System.out.println((char)num);
		num = fis.read();
		//如果读取到文件没有字符了返回-1;
		System.out.println(num);
		//关闭资源
		fis.close();
	}

由上面的例子我们得知当返回-1的时候我们的文件已经读完了,所以要完整的读取一个文件,我们使用循环的停止条件是 .read()返回-1时.如此看下面一个例子

public static void fun2() throws FileNotFoundException, IOException {
		File file = new File("/Users/lanou/Desktop/afd/mingwei.txt");
		FileInputStream fis = new FileInputStream(file);
		//循环读取(一次只能读一个字节)
		int num = 0;
		
		while ((num= fis.read())!=-1) { 
			System.out.println((char)num);	
		}
		fis.close();
	}

文件的复制和续写:

对文件 进行读写(边读编写) 写完之后关闭输入流 关闭输出流.

续写:
public static void fun1() throws FileNotFoundException, IOException {
		File file = new File("/Users/lanou/Desktop/afd/xuxie.txt");
		//利用构造方法的参数进行续写(布尔参数)
		//Mac换行 \n
		//window换行 \r\n
		OutputStream oS= new FileOutputStream(file,true);
		oS.write("wanglong\n".getBytes());
		oS.close();
	}

文件的续写是由输出流的构造方法的参数决定. Boolean append 

默认为false 写入的覆盖 参数为true时 可以以append 的方式添加文件.

复制

		
		//fun1();
		//字节流 进行文件的复制(又叫万能流)
		//不但可以写文本 图片音频 视频....
		//使用字节流 进行文件的复制(需要异常处理 并计算两种读写方式的时间)
		//对文件 进行读写(边读编写)
		
		//计算复制时间
		long start = System.currentTimeMillis();
		 File src = new File("/Users/lanou/Desktop/afd/001.jpg"); 
		 File dex = new File("/Users/lanou/Desktop/afd/1000.jpg");
		 
		 OutputStream os=null;
		 InputStream is =null;
		 int n = 0;
		 byte [] b = new byte[1024];
		 try {
			os = new FileOutputStream(dex);
			is = new FileInputStream(src);
			 while ((n=is.read(b))!=-1) {
					// 写文件
					os.write(b, 0, n);
				}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件找不到");
			
		}catch (IOException e) {
			throw new RuntimeException("读写失败");
		}finally {
			if (src!=null) {
				try {
					os.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭失败");
					
				}finally {
					try {
						is.close();
					} catch (IOException e) {
						throw new RuntimeException("关闭失败");
					}
				}
				
			}
		}
	   //结束时间
		 long stop = System.currentTimeMillis();
		 System.out.println(stop-start);
	

 将一个文件夹 复制 到另一个文件夹下:


	public static void main(String[] args) throws IOException {
		File src = new File("/Users/lanou/Desktop/afd/a");
		File dest = new File("/Users/lanou/Desktop/afd/c");
		copyDir(src, dest);
		
	}
	public static void copyDir(File src ,File dest) throws IOException {
		//去目标文件下创建一个文件夹下来
		//新文件夹的名字是源文件夹的名字 ;路径是目标文件的名字
			File newFile = new File(dest, src.getName());
			newFile.mkdir();
		//遍历所有文件
		File[] files = src.listFiles();
		for (File subFile : files) {
			if (subFile.isFile()) {
				//读写
				FileInputStream fis = new FileInputStream(subFile);
				//创建一个要写入的文件,需要拼接文件名字
				File tempFile = new File(newFile, subFile.getName());
				FileOutputStream fos = new FileOutputStream(tempFile);
				int len= 0;
				byte [] b = new byte[1024];
				while ((len=fis.read(b))!=-1) {
					fos.write(b, 0, len);
				}
				
			}else {
				//文件夹继续遍历
				copyDir(subFile, newFile);
			}
		}	
	}

//过滤器
class TxtFile implements FileFilter{

	@Override
	public boolean accept(File pathname) {
		//放行文件夹
		if (pathname.isDirectory()) {
			return true;
		}
		return pathname.getName().endsWith("txt");
	}
	
}
通过过滤器可以将文件夹下的文件以过滤后的数据复制到新的文件夹下.

接下来我们看下字符流:

基本编码格式.

 MAC 默认使用 UTF-8格式(通用编码格式)

   一个中文占3个字节

 window 默认使用 GBK 格式(简体中文格式)

  一个中文占2个字节

字符流:只对文本文件操作

字符流的两个抽象父类

  Writer  写文件 字符输出流  --->FileWriter

  Reader  读文件 字符输入流  --->FileReader


字节流 进行文件的复制(又叫万能流) 基本上可以操作所有类型的文件

看下字符流的读写方法:
public static void main(String[] args) throws IOException {
		//创建一个文件字符输出流
		File file = new File("/Users/lanou/Desktop/afd/dongdong.txt");
		FileWriter fw = new FileWriter(file);
		fw.write(65);
		fw.flush();
		//写入字符数组
		char [] c = {'x','s','e','w'};
		fw.write(Arrays.toString(c)+"\n");
		//常用 :利用字符串写入
		fw.write("一本小黄书\n");
		fw.write("一撸一下午\n");
		
		//刷新方法 
		//相当于写入的时候有个缓冲区;
		//写的字符实际上是先写入缓冲区;
		//刷新时 才会将写的字符全部写入到目标文件中
		//建议,写一次刷新一次
		fw.flush();
		//关闭流资源之前会自动刷新缓冲区
		fw.close();
	}
public static void main(String[] args) throws IOException {
		//读取文件两种方式
		//单个字符读
		File file = new File("/Users/lanou/Desktop/afd/dongdong.txt");
		FileReader fr = new FileReader(file);
		/*int num = 0;
		while ((num=fr.read())!=-1) {
			System.out.println((char)num);
		}*/
		//利用缓冲数组读
		int len = 0;
		char [] c =new char[1024];
		while ((len=fr.read(c))!=-1) {
			//字符数组转字符串
			System.out.println(new String(c, 0, len));
		}
		
		fr.close();
	}
可以看到的出与字节流的操作基本一样.

转换流

OutputStreamWriter(字符流转向字节流的桥梁)

可以查询对应的编码表

1.程序中写入字符时 先使用转化流 根据转换流想查询码表格式去查询

2.如果查的是GBK格式 那么一个中文字符就查到了两个字节的 字节编码

3.这个字节最后给盗了 构建转换流是 传入的字节流

4.通过这个字节流 按字节写入到文件中


默认UTF-8格式写文件拿到Windows系统上读取

  Windows会默认使用GBK读取文件,造成乱码.

  转换流可以根据你想要的编码格式读写.  读写时可以设置编码格式

  

  构造方法(不传编码格式,默认使用系统的编码格式)

  1.需要一个字节输出流

  2.编码格式的名字 UTF-8 GBK  不区分大小写

  

  InputStreamReader (读取文件 字节流通向字符流的桥梁)

  1.按字节读取文件 将字节编码给到装换流

  2.如果UTF-8需要3个字节

  3.使用字符流读取到程序中

  

  转换流与其子类有什么区别

  子类(FileWriter/FileReader)

  只能以默认的字符编码格式

  父类可以设置编码格式

	public static void main(String[] args) throws IOException {
		//测试
		getUTF8();
		getGBK();
		readByUTF8();
		readByGBK();
	}
	
	//按操作系统默认格式(UTF-8) 写一个文件
	public static void getUTF8() throws IOException {
		//创建一个字节输出流
		FileOutputStream fos = new FileOutputStream("/Users/lanou/Desktop/afd/UTF8.txt");
		//创建一个转换流 
		OutputStreamWriter osw = new OutputStreamWriter(fos);
		osw.write("刘冰");
		//注意:1.一般只关外层的流就可以
		//2.自己创建的流自己关.系统创建的系统自己关.
		osw.close();
	
	}
   //按GBK 格式写入文件 
	public static void getGBK() throws IOException {
		FileOutputStream fos = new FileOutputStream("/Users/lanou/Desktop/afd/GBK.txt");
		OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
		osw.write("刘冰");
		osw.close();
	}
	//按操作系统默认格式(UTF-8) 读一个文件
	public static void readByUTF8() throws IOException {
		FileInputStream fis = new FileInputStream("/Users/lanou/Desktop/afd/GBK.txt");
		InputStreamReader isr = new InputStreamReader(fis);
		int n = 0;
		char [] c = new char[1024];
		while ((n=isr.read(c))!=-1) {
			System.out.println(new String(c, 0, n));
		}
		isr.close();
	}

	 //按GBK 格式读文件 
	public static void readByGBK() throws IOException {
		FileInputStream fis = new FileInputStream("/Users/lanou/Desktop/afd/UTF8.txt");
		InputStreamReader isr = new InputStreamReader(fis, "gbk");
		int n = 0;
		char [] c = new char[1024];
		while ((n=isr.read(c))!=-1) {
			System.out.println(new String(c, 0, n));
		}
		isr.close();
	}

缓冲流(高效流)

 内部自带一个缓冲区(字节数组)

  BufferedOutputStream(写文件) 缓冲字节输出流

  BufferedInputStream(读文件) 缓冲字节输入流

	public static void main(String[] args) throws IOException {
		//思考如何验证缓冲流的高效
		fun1();
		FileInputStream fis = new FileInputStream("/Users/lanou/Desktop/afd/GUIfen.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();
	}

	public static void fun1() throws FileNotFoundException, IOException {
		//构建一个缓冲流写文件
		FileOutputStream fos = new FileOutputStream("/Users/lanou/Desktop/afd/GUIfen.txt");
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		bos.write("hellow".getBytes());
		bos.close();
	}

缓冲流可以提升文件的传输效率

public class Demo09测试缓冲流 {
	public static void main(String[] args) throws IOException {
//	  new CopyA().test();
	  new CopyB().test();
	}

	
}
//模板类计算时间
 abstract class Testbuff{
	 //声明复制文件路径成员变量 
	 public String src = "/Users/lanou/Desktop/afd/头号玩家_bd.mp4";
	 public String dest = "/Users/lanou/Desktop/afd/thwj2.mp4";
	 //计算程序时间的方法
	public void test() throws IOException {
		long timeMillisOne = System.currentTimeMillis();
		copyFile();
		long timeMillisTwo = System.currentTimeMillis();
		System.out.println(timeMillisTwo-timeMillisOne);
	}
	//抽象方法
	//注意:异常在继承中的使用
	abstract void copyFile() throws IOException;
 }
 
 //计算文件字节流复制测试
 class CopyA extends Testbuff{

	@Override
	void copyFile() throws IOException {
		//一个一个读
		FileInputStream fis = new FileInputStream(src);
		FileOutputStream fos = new FileOutputStream(dest);
		int num =  0;
		byte [] b = new byte[1024*1024];
		while ((num=fis.read(b))!=-1) {
			fos.write(b, 0, num);
		}
		fos.close();
		fis.close();
	}
	 
 }
 //测试缓冲流
 class CopyB extends Testbuff{

	@Override
	void copyFile() throws IOException {
		
		FileInputStream fis = new FileInputStream(src);
		FileOutputStream fos = new FileOutputStream(dest);
		
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int num =  0;
		byte [] b = new byte[1024*1024];
		while ((num=bis.read(b))!=-1) {
			bos.write(b, 0, num);
		}
		bos.close();
		bis.close();
	}
	 
 }
上面的例子我们可以 看出缓冲流的高效性.

* "Success is the constant experience of failure and always keeping the initial enthusiasm"
 	把上列字符串以下列形式写入文件
 	Success=1
 	is=1
 	the=2
 	…..
 */
public class Demo10 {
	public static void main(String[] args) throws IOException {
		File file = new File("/Users/lanou/Desktop/afd/lainxi.txt");
		FileWriter fw = new FileWriter(file);
		String str = "Success is the constant experience of failure and always keeping the initial enthusiasm";
		String[] split = str.split(" ");
		System.out.println(Arrays.toString(split));
		HashMap<String, Integer> map = new HashMap<>();
		
		
		for (int i = 0; i < split.length; i++) {
			if (!map.containsKey(split[i])) {
				map.put(split[i], 1);
			}else {
				Integer integer = map.get(split[i]);
				integer++;
				map.put(split[i], integer);
			}
		}
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		System.out.println(entrySet);
	 
	 for (String key : map.keySet()) {
		String string = key+"="+map.get(key);
		 fw.write(string+"\n");
		}
 	 
		fw.close();
	
	}
 
}





猜你喜欢

转载自blog.csdn.net/vlin_fan/article/details/80500726