IO流、Java序列化、内存操作流、加密解密文件

DAY13

☞☞☞ IO流

  • 按照流的方法
  • 读取流:读取数据
  • 输出流:写出数据
  • 按照数据类型
  • 字节流:任何文件都可以被看成一个字节数组,字节流可以操作任何文件
  • 字符流:只能操作文本类型的文件
  • 字节流基类
  • 输出流基类:OutputStream
  • 输入流基类:InputStream
  • 字符流基类
  • 输出流基类:Writer
  • 输入流基类:Reader
    注:字节流和字符流的子类的命名方式都是以它们的基类作为后缀名的

输出流代码实现:
分析:将“中国,你好”输出到一个文本文件中,发现更适合用字符流,但是字符流是通过字节流包装得来的,所以先要学习字节流

  • public FileOutputStream(File file)创建一个向指定File对象表示的文件中写入数据的文件输出流
  • public FileOutputStream(String name)创建一个向具有指定名称的文件中写入数据的输出文件流
  • public void write(byte[] b)将b.length个字节从指定byte数组写入此文件输出流中
  • public void write(byte[] b, int off, int len)将指定byte数组中从偏移量off开始的len个字节写入此文件输出流
  • public viod close()关闭侧文件输出流并释放与此流有关的所有系统资源
package cn.edu360;

import java.io.FileOutputStream;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args){
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream("D:\\haha.txt");
			byte[] bytes = "中国,你好".getBytes();
			fos.write(bytes);
			
			fos.write(bytes, 6, 9);
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(null != fos){
				try {
					fos.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}		
	}
}

图解说明:
IO流、Java序列化、内存操作流、加密解密文件_第1张图片

  • public FileOutputStream(String name, boolean append):append—如果为true,则将字节写入文件末尾部,而不是文件开始部

输入流:

  • public FileInputStream(File file)和指定文件建立一个读取通道
  • public FileInputStream(String name)和指定文件建立一个读取通道
  • public int read()从读取通道中读取一个字节,这个方法是阻塞的(意思就是如果读取到值后,后续代码才能执行,如果没有读取导致,后续代码执行不了
  • public int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中;返回值为:读入缓冲区的总字节数,如果因为已经到达流末尾而不再有数据可用,则返回-1;
    代码实现:
package cn.edu360;

import java.io.FileInputStream;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args){
		FileInputStream fis = null;
		try {
			fis = new FileInputStream("D:\\haha.txt");
			int i = fis.read();
			System.out.println(i);//228
			i = fis.read();
			System.out.println(i);//184
			
			byte[] b = new byte[1024];
			int len = fis.read(b);
			System.out.println(len);//22
			String result = new String(b, 0, len);
			System.out.println(result);//中国,你好,你好
		} catch (Exception e) {
			e.printStackTrace();
		}		
	}
}

案例展示:
1、把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中

代码实现:

package cn.edu360;

import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args){
		//先读后写
		//文件字节流
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream("D:\\haha.txt");
			fos = new FileOutputStream("D:\\hehe.txt");
			
			//读的时候,需要定义一个缓冲区容器,一次读取一点
			byte[] buf = new byte[1024];
			//定义一个变量用于接收每次读取的字节数
			int len = -1;
			//循环读写
			while ((len = fis.read(buf)) != -1) {
				fos.write(buf, 0, len);
			}
			System.out.println("拷贝成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//先创建的后关闭
			if(null != fos){
				try {
					fos.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(null != fis){
				try {
					fis.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

注意:简化上述代码的两种方式:

  • 直接将后续的关闭流操作封装成方法或者封装到一个工具类里面,通过工具类名.方法名来调用
  • JDK1.7新特性,可以在用完流的时候自动关闭流;在try括号里面自动用于创建流的代码才可以

简化代码如下:

package cn.edu360;

import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args){
		//先读后写
		//文件字节流
		try(FileInputStream fis = new FileInputStream("D:\\haha.txt");
			FileOutputStream fos = new FileOutputStream("D:\\hehe.txt");) {
			//读的时候,需要定义一个缓冲区容器,一次读取一点
			byte[] buf = new byte[1024];
			//定义一个变量用于接收每次读取的字节数
			int len = -1;
			//循环读写
			while ((len = fis.read(buf)) != -1) {
				fos.write(buf, 0, len);
			}
			System.out.println("拷贝成功");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

字节缓冲流:

  • 字节缓冲输入流
  • public BufferedInputStream(InputStream in)创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用。创建一个内部缓冲区数组并将其存储在buf中
  • 字节缓冲输出流
  • public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流

代码实现:

package cn.edu360;

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

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args){
		//先读后写
		//文件字节流
		try (FileInputStream fis = new FileInputStream("D:\\haha.txt");
			BufferedInputStream bis = new BufferedInputStream(fis);
			FileOutputStream fos = new FileOutputStream("D:\\hehe.txt");
			BufferedOutputStream bos = new BufferedOutputStream(fos);){
			
			byte[] buf = new byte[1024];
			int len = -1;
			while((len = bis.read(buf)) != -1){
				bos.write(buf,0,len);
				//写一次数据就刷一次
				bos.flush();
			}
			System.out.println("复制成功");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

字符流:
使用字节流操作文本数据比较麻烦,所以就出现了字符流
字符流=字节流+编码表
编码表:就是一张可以表示文字的码表,我们现实生活中的文字和符号,计算机使不认识的,我们需要给这些文字和符号一个编码,这样计算机存储这些编号就可以了;每个国家都有不同的文字,比如录入中国的文字的编码表有GB2312/GBK/GB18030

  • 转换流父类
  • OutputStreamWriter是字符流通向字节流的桥梁;其中以什么编码写出的,就以什么编码查看
  • InputStreamReader是字节流通向字符流的桥梁
  • Charset.defaultCharset().name()获取平台默认编码
  • public OutputStreamWriter(OutputStream out)创建使用默认字符编码的OutputStreamWriter
  • public void write(String str)写入字符串
  • public OutputStreamWriter(OutputStream out,String charseName)创建使用指定字符集的OutputStreamWriter

代码实现:

package cn.edu360;

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		FileOutputStream fis = new FileOutputStream("D:\\haha.txt");
		OutputStreamWriter osw = new OutputStreamWriter(fis);
		osw.write("哈哈,我使用字符流写出的!");
		osw.flush();//一定要进行flush,不然没有结果,因为写入的是缓冲区
		osw.close();
	}
}
  • public InputStreamReader(InputStream in)创建一个使用默认字符集的InputStreamReader
  • public InputStreamReader(InputStream in, String charseNmae)创建使用指定字符集的InputStreamReader
  • public int read(char[] cbuf)将字符读入数组,读取的字符数,如果已达到流的末尾,则返回-1
    注意:文件是什么类型的编码,就用什么类型的编码读取

代码实现:

package cn.edu360;

import java.io.FileInputStream;
import java.io.InputStreamReader;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		FileInputStream in = new FileInputStream("D:\\haha.txt");
		InputStreamReader isr = new InputStreamReader(in);
		char[] cbuf = new char[1024];
		int len = isr.read(cbuf);
		String content = new String(cbuf, 0, len);
		System.out.println(content);
	}
}
  • FileReader和FileWriter
  • FileWriter是OutputStreamWriter的简化写法,FileWriter的编码方式默认就是平台的编码;如果一定要指定编码格式,只能用OutputStreamWriter
    代码实现:
package cn.edu360;

import java.io.FileWriter;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		FileWriter fw = new FileWriter("D:\\haha.txt");
		fw.write("哈哈,我是用FileWriter写出的");
		fw.flush();
		fw.close();
	}
}
  • FileReader是InputStreamReader的简化写法,FileReader的编码方式默认就是平台的编码;如果一定要指定编码格式,只能用InputStreamReader
  • 代码实现:
package cn.edu360;

import java.io.FileReader;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		FileReader fr = new FileReader("D:\\haha.txt");
		char[] cbuf = new char[1024];
		int len = fr.read(cbuf);
		System.out.println(new String(cbuf, 0, len));
	}
}

综合案例:

package cn.edu360;

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

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//先读后写
		FileReader fr = new FileReader("D:\\haha.txt");
		FileWriter fw = new FileWriter("D:\\hehe.txt");
		
		char[] cbuf = new char[1024];
		int len = -1;
		while((len = fr.read(cbuf)) != -1){
			fw.write(cbuf);
			fw.flush();
		}
		fw.close();
		fr.close();
		System.out.println("拷贝成功");
	}
}

注意事项:在windows中换行分隔符:\r\n;在Linux里面中的换行分隔符:\n

  • BufferedReader和BufferedWriter
  • public BufferedWriter(Writer out)创建一个使用默认大小输出缓冲区的缓冲字符输出流
  • public void newLine()写入一个行分隔符。行分隔符字符串由系统属性line.separator定义,并且不一定是单个新行(‘\n’)符

代码实现:

package cn.edu360;

import java.io.BufferedWriter;
import java.io.FileWriter;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		FileWriter fw = new FileWriter("D:\\hehe.txt");
		BufferedWriter bw = new BufferedWriter(fw);
		bw.write("哈哈,我是通过缓冲字符输出流写出的");
		bw.newLine();
		bw.write("哈哈,我是通过缓冲字符输出流写出的");
		bw.flush();
		bw.close();
	}
}
  • public BufferedReader(Reader in)创建一个使用默认大小输入缓冲区的缓冲字符输入流
  • public String readLine()读取一个文本行,如果没有数据可以读取了返回null

代码实现:

package cn.edu360;

import java.io.BufferedReader;
import java.io.FileReader;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		FileReader fr = new FileReader("D:\\hehe.txt");
		BufferedReader br = new BufferedReader(fr);
		String content = br.readLine();
		System.out.println(content);//打印一行
		content = br.readLine();
		System.out.println(content);//打印两行
		content = br.readLine();
		System.out.println(content);//打印三行
	}
}

IO流练习:
1、复制文本

  • 使用缓冲区写出数据时,如果中途不着急将一部分数据刷新出去,可以等到最后关闭流的时候再将数据刷新出去
  • 如果缓冲区存满了,缓存区将里面的数据强制刷新出去

代码实现:

package cn.edu360;

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

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new FileReader("D:\\haha.txt"));
		BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\xixi.txt"));
		
		String len = null;
		while((len = br.readLine()) != null){
			bw.write(len);
			bw.newLine();
		}
		bw.close();
		br.close();
		System.out.println("复制成功");
	}
}

2、复制图片

代码实现:

package cn.edu360;

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

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args){
		try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\mm.jpg"));
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\nn.jpg"));){
			//自定义缓冲区容器
			byte[] buf = new byte[1024];
			//自定义变量用于接收每次读取的字节长度
			int len = -1;
			//循环读取
			while((len = bis.read(buf)) != -1){
				//读多少写多少
				bos.write(buf, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("拷贝成功");
	}
}

3、将ArrayList集合中的字符串写入到文本文件中

代码实现:

package cn.edu360;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//创建ArrayList并添加内容
		ArrayList list = new ArrayList();
		list.add("javaSe");
		list.add("javaEE");
		list.add("hadoop");
		list.add("张明");
		list.add("lili");
		
		//创建缓冲字符流
		BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\list.txt"));
		for (String result : list) {
			bw.write(result);
			bw.newLine();
		}
		bw.close();
		System.out.println("添加成功");
	}
}

4、从文本文件中读取数据(每一行为一个字符串数据)到集合中,并遍历结合

代码实现:

package cn.edu360;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new FileReader("D:\\list.txt"));
		ArrayList list = new ArrayList();
		String line = null;
		while((line = br.readLine()) != null){
			list.add(line);
		}
		br.close();
		for (String result : list) {
			System.out.println(result);
		}
	}
}

5、复制单级文件夹
复制单级文件夹中指定文件并修改文件名称

代码实现:

package cn.edu360;

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

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//复制单级文件夹
		//1.封装源文件夹的文件对象
		File srcFolder = new File("D:\\test123");
		//2.封装要拷贝到的文件夹对象
		File destFolder = new File("E:\\");
		//3.在目标盘符创建一个一模一样的文件夹
		destFolder = new File(destFolder, srcFolder.getName());
		destFolder.mkdir();
		//4.获取源文件夹中所有的子文件对象
		File[] files = srcFolder.listFiles();
		//遍历所有的子文件对象数组,然后拷贝到目标文件中
		for (File srcFile : files) {
			//在目标文件夹里面创建一个名字一模一样的文件
			File destFile = new File(destFolder, srcFile.getName());
			//调用拷贝文件的方法
			copyFile(srcFile,destFile);
		}
		System.out.println("拷贝成功");
	}

	private static void copyFile(File srcFile, File destFile) {
		try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile))){
			byte[] buf = new byte[1024];
			int len = -1;
			while((len = bis.read(buf)) != -1){
				bos.write(buf, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

6、复制多级文件夹

代码实现:

package cn.edu360;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//1.封装原文件夹对象
		File srcFolder = new File("D:\\test123");
		//2.封装目标文件夹对象
		File destFolder = new File("E:\\");
		//调用拷贝文件夹的方法
		copyFolder(srcFolder,destFolder);
		
		System.out.println("拷贝成功");
	}

	private static void copyFolder(File srcFolder, File destFolder) {
		//4.判断srcFolder是不是一个标准文件
		if(srcFolder.isFile()){
			//4.1如果是一个标准文件就直接拷贝
			//在目标文件夹中,创建有一个一模一样名字文件
			File destFile = new File(destFolder, srcFolder.getName());
			copyFile(srcFolder,destFile);
		}else {
			//4.2如果不是一个标准文件,那么就是一个文件夹
			//在目标文件夹中创建一个一模一样的名字子文件夹
			destFolder = new File(destFolder, srcFolder.getName());
			destFolder.mkdir();
			
			//5.获取原文件夹中所有的子文件对象
			File[] files = srcFolder.listFiles();
			//6.遍历子文件对象数组,再调用拷贝文件夹的方法
			for (File srcFile : files) {
				copyFolder(srcFile, destFolder);
			}
		}
	}

	private static void copyFile(File srcFile, File destFile) {
		try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile))){
			byte[] buf = new byte[1024];
			int len = -1;
			while((len = bis.read(buf)) != -1){
				bos.write(buf, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

☞☞☞ Java序列化

  • Java序列化是指把Java对象转换成字节序列的过程
  • Java反序列化是指把字节序列恢复为Java对象的过程

当两个Java进程进行通信时,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方面需要从字节序列中恢复出Java对象

  • Java序列化:ObjectOutputStream将Java对象的基本数据类型和图形写入OutputStream
  • public ObjectOutputStream(OutputStream out)创建写入指定OutputStream的ObjectOutputStream
  • public final void writeObject(Object obj)将指定的对象写入ObjectOutputStream
  • Java反序列化:ObjectInputStream对以前使用ObjectOutputStream写入的基本数据和对象进行反序列化
  • public ObjectInputStream(InputStream in)创建从指定InputStream读取的ObjectInputStream
  • public final Object readObject()从ObjectInputStream读取对象

序列化的注意事项:

  • 要被序列化的对象必须实现Serializable接口
  • 如果一个成员被transient修饰了,那么这个成员就不能被序列化保存

代码实现:
(1)主代码:

package cn.edu360;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//序列化
		objectToFile();
		//反序列化
		fileToObject();
	}

	private static void fileToObject() throws Exception{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\person.txt"));
		Object object = ois.readObject();
		System.out.println(object);
	}

	private static void objectToFile() throws Exception {
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\person.txt"));
		oos.writeObject(new Person("张三", 18, "西安"));
		oos.close();
		System.out.println("成功");
	}
}

(2)相关类

package cn.edu360;

import java.io.Serializable;

public class Person implements Serializable{
	
	private String name;
	private int age;
	private String address;
	
	public Person() {
	}
	
	public Person(String name, int age, String address) {
		super();
		this.name = name;
		this.age = age;
		this.address = address;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "[name=" + name + ", age=" + age + ", address=" + address
				+ "]";
	}	
}

☞☞☞ 内存操作流

  • 操作字节数组
  • ByteArrayInputStream:包含一个内部缓冲区,该缓冲区包含从流 中读取的字节
  • ByteArrayOutputStream:此类实现了一个输出流,其中的数据被写入一个byte数组。缓冲区会随着数组的不断写入而自动增长。可使用toByteArray()和toString()获取数据
    代码实现:
package cn.edu360;

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

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//将一张图片转换成字节数组
		byte[] byteArray = imageToByteArray();
		
		//将一个字节数组保存成一张图片
		byteArrayToImage(byteArray);
	}

	private static void byteArrayToImage(byte[] byteArray) throws Exception {
		ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
		//将字节数组保存到硬盘上一个文件图片中
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\hehe.jpg"));
		//定义一个缓冲区容器
		byte[] buf = new byte[1024];
		int len = -1;
		while((len = bais.read(buf)) != -1){
			bos.write(buf, 0, len);
		}
		bos.close();
		System.out.println("保存成功");
	}

	private static byte[] imageToByteArray() throws FileNotFoundException,
			IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\abc.jpg"));
		ByteOutputStream baos = new ByteOutputStream();
		//自定义缓冲区
		byte[] buf = new byte[1024];
		int len = -1;
		while((len = bis.read(buf)) != -1){
			//我们之前是往一个文件中去写,现在改为往一个字节数组中写
			baos.write(buf, 0, len);
		}
		baos.close();
		//将字节数组中的字节取出来
		byte[] byteArray = baos.toByteArray();
		return byteArray;
	}
}
  • 操作字符数组
  • CharArrayReader
  • CharArrayWrite
  • 操作字符串
  • StringReader
  • StringWriter

注意事项:上述两个跟第一个的案例类似

加密分割和解密组成文件(很重要):

package cn.edu360;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
 *  @author Zhang
 */
public class ClassDemo {
	public static void main(String[] args) throws Exception{
		//将一个文件分割成最多四份并且加密
		spiltFile();
		
		//将四个文件组合成一张图片
		groupFile();
	}

	private static void groupFile() throws Exception {
		//1.创建一个缓冲字节读取流
		BufferedInputStream bis = null;
		//2.创建字节数组输出流
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		for(int i = 0; i < 4; i++){
			switch (i) {
			case 0:
				bis = new BufferedInputStream(new FileInputStream("D:\\temp1.dll"));
				//将文件中的字节读取到字节数组中
				readByteArray(bis,baos);
				break;
			case 1:
				bis = new BufferedInputStream(new FileInputStream("D:\\temp2.dll"));
				readByteArray(bis,baos);
				break;
			case 2:
				bis = new BufferedInputStream(new FileInputStream("D:\\temp3.dll"));
				readByteArray(bis,baos);	
				break;
			case 3:
				//首先判断第四个文件存不存在
				File file = new File("D:\\temp4.dll");
				if(file.exists()){
					bis = new BufferedInputStream(new FileInputStream("D:\\temp4.dll"));
					readByteArray(bis,baos);
				}
				break;
			}
			bis.close();
		}
		//3.将字节数组写出流中的字节数组取出来解密
		byte[] byteArray = lockAndKey(baos);
		
		//4.将字节数组保存成一个图片
		ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\group.jpg"));
		byte[] buf = new byte[1024];
		int len = -1;
		while((len = bais.read(buf)) != -1){
			bos.write(buf, 0, len);
		}
		bos.close();
		System.out.println("图片组合成功");
	}

	private static void readByteArray(BufferedInputStream bis,ByteArrayOutputStream baos) throws Exception {
		byte[] buf = new byte[1024];
		int len = -1;
		while((len = bis.read(buf)) != -1){
			baos.write(buf, 0, len);
		}
	}

	private static void spiltFile() throws Exception {
		//1.将图片转换成一个加密过后的字节数组
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\车.jpg"));
		//2.创建一个字节数组输出流
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		//3.循环读写
		byte[] buf = new byte[1024];
		int len = -1;
		while((len = bis.read(buf)) != -1){
			baos.write(buf, 0, len);
		}
		bis.close();
		//4.将字节数组输出流中的字节数组取出来并加密
		byte[] byteArray = lockAndKey(baos);
		//5.将字节数组最多分割成四份
		//三份分割的文件保存的字节长度
		int size = byteArray.length/3;
		//6.将每一份数据保存到文件中
		BufferedOutputStream bos = null;
		for (int i = 0; i < 3; i++) {
			switch (i) {
			case 0:
				bos = new BufferedOutputStream(new FileOutputStream("D:\\temp1.dll"));
				//第一次写size字节
				bos.write(byteArray, 0, size);//这样写如果文件很大的情况下,内存可能会crash
				break;
			case 1:
				bos = new BufferedOutputStream(new FileOutputStream("D:\\temp2.dll"));
				bos.write(byteArray, size, size);				
				break;
			case 2:
				bos = new BufferedOutputStream(new FileOutputStream("D:\\temp3.dll"));
				bos.write(byteArray, size*2, size);
				break;
			}
			bos.close();
		}
		//7.判断还有没有剩余的字节
		if(size*3 < byteArray.length){
			bos = new BufferedOutputStream(new FileOutputStream("D:\\temp4.dll"));
			bos.write(byteArray, size*3, byteArray.length-size*3);
			bos.close();
		}
		System.out.println("分隔成功");
	}

	private static byte[] lockAndKey(ByteArrayOutputStream baos) {
		byte[] byteArray = baos.toByteArray();
		//加密过程(采用异或)
		for (int i = 0; i < byteArray.length; i++) {
			byteArray[i] = (byte) (byteArray[i]^61);
		}
		return byteArray;
	}
}

你可能感兴趣的:(温习基础)