java io流小结

本文总结了Java IO流的基本概念和分类,包括字节流和字符流的区别,以及常用流的使用,如FileInputStream、FileOutputStream、BufferedInputStream、BufferedOutputStream、FileReader、FileWriter等,并探讨了如何处理对象流和字符编码转换的问题。
摘要由CSDN通过智能技术生成

java IO流类结构图:

 

流:

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

IO流的分类:

    根据处理数据类型的不同分为:字节流和字符流。

    根据数据流向不同分为:输入流和输出流。

字节流和字符流:

    字符流的由来:因为字符编码的不同,而有了对字符进行高效操作的流对象,本质就是基于字节流读取时,去查了指定的码表。

    二者的区别:

        读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读取多个字节。

        处理对象不同:字节流能处理所有类型的数据(如图片、视频等),而字符流只能处理字符类型的数据。

输入流和输出流:(输入与输出是站在程序的角度而言的)

    对输入流只能进行读操作, 对输出流只能进行写操作。

 

在java中,有很多流类,但我们常用的只有那么几个。

字节流:


1. FileInputStream与FileOutputStream:对文件系统中某个文件的读写操作。

一个文件拷贝的列子:

读取文件:

<span style="font-family:Microsoft YaHei;">public class FileCopyInputStream {

	/**
	 * 读源文件,并将读取的结果保存到ArrayList中
	 * 
	 * @param file
	 *            源文件
	 * @param isCut
	 *            是否剪切,true==剪切,false==复制
	 * @return 源文件内容,即ArrayList
	 */
	public ArrayList<DataBuffer> read(File file, boolean isCut) {
		// 文件输入流
		FileInputStream fis = null;
		// ArrayList,用来保存读取的数据
		ArrayList<DataBuffer> aList = new ArrayList<>();
		try {
			// 初始化文件输入流
			fis = new FileInputStream(file);
			// 文件容量大于0,就读
			if (fis.available() > 0) {
				// 读取的内容,为-1时表示文件读取结束
				// 临时数组,用来保存read方法读到的数据
				byte[] bytes = new byte[1024];
				// read方法读到的数据的长度
				int readLength = 0;
				// 一直读到文件结尾
				while ((readLength = fis.read(bytes)) != -1) {
					// 创建一个DataBuffer对象,用来装载每一次read方法读出的数据
					DataBuffer db = new DataBuffer();
					// 读取的内容
					db.setBytes(bytes);
					// 读取的长度
					db.setLength(readLength);
					// 将DataBuffer对象添加到ArrayList中
					aList.add(db);
				}

			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 文件输入流不为空时,关闭输入流
			if (fis != null) {
				try {
					// 关闭文件流
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		// 剪切,删除源文件
		if (isCut) {
			file.delete();
		}
		// 返回读取的内容
		return aList;
	}
}</span>
将读取的数据写入到文件:

<span style="font-family:Microsoft YaHei;">public class FileCopyOutputStream {

	/**
	 * 将数据写入到一个新的文件中
	 * 
	 * @param file
	 *            目标文件
	 * @param aList
	 *            数据源
	 */
	public void write(File file, ArrayList<DataBuffer> aList) {
		// 文件输出流
		FileOutputStream fos = null;
		try {
			// 初始化文件输出流
			fos = new FileOutputStream(file);
			// 迭代器,遍历ArrayList中的数据
			Iterator<DataBuffer> iter = aList.iterator();
			// 遍历
			while (iter.hasNext()) {
				// 取出数据
				DataBuffer db = iter.next();
				// 将数据写入到输出流
				fos.write(db.getBytes(), 0, db.getLength());
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 文件输出流不为空时,关闭输出流
			if (fos != null) {
				try {
					// 清空文件输出流
					fos.flush();
					// 关闭文件输出流
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}</span>
DataBuffer辅助类:

<span style="font-family:Microsoft YaHei;">public class DataBuffer {
	// byte数组,用来保存读出的数据
	private byte[] bytes;
	// 保存每次读出的数据长度
	private int length;

	/**
	 * 获取byte数组
	 * 
	 * @return byte数组
	 */
	public byte[] getBytes() {
		return bytes;
	}

	/**
	 * 设置byte数组的值
	 * 
	 * @param bytes
	 *            byte数组
	 */
	public void setBytes(byte[] bytes) {
		this.bytes = bytes;
	}

	/**
	 * 获取数据长度
	 * 
	 * @return 数据长度
	 */
	public int getLength() {
		return length;
	}

	/**
	 * 设置数据长度
	 * 
	 * @param length
	 *            数据长度
	 */
	public void setLength(int length) {
		this.length = length;
	}

}</span>
测试类:

<span style="font-family:Microsoft YaHei;">public class FileCopyTest {

	public static void main(String[] args) {
		// 源文件
		File src = new File("C:\\Users\\Administrator\\Desktop\\aa.txt");
		// 目标文件目录
		File desc = new File("src/com/wzd/filecopy/");
		// 执行拷贝操作
		copy(src, desc, false);
	}

	/**
	 * 拷贝
	 * 
	 * @param src
	 *            源文件
	 * @param desc
	 *            目标目录
	 * @param isCut
	 *            true,剪切 false,复制
	 */
	public static void copy(File src, File desc, boolean isCut) {
		// 判断源文件是目录还是文件
		if (src.isFile()) {
			// 是文件
			copyFile(src, desc, false);
		} else {
			// 是目录
			coprDirectory(src, desc, false);
		}
	}

	/**
	 * 拷贝目录
	 * 
	 * @param src
	 *            源文件
	 * @param desc
	 *            目标目录
	 * @param isCut
	 *            true,剪切 false,复制
	 */
	private static void coprDirectory(File src, File desc, boolean isCut) {
		// 在目标目录下创建一个新文件对象
		File newDirectory = new File(desc, src.getName());
		// 创建目录
		newDirectory.mkdirs();
		// 拷贝该目录内的子文件
		File[] files = src.listFiles();
		// 遍历flies数组
		for(File file : files) {
			// 继续拷贝
			copy(file, newDirectory, false);
		}
		// 剪切文件,则删除
		if(isCut) {
			src.delete();
		}
	}

	/**
	 * 拷贝文件
	 * 
	 * @param src
	 *            源文件
	 * @param desc
	 *            目标目录
	 * @param isCut
	 *            true,剪切 false,复制
	 */
	private static void copyFile(File src, File desc, boolean isCut) {
		// 在目标目录下创建一个新文件对象
		File newFile = new File(desc, src.getName());
		// 如果目标文件不存在,则创建一个目标文件
		if (!newFile.exists()) {
			try {
				// 创建一个新文件
				newFile.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 文件复制输入流
		FileCopyInputStream input = new FileCopyInputStream();
		// 读文件
		ArrayList<DataBuffer> aList = input.read(src, false);
		// 文件复制输出流
		FileCopyOutputStream output = new FileCopyOutputStream();
		// 写文件
		output.write(newFile, aList);
	}
}</span>

2. ObjectInputStream与ObjectOutputStream:对对象进行的读写操作,一般是将对象保存在文件中。

一个模拟数据库的列子:

此时需要注意:ObjectOutputStream的构造器会向输出流中写入头信息,因此在向文件中追加数据时,每一次都会写入头信息。

一种处理方式是自定义一个类,继承自ObjectOutputStream,重写writeStreamHeader()方法,该方法什么都不做,就不会再写入头信息。

自定义类,继承自ObjectOutputStream:

<span style="font-family:Microsoft YaHei;">public class DBObjectOutputStream extends ObjectOutputStream {

	public DBObjectOutputStream() throws IOException, SecurityException {
	}

	public DBObjectOutputStream(OutputStream out) throws IOException {
		super(out);
	}

	/**
	 * 写流的头信息
	 */
	@Override
	protected void writeStreamHeader() throws IOException {
		// 不实现该方法,则不会写入文件头信息
		return;
	}
}</span>
向文件中写入数据:
<span style="font-family:Microsoft YaHei;">public class DBOutputStream<T> {

	/**
	 * 向指定文件写入数据
	 * 
	 * @param t
	 *            泛型对象
	 * @param file
	 *            目标文件
	 */
	public void write(T t, File file) {
		// 创建一个FileOutputStream对象
		FileOutputStream fos = null;
		// 创建一个ObjectOutputStream对象
		ObjectOutputStream oos = null;
		try {
			// 初始化FileOutputStream对象,append参数为true
			fos = new FileOutputStream(file, true);
			// 检测文件是否存在,若不存在,则创建文件
			if (!file.exists()) {
				// 创建新文件
				file.createNewFile();
			}
			// 检测文件大小,确定是否是第一次操作文件
			if (file.length() < 1) {
				// 第一次操作文件。由于ObjectOutputStream每次都会向文件中写入文件头信息,
				// 因此只在第一次操作文件时使用
				oos = new ObjectOutputStream(fos);
			} else {
				// 不是第一次操作文件,则使用自己定义的DBObjectOutputStream
				oos = new DBObjectOutputStream(fos);
			}
			// 向文件中写入对象
			oos.writeObject(t);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				// 若oos不为空,则关闭该输出流
				if (oos != null) {
					// 刷新流缓冲
					oos.flush();
					// 关闭流
					oos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}</span>
从文件中读取数据:

<span style="font-family:Microsoft YaHei;">public class DBInputStream {

	/**
	 * 从指定文件中读取数据
	 * 
	 * @param file
	 *            指定文件
	 * @return ArrayList<Object> 读取的结果
	 */
	public ArrayList<Object> read(File file) {
		// 创建一个FileInputStream对象
		FileInputStream fis = null;
		// 创建一个ObjectInputStream对象
		ObjectInputStream ois = null;
		// 创建一个ArrayList<Object>
		ArrayList<Object> aList = new ArrayList<>();
		// 创建一个Object对象
		Object object = null;
		try {
			// 判断文件是否存在
			if (!file.exists()) {
				return null;
			}
			// 初始化FileInputStream对象
			fis = new FileInputStream(file);
			// 初始化ObjectInputStream对象
			ois = new ObjectInputStream(fis);
			// 死循环读取文件内容,当抛出EOFException异常时,表示已经读至文件结尾
			while (true) {
				// 从文件里读对象
				object = ois.readObject();
				// 将对象放入ArrayList<Object>中
				aList.add(object);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (EOFException e) {
			// TODO: handle exception
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				// 若ois不为空,关闭输入流
				if (ois != null) {
					// 关闭流
					ois.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		// 返回ObjectInputStream读出的结果
		return aList;
	}
}</span>

dao类:

<span style="font-family:Microsoft YaHei;">public class StudnetInfoDAO {

	// 接受控制台的输入信息
	Scanner scanner = new Scanner(System.in);
	// 保存学生对象的文件
	File studentFile = new File("src/com/wzd/dbimitate/resource/student.obj");
	// 保存课程对象的文件
	File courseFile = new File("src/com/wzd/dbimitate/resource/course.obj");
	// 保存成绩对象的文件
	File gradeFile = new File("src/com/wzd/dbimitate/resource/grade.obj");
	// ArrayList<Object>,保存DBInputStream读出的数据
	ArrayList<Object> objects = new ArrayList<>();
	// DBInputStream,从指定文件中读取数据
	DBInputStream dbis = new DBInputStream();

	/**
	 * 添加学生信息
	 */
	public void insertIntoStudent() {
		// 提示输入格式
		System.out.println("请输入学生信息(学生姓名,学生学号,学生电话):");
		// 接收输入的信息
		String str = scanner.next().trim();
		// 分解字符串
		String[] strs = str.split(",");
		// 创建一个Student对象,并赋值
		Student student = new Student();
		student.setName(strs[0]);
		student.setNumber(strs[1]);
		student.setPhone(strs[2]);
		// DBOutputStream<Student>输出流
		DBOutputStream<Student> dbos = new DBOutputStream<>();
		// 向学生文件中写数据
		dbos.write(student, studentFile);
	}

	/**
	 * 添加课程信息
	 */
	public void insertIntoCourse() {
		// 提示输入格式
		System.out.println("请输入课程信息(课程名,课程号):");
		// 接收输入的信息
		String str = scanner.next().trim();
		// 分解字符串
		String[] strs = str.split(",");
		// 创建一个Course对象,并赋值
		Course course = new Course();
		course.setName(strs[0]);
		course.setNumber(strs[1]);
		// DBOutputStream<Course>输出流
		DBOutputStream<Course> dbos = new DBOutputStream<>();
		// 向课程文件中写数据
		dbos.write(course, courseFile);
	}

	/**
	 * 添加成绩信息
	 */
	public void insertIntoGrade() {
		// 提示输入格式
		System.out.println("请输入成绩信息(学生学号,课程号,成绩):");
		// 接收输入的信息
		String str = scanner.next().trim();
		// 分解字符串
		String[] strs = str.split(",");
		// 创建一个Grade对象,并赋值
		Grade grade = new Grade();
		grade.setStudentNumber(strs[0]);
		grade.setCourseNumber(strs[1]);
		grade.setGrade(Double.parseDouble(strs[2]));
		// DBOutputStream<Grade>输出流
		DBOutputStream<Grade> dbos = new DBOutputStream<>();
		// 向成绩文件中写数据
		dbos.write(grade, gradeFile);
	}

	/**
	 * 通过学生姓名查询到所有的成绩信息
	 */
	public void selectGrade() {
		// 提示输入信息
		System.out.println("请输入学生姓名:");
		// 接收输入的信息
		String studentName = scanner.next().trim();
		// 查询学生信息
		Student student = selectStudentInfo(studentName);
		// 查询成绩信息
		ArrayList<Grade> grades = selectGradeInfo(student.getNumber());
		// 创建一个课程对象数组
		Course[] course = new Course[grades.size()];
		// 遍历ArrayList<Grade>
		for (int i = 0; i < grades.size(); i++) {
			// 查询课程信息
			course[i] = selectCourseInfo(grades.get(i).getCourseNumber());
		}
		// 打印头信息
		System.out.println("学生姓名\t\t课程名\t\t分数");
		// 遍历
		for (int i = 0; i < grades.size(); i++) {
			// 打印最终结果
			System.out.println(student.getName() + "\t\t" + course[i].getName()
					+ "\t\t" + grades.get(i).getGrade());
		}
	}

	/**
	 * 通过学生姓名查询到所有的考试科目
	 */
	public void selectCourse() {
		// 提示输入信息
		System.out.println("请输入学生姓名:");
		// 接收输入的信息
		String studentName = scanner.next().trim();
		// 查询学生信息
		Student student = selectStudentInfo(studentName);
		// 查询成绩信息
		ArrayList<Grade> grades = selectGradeInfo(student.getNumber());
		// 创建一个课程对象数组
		Course[] course = new Course[grades.size()];
		// 遍历ArrayList<Grade>
		for (int i = 0; i < grades.size(); i++) {
			// 查询课程信息
			course[i] = selectCourseInfo(grades.get(i).getCourseNumber());
		}
		// 打印头信息
		System.out.println("学生姓名\t\t考试科目");
		// 遍历
		for (int i = 0; i < course.length; i++) {
			// 打印最终结果
			System.out.println(student.getName() + "\t\t" + course[i].getName());
		}
	}

	/**
	 * 通过学生姓名获取学生信息
	 */
	public void selectStudent() {
		// 提示输入信息
		System.out.println("请输入学生姓名:");
		// 接收输入的信息
		String studentName = scanner.next().trim();
		// 查询学生信息
		Student student = selectStudentInfo(studentName);
		// 打印头信息
		System.out.println("学生姓名\t\t学号\t\t电话号码");
		// 打印最终结果
		System.out.println(student.getName() + "\t\t" + student.getNumber()
				+ "\t\t" + student.getPhone());
	}

	/**
	 * 通过课程号查询课程信息
	 * 
	 * @param courseNumber
	 *            课程号
	 * @return 课程对象
	 */
	private Course selectCourseInfo(String courseNumber) {
		// 创建一个Course对象
		Course course = null;
		// 从课程文件中读取数据
		objects = dbis.read(courseFile);
		// 遍历读取结果
		for (Object object : objects) {
			// 转换为Course对象
			course = (Course) object;
			// 若匹配
			if (courseNumber.equals(course.getNumber())) {
				// 返回课程对象
				return course;
			}
		}
		// 返回空
		return null;
	}

	/**
	 * 通过学号查询成绩信息
	 * 
	 * @param studentNumber
	 *            学号
	 * @return ArrayList<Grade> 成绩信息
	 */
	private ArrayList<Grade> selectGradeInfo(String studentNumber) {
		// 创建一个Grade对象
		Grade grade = null;
		// 创建一个ArrayList<Grade>
		ArrayList<Grade> grades = new ArrayList<>();
		// 从成绩文件中读取数据
		objects = dbis.read(gradeFile);
		// 遍历读取结果
		for (Object object : objects) {
			// 转换为Grade对象
			grade = (Grade) object;
			// 若匹配
			if (studentNumber.equals(grade.getStudentNumber())) {
				// 将Grade对象添加到ArrayList<Grade>中
				grades.add(grade);
			}
		}
		// 返回结果
		return grades;
	}

	/**
	 * 通过学生姓名查询学生信息
	 * 
	 * @param studentName
	 *            学生姓名
	 * @return 学生对象
	 */
	private Student selectStudentInfo(String studentName) {
		// 创建一个Student对象
		Student student = new Student();
		// 从学生文件中读取数据
		objects = dbis.read(studentFile);
		// 遍历读取结果
		for (Object object : objects) {
			// 转换为Student对象
			student = (Student) object;
			// 若匹配
			if (studentName.equals(student.getName())) {
				// 返回Student对象
				return student;
			}
		}
		// 返回空
		return null;
	}
}</span>
测试类:

<span style="font-family:Microsoft YaHei;">public class DBImitateTest {

	public static void main(String[] args) {
		// 创建一个StudnetInfoDAO对象
		StudnetInfoDAO dao = new StudnetInfoDAO();

		// 1.可以使用命令 存入学生成绩: 学生学号,学生姓名,学生成绩,科目,学生电话
		// 添加学生信息
		for (int i = 0; i < 5; i++) {
			dao.insertIntoStudent();
		}
		// 添加课程信息
		for (int i = 0; i < 4; i++) {
			dao.insertIntoCourse();
		}
		// 添加成绩信息
		for (int i = 0; i < 9; i++) {
			dao.insertIntoGrade();
		}

		// 2.可以通过学生姓名查询到所有的成绩信息
		dao.selectGrade();

		// 3.可以通过学生姓名查询到所有的考试科目
		dao.selectCourse();

		// 4.可以通过学生姓名获取学生信息
		dao.selectStudent();
	}
}</span>

3. BufferedInputStream与BufferedOutputStream:缓冲流,里面包装其他的输入输出流,以提高读写的效率,其中BufferedInputStream支持mark和reset的使用。

示列如下:

<span style="font-family:Microsoft YaHei;">public class BufferedInputStreamTest {

	public static void main(String[] args) {
		//
		try {
			BufferedInputStream bis = 
					new BufferedInputStream(new FileInputStream("src/com/wzd/test/dec22/ReaderTest.java"));
			// 判断该流是否可读
			if(bis.available() > 0) {
				// 判断该流是否可以被mark
				if(bis.markSupported()) {
					// mark一下,做一个标记,参数在此时没有使用,只要填写一个int值就行
					// mark在一个流中只有一个有效,后面下的mark会覆盖掉前面的
					System.out.print((char)bis.read());
					System.out.println((char)bis.read());
					bis.mark(0);
					System.out.print((char)bis.read());
					System.out.println((char)bis.read());
					// 回到mark标记处
					bis.reset();
					System.out.print((char)bis.read());
					System.out.println((char)bis.read());
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}</span>


4. DataInputStream与DataOutputStream:对java基本数据类型进行读写操作。


字符流:(字符流的操作与字节流基本类似)

1. FileReader与FileWriter:以字符的形式对文件进行读写操作。


2. BufferedReader与BufferedWriter:缓冲字符流。


3. InputStreamReader与OutputStreamWriter:

InputStreamReader是字节流通向字符流的桥梁:它使用charset读取字节并将其解码为字符。

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值