数据流
数据流是操作基本数据类型的流,分为数据输入流和数据输出流。下面分别来对它们进行介绍。
数据输入流
概述
数据输入流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);
}
}
}