文件流与缓冲流

流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或者抽象,即 数据在两设备之间的传输称为流.

流的本质就是"数据传输",根据数据传输的特性将流抽象成各种类,可以对数据进行各种操作

流的分类:
1.按照流向分:
输入流和输出流,对于输入流只能进行读的操作,对于输出流只能进行写的操作.
2.按照流的类型分:
字节流:可以操作任何数据,因为在基三集中任何数据都是以字节形式存储的,字节流的抽象父类为InputStream,OutputStream
字符流:字符流只能操作字符数据,一次可以读取多个字节,字符流的抽象父类为Reader和Writer

FileInputStream类

  1. 它是InputStream的子类,可以用于操作文件
    常用构造方法:
    public FileInputStream(String name);
    //通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
    public FileInputStream(File file);
    //通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定
public static void main(String[] args) throws Exception {
     
		// 使用File对象构造输入流对象
		File f = new File("xxx.txt");
		f.createNewFile();
		// 生成一个输入流,只能为读取操作
		FileInputStream fis = new FileInputStream("xxx.txt");
		
		int content;// 用于判断写入字符是否为-1
		while ((content = fis.read()) != -1) {
     
			System.out.println((char) content);// 读取xxx.txt里面内容
			// int y = fis.read();
			// int z = fis.read();
			// int x = fis.read();
			// System.out.println((char)y);
			// System.out.println((char)z);
			// System.out.println((char)x);
			// 建立一个文件输出流,只能为写入操作	
		}
	// 注意:
		// 输出流在写出数据时,会先清空文件,再写入
		// 如果需要追加,可以使用下面的构造方法
		FileOutputStream fos1 = new FileOutputStream("xxx.txt");
		fos1.write(100); //FileOutputStream在创建对象的时候是如果没有这个文件会帮我创建出来,如果有这个文件就会先将文件清空
		FileOutputStream fos = new FileOutputStream("xxx.txt", true);// //如果想续写就在第二个参数传true
		fos.write(101);
		fis.close();  
	    fos.close();
	} 

FileOutputStream类

文件输出流,用于将文件内容写出

注意:输出流在写出数据时,会先清空文件,再写入,因此,如果想往后追加而不清空源文件内容,就使用以下构造方法
FileOutputStream fos = new FileOutputStream("xxx.txt", true);// //如果想续写就在第二个参数传true
//复制图片public static void main(String[] args) throws Exception {
     

		//FileInputStream fis = new FileInputStream("D:\\材料\\1.jpg");
		//注意,不要去资源管理器中复制路径,windows上会报错,因为编码问题
		FileInputStream fis = new FileInputStream("D:\\材料\\1.jpg");
		FileOutputStream fos = new FileOutputStream("副本.jpg");
		int content;
		while ((content = fis.read()) != -1) {
     
			fos.write(content);
		}
		fis.close();
		fos.close();
	}




//复制mp4格式视频
public static void main(String[] args) throws Exception {
     
		FileInputStream fis = new FileInputStream("D:\\材料\\年少有为.mp4");
		FileOutputStream fos = new FileOutputStream("D:\\材料\\副本.mp4");
		byte[] buf = new byte[1024 * 8];//8k
		int len;
		while ((len = fis.read(buf)) != -1) {
     //如果忘记加buf,返回的就不是读取的字节个数,而是字节的码表值
			fos.write(buf, 0, len);//byte数组,第一个字符,实际长度
		}
		fis.close();
		fos.close();
	}

//用io流中的技术,指定一个文件夹的目录,获取此目录下的所有子文件夹路径
public static void main(String[] args) {
     
		File my = new File("D:" + File.separator);// 操作路径,可以有外部参数决定的
		print(my);
	}

	public static void print(File file) {
     // 递归调用
		if (file != null) {
     // 判断对象是否为空
			if (file.isDirectory()) {
     // 如果是目录
				File f[] = file.listFiles();// 列出全部的文件
				if (f != null) {
     // 判断此目录能否列出
					for (int i = 0; i < f.length; i++) {
     
						print(f[i]);// 因为给的路径有可能是目录,所以,继续判断
					}
				}
			} else {
     
				System.out.println(file);// 输出路径
			}
		}
	}

/*IO流:定义小数组
 write(byte[] b)
 write(byte[] b, int off, int len)写出有效的字节个数
 */
public static void main(String[] args) throws Exception {
     
		File file = new File("b.txt");
		file.createNewFile();
		FileInputStream fis = new FileInputStream("b.txt");
		byte[] arr = new byte[2];// 2的倍数
		int a = fis.read(arr); // 将文件上的字节读取到字节数组中
		System.out.println(a); // 2   读到的有效字节个数
		for (byte b : arr) {
      // 第一次获取到文件上的a和b
			System.out.println(b); // 97 98
		}
		FileOutputStream fos = new FileOutputStream("b.txt",true);
		fos.write(99);
		fis.close();
		fos.close();
	}
	    /*FileInputStream fis = new FileInputStream("xxx.txt");
	    FileOutputStream fos = new FileOutputStream("yyy.txt");
	    byte[] arr = new byte[2];
	    int len;
	    while((len = fis.read(arr)) != -1) {
         fos.write(arr,0,len); //从0开始写len个
	    }
	    fis.close();
	    fos.close();*/

缓冲流

BufferedInputStream 缓冲输入流
BufferedOutputStream 缓冲输出流
它们都是在InputStreamhe OutputStream的基础上实现的包装类,它们两个没有真正的读写功能,读写方法实际上还是调用了InputStream
和OutputStream的方法

public static void main(String[] args) throws IOException {
     
		FileInputStream fis = new FileInputStream("D:/材料/哑巴.mp3"); // 创建输入流对象,关联致青春.mp3
		FileOutputStream fos = new FileOutputStream("D:/材料/copy.mp3"); // 创建输出流对象,关联copy.mp3
		BufferedInputStream bis = new BufferedInputStream(fis); // 创建缓冲区对象,对输入流进行包装让其变得更加强大
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int b;
		while ((b = bis.read()) != -1) {
     //取到得是字节
			bos.write(b);
		}
		bis.close();
        bos.close();
	}
原理:
    缓冲流内置了一个缓冲区,会一次性从文件读取8192个字节,存储在缓冲区中返回一个字节(在内存中效率非常高,对硬盘的访问次数变少了)程序再次读取时
不需要找文件了,直接从缓冲区读取,知道缓冲区所有数据都被使用过,才重新从文件中再次读取8192个字节

刷新缓冲区

刷新缓冲区
  使用缓冲区功能,必须刷新或关闭流,因为在最后一次读取数据时,如果不刷新字节数组,那么读取到的数据就不会写出,可以使flush⽅法解决此问题。
  IO流(flush和close方法的区别)
 flush()方法
     用来刷新缓冲区的,刷新后可以再次写出 
 close()方法
     具备刷新的功能,在关闭流之前,就会先刷新一次缓冲区,将缓冲区的字节全都刷新到文件上,再关闭,close方法刷完之后就不能写了 
ublic static void main(String[] args) throws IOException {
     
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
				"D:/材料/哑巴.mp3"));
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream("D:/材料/copy.mp3"));
		int b;
		while ((b = bis.read()) != -1) {
     
			bos.write(b);
		}
		// bos.flush();将字节数组中的剩余内容写出
		bis.close();
		bos.close();
	}

字节流读取中文的问题

如果使用字节流读取中文,会涉及到编码问题,在输出读到的内容时使用字符串的构造方法会根据平台默认编码进行解码,可能会造成乱码,在复制数据时不会出现这个问题

public static void main(String[] args) throws IOException {
     
		File file = new File("yyy.txt");
		file.createNewFile();
		FileInputStream fis = new FileInputStream("yyy.txt");
		FileOutputStream fos = new FileOutputStream("zzz.txt");
		byte[] arr = new byte[4];//根据编码不同,修改数组大小来测试
		int len;
		while ((len = fis.read(arr)) != -1) {
     
			System.out.println(new String(arr, 0, len));
			//fos.write(buf, 0, len);
		} 
		/*
		 * 字节流写出中文的问题 字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组 写出回车换行
		 * write("\r\n".getBytes());
		 */
		
		fos.write("你傻嘛".getBytes());
		fos.write("\r\n".getBytes());
		fos.close();
		fis.close();
	}

捕获流的异常

public static void main(String[] args) {
     

		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
     
			fis = new FileInputStream("D:\\材料\\年少有为.mp4");
			fos = new FileOutputStream("D:\\材料\\副本.mp4");
			byte[] buf = new byte[1024 * 8];// 8k
			int len;
			while ((len = fis.read(buf)) != -1) {
     // 如果忘记加buf,返回的就不是读取的字节个数,而是字节的码表值
				fos.write(buf, 0, len);// byte数组,第一个字符,实际长度
			}
		} catch (Exception e) {
     
			e.printStackTrace();
		} finally {
     
			try {
     
				if (fis != null)
					fis.close();
				if (fos != null)
					fos.close();
			} catch (IOException e) {
     
				e.printStackTrace();
			}
		}
	}

重点来喽,我们来玩一个小游戏,尝试加密一张图片

加密前图片文件流与缓冲流_第1张图片

加密后图片文件流与缓冲流_第2张图片

//图片加密
public static void main(String[] args) throws IOException {
     
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
				"D://材料//孤独的人.jpg"));
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream("D://材料//copy.jpg"));

		int b;
		while ((b = bis.read()) != -1) {
     
			bos.write(b ^ 2);//2代表秘钥,加密解密一致才能解密成功,类比钥匙和锁理解,在这里我们采取异或的办法来进行图片加密
		}

		bis.close();
		bos.close();
	}
//图片解密
public static void main(String[] args) throws IOException {
     
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D://材料//copy.jpg"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D://材料//copy1.jpg"));
		
		int b;
		while ((b = bis.read()) != -1) {
     
			bos.write(b ^ 2);
		}
		
		bis.close();
		bos.close();
	}
我们来分析一下:
第一步,异或第一次,将原文件进行加密操作
第二步,将中间复制的文件在进行一次异或就得到了我们原图,是不是很神奇呢
//将键盘录入数据存入c.txt文件中,输入esc退出
public static void main(String[] args) throws IOException {
     
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c.txt"));
        Scanner sc = new Scanner(System.in);
        System.out.println("键盘录入数据!esc时结束!");
        while(true){
     
            String line = sc.nextLine();
            if("esc".equals(line)){
     
                System.out.println("结束键盘录入!");
                break;
            }else{
     
                bos.write(line.getBytes());
               // bos.write("\r\n".getBytes());
            }
        }
        bos.close();

    }

编程这条路一定是布满荆棘的,只要不服输,什么困难都能迎刃而解,既然没有退路,那就一往直前吧!!! 加油!!!

你可能感兴趣的:(IO流)