第四十八讲 I/O流——常用IO流(数据流和内存操作流)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yerenyuan_pku/article/details/84669496

数据流

数据流是操作基本数据类型的流,分为数据输入流和数据输出流。下面分别来对它们进行介绍。

数据输入流

概述

数据输入流DataInputStream允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。

数据输出流

概述

数据输出流DataOutputStream允许应用程序以适当方式将基本Java数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。

案例

写入一些基本数据值,存储到文件,并读取出来。

package cn.liayun.otherio.datastream;

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

public class DataStreamDemo {

	public static void main(String[] args) throws IOException {
//		writeData();
		readData();
	}

	public static void readData() throws IOException {
		FileInputStream fis = new FileInputStream("tempfile\\data.txt");
		DataInputStream dis = new DataInputStream(fis);
		boolean b = dis.readBoolean();
		System.out.println(b);
		dis.close();
	}

	public static void writeData() throws IOException {
		//写入一些基本数据值,存储到文件。
		FileOutputStream fos = new FileOutputStream("tempfile\\data.txt");
		DataOutputStream dos = new DataOutputStream(fos);
		
		dos.writeBoolean(true);
		
		dos.close();
	}

}

内存操作流

内存操作流是用于操作字节数组,处理临时存储信息的,程序结束,数据就从内存中消失。它分为字节数组输入流ByteArrayInputStream和字节数组输出流ByteArrayOutputStream。该流在后续的学习中,相信你估计会碰到!下面分别来对它们进行介绍。

ByteArrayInputStream

概述

ByteArrayInputStream包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪read方法要提供的下一个字节。关闭ByteArrayInputStream无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException。

ByteArrayOutputStream

概述

此类实现了一个输出流,其中的数据被写入一个byte数组。缓冲区会随着数据的不断写入而自动增长。可使用toByteArray()和toString()获取数据。关闭ByteArrayOutputStream无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException。

案例

用IO流的读写思想操作数组。

package cn.liayun.otherio.bytearraystream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class ByteArrayStreamDemo {

	public static void main(String[] args) {
		//用IO的读写思想操作数组
		//1,确定源
		ByteArrayInputStream bis = new ByteArrayInputStream("abcde".getBytes());//该数据源可以来自于文件
		//2,确定目的,内置了一个byte数组
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		int by = 0;
		while ((by = bis.read()) != -1) {
			bos.write(by);
		}
		
		System.out.println(bos.toString());
	}

}

涉及到IO流的两个练习

文件切割器

对一个文件进行切割(一个源对应多个目的),切成碎片,而且生产的碎片文件都有有序的编号。

package cn.liayun.otherio.splitfile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class SplitFileTest {

	public static void main(String[] args) throws IOException {
		/*
		 * 文件切割器。
		 * 一个读取流,对应多个输出流,而且生产的碎片文件都有有序的编号。
		 */
		File srcFile = new File("c:\\1.mp4");
		File destDir = new File("tempfile\\partfiles");
		fileSplit(srcFile, destDir);
	}

	public static void fileSplit(File srcFile, File destDir) throws IOException {
		if (!srcFile.exists()) {
			throw new RuntimeException(srcFile.getAbsolutePath() +  "源文件不存在");
		}
		
		if (!destDir.exists()) {
			destDir.mkdirs();
		}
		
		//1,读取源文件
		FileInputStream fis = new FileInputStream(srcFile);
		//2,创建目的引用
		FileOutputStream fos = null;
		//3,创建一个缓冲区(5M)
		byte[] buf = new byte[1024 * 1024 * 5];//5M
		int count = 0;
		int len = 0;
		//4,往缓冲区中存储数据
		while ((len = fis.read(buf)) != -1) {
			//5,创建输出流,并明确要写入的文件对象
			File partFiles = new File(destDir, (++count) + ".part");
			fos = new FileOutputStream(partFiles);
			fos.write(buf, 0, len);
			fos.close();
		}
		
		//应该在产生碎片文件时,需要产生一个配置文件。至少要记录碎片的个数和源文件的名字
		//partcount = 5, filename = 1.mp4
		//配置文件中存储的是键值信息,可使用Properties集合
		Properties prop = new Properties();
		prop.setProperty("partcount", Integer.toString(count));
		prop.setProperty("filename", srcFile.getName());
		
		File configFile = new File(destDir, ++count + ".properties");
		fos = new FileOutputStream(configFile);
		prop.store(fos, "save part file info");
		
		fis.close();
		fos.close();
	}
	

}

按照字节数截取一个字符串

按照字节数截取一个字符串,例如"abc你好",如果截取到半个中文,舍弃。比如截取4个字节,就是“abc”,截取5个字节,就是“abc你”。

package cn.liayun.otherio.splitfile;

public class Test {

	public static void main(String[] args) {
		/*
		按照字节数截取一个字符串,"abc你好",如果截取到半个中文,舍弃。比如截取4个字节,abc。截取5个字节,abc你。
		定义功能实现。
		
		字符串--->字节数组,编码。
		字节数组--->字符串,解码。
		
		友情提示:GB2312编码的一个中文是两个字节,而且两个字节的最高位都是1,也就是说是一个负数。
		
		思路:
		1,提示中告诉我中文两个字节都是负数;
		2,判断截取的最后一个字节是否是负数?
		      如果不是,直接截取。
		      如果是,就往回判断前一个是否是负数,并记录住负数的个数,如果连续的负数有奇数个,舍弃最后一个字节。
		      如果连续的负数是偶数个,不舍弃,哦耶!
		*/
		
		//字符串转成字节数组
		String str = "abc你好";
		str = "abc琲琲cde琲琲";//-84 105
		byte[] buf = str.getBytes();
//		for (byte b : buf) {
//			System.out.print(b + ", ");
//		}
		
		for (int x = 0; x < buf.length; x++) {
			String temp = cutStringByCount(str, x + 1);
			System.out.println("截取" + (x + 1) + "个字节是:" + temp);
		}
	}

	public static String cutStringByCount(String str, int len) {
		//1,将字符串先转成字节数组,因为要判断截取的字节是否是负数(先有字节)
		byte[] buf = str.getBytes();
		//2,定义计数器,记录住负数的个数
		int count = 0;
		//3,对字节数组进行遍历,而且应该从截取长度的最后一个字节开始判断,并往回判断
		for (int x = len - 1; x >= 0; x--) {
			//4,在遍历过程中,只要满足了负数,就进行计数。只要不是负数直接结束遍历
			if (buf[x] < 0) {
				count++;
			} else {
				break;
			}
		}
		
		//5,对遍历后的计数器的值进行判断,奇数,就舍弃最后一个字节,并将字节数组转成字符串;偶数,不舍弃,将字节数组转成字符串
		if (count % 2 ==0) {
			return new String(buf, 0, len);
		} else {
			return new String(buf, 0, len - 1);
		}
		
	}

}

猜你喜欢

转载自blog.csdn.net/yerenyuan_pku/article/details/84669496