IO
节点流 + 缓冲流(共8个)
IO流使用步骤、技巧
"IDEA中"
JUnit单元测试中,相对路径为当前Module下。
如果是main方法,相对路径为当前Project下。
========================================================================================================================
"IO流使用步骤"
①造文件/路径 //流的构造方法可以是 : 文件全路径 或者 File对象
②造流(用缓冲流)
③读写(续写)数据
④关闭资源:只需要关外层流
⑤try catch finally
=======================================================================================================================
"技巧"
字符流:文本文件(.txt、.java、.c、.cpp...)。 char[]、str.toCharArray()
字节流:二进制文件(图片、视频、声音、doc、ppt等)不会被损坏。 byte[]、str.getBytes()
熟悉之后写法:new BufferedInputStream(new FileInputStream(scrPath));
输出流构造方法,设置是否续写(,true)
=======================================================================================================================
//写文件时,文件不存在,自动创建文件,没设置续写则覆盖
System.out.println(new String(buf,0,len));
while((line = br.readLine())!=null){
System.out.println(line);
}
//设置续写
new BufferedWriter(new FileWriter(filePath,true));
bw.newLine(); //换行
//
IO 流体系
视频(非文本)加密
/**
* 非文本:字节流
* 非文本文件加密:异或5
* */
public static void code(String scrPath,String destPath){
//为了提高效率,都用缓存流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//造流:操作视频用字节流
bis = new BufferedInputStream(new FileInputStream(scrPath));
bos = new BufferedOutputStream(new FileOutputStream(destPath));
//读写操作
byte[] buff = new byte[1024];
int len;
while((len=bis.read(buff))!=-1){
//加密操作,异或操作
for (int i = 0; i < len; i++) {
buff[i] = (byte) (buff[i]^5);
}
//写入原文件
bos.write(buff,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("加密完成!");
}
}
视频(非文本)解密
/**
* 非文本文件解密:异或5
* */
public static void deCode(String scrPath,String destPath){
//为了提高效率,都用缓存流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//造流:操作视频用字节流
bis = new BufferedInputStream(new FileInputStream(scrPath));
bos = new BufferedOutputStream(new FileOutputStream(destPath));
//读写操作
byte[] buff = new byte[1024];
int len;
while((len=bis.read(buff))!=-1){
//加密操作,异或操作
for (int i = 0; i < len; i++) {
buff[i] = (byte) (buff[i]^5);
}
//写入原文件
bos.write(buff,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("解密完成!");
}
}
统计文本上每个字符出现的个数(Map)
/**
* 文本:字符流
* 获取文本上每个字符出现的个数(Map实现)
* 然后写进新文件
* */
public static void CountText(String scrPath,String destPath) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//1.造流
br = new BufferedReader(new FileReader(scrPath));
bw = new BufferedWriter(new FileWriter(destPath));
HashMap<Character,Integer> map = new HashMap<>();
//读写操作
char[] cbuff = new char[1024];
int len;
while ((len=br.read(cbuff))!=-1){
//遍历cbuff,将数据更新进map
for (int i = 0; i < len; i++) {
//如果map存在当前字符,value++;
if(map.containsKey(cbuff[i])){
map.put(cbuff[i],(map.get(cbuff[i])+1));
}else {
map.put(cbuff[i],1);
}
}
}
//把map的数据写入destPath
Set<Map.Entry<Character, Integer>> entries = map.entrySet();
for (Map.Entry<Character, Integer> entry : entries) {
switch (entry.getKey()){
case ' ':
bw.write("空格="+entry.getValue());break;
case '\t':
bw.write("tab建="+entry.getValue());break;
case '\r':
bw.write("回车="+entry.getValue());break;
case '\n':
bw.write("换行="+entry.getValue());break;
default:
bw.write(entry.getKey()+"="+entry.getValue());break;
}
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("文本统计完成!");
}
}
其他处理流
字符集
ASCII:美国标准信息交换码
ISO8859-1:拉丁码表
GB2312:早期中文编码表
GBK:升级版中文编码表
Unicode:国际标准码
UTF-8:变长的编码格式
转换流:字符流
========================================================================================================================
InputStreamReader(InputStream,...) : 字节输入流 ==> 字符输入流----解码(提供解码字符集)(看不懂 ==> 看得懂)
OutputStreamWriter(OutputStream,...) : 字符输出流 ==> 字节输出流----编码(设置编码字符集)(看得懂 ==> 看不懂)
作用:提供字节流与字符流之间的转换,解码以及编码
========================================================================================================================
public static void Test01(String srcPath,String destPath) {
//可以嵌套缓冲流,不过只能读取文本,因为是下面四个字符流
BufferedReader br = null;
BufferedWriter bw = null;
long start = System.currentTimeMillis();
long end=0;
try {
//转换流:字符流
InputStreamReader isr = new InputStreamReader(new FileInputStream(srcPath));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destPath));
//缓冲流
br = new BufferedReader(isr);
bw = new BufferedWriter(osw);
//注意InputStreamReader 和 OutputStreamWriter 属于字符流
char[] cbuff = new char[1024];
int len;
while((len=br.read(cbuff))!=-1){
//写入新文件
bw.write(cbuff,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bw!=null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br!=null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
end = System.currentTimeMillis();
System.out.println("复制成功,共花了"+(end-start)+"毫秒");
}
}
对象处理流(类要实现Serializable,并提供serialVersionUID)
要求
(1) 自定义类实现Serializable接口
(2) 自定义类提供一个全局常量 private static final long serialVersionUID = 263298232L;
防止版本不兼容:类内容发生改变,导致反序列化失败
(3) 自定义类中内部所有属性也必须是可序列化的
对象序列化处理流:ObjectOutputStream
对象反序列化处理流:ObjectInputStream
public class ObjectOutputStream_ {
public static void main(String[] args) throws IOException {
//序列化后,保存的文件格式是java自己定的格式,所以我们可以随便给后缀名
String filePath = "f:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据
oos.writeInt(100); //序列化int型数据
oos.writeBoolean(true); //序列化Boolean型数据
oos.writeChar('a'); //序列化Char型数据
oos.writeUTF("我是字符串"); //序列化String型数据
//当要序列化自定义对象时,对象实现Ser\
oos.writeObject(new Dog("金毛","绿色"));
oos.close();
}
}
//实现序列化 Serializable
static class Dog implements Serializable {
private String name;
private String color;
//唯一标识号,实现这个之后,序列化之后改变类也能反序列化出来
private static final long serialVersionUID = 1L;
public Dog(String name, String color) {
this.name = name;
this.color = color;
}
}
`
读取(反序列化)的顺序一定要和写入(序列化)顺序一致
如果要读取自定义类,输出信息,就必须在读取类下面定义这个类
static class Dog implements Serializable
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String filePath = "f:\\data.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
//读取的顺序一定要和存入的顺序一致,不然报错
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readUTF());
Dog dog = (Dog)ois.readObject();
ois.close();
/*
byte[] buf = new byte[1024];
ois.readFully(buf);
System.out.println();*/
}
static class Dog implements Serializable {
private String name;
private String color;
//唯一标识号,实现这个之后,序列化之后改变类也能反序列化出来
private static final long serialVersionUID = 1L;
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Dog(String name, String color) {
this.name = name;
this.color = color;
}
}
}
RandomAccessFile:直接父类Object,和四个抽象基类没关系,但是属于io
二维数组写入与读出
//写入内存
public static void write(int[][] sparseArr){
//写入内存
String filePath = "D:\\CODE\\算法\\DataStructes\\src\\reader.txt";
ObjectOutputStream bos = null;
try {
bos = new ObjectOutputStream(new FileOutputStream(filePath));
bos.writeObject(sparseArr);
//一定要刷新或者关闭
bos.flush();
System.out.println("稀疏数组写入成功");
} catch (IOException e){
e.getCause();
} finally {
try {
if(bos!=null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//读取稀疏数组
public static int[][] ride(){
String filePath = "D:\\CODE\\算法\\DataStructes\\src\\reader.txt";
ObjectInputStream bis = null;
int[][] sparseArr01 = null;
try {
bis = new ObjectInputStream(new FileInputStream(filePath));
sparseArr01 = (int[][]) bis.readObject();
System.out.println("========从内存中读取稀疏数组成功!==========");
}catch (IOException | ClassNotFoundException e){
e.getCause();
}finally {
try {
if(bis!=null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sparseArr01;
}
面试题
1、流的三种分类方式
流向:输入流、输出流
数据单位:字节流、字符流
流的角色:节点流、处理流