这一块的内容主要是有关字符流,以及序列化的内容。
编码表
由字符及其对应的数值组成的一张表
通过字符集解码字符数组
- public String(byte[] bytes,Charset charset)
- public byte[] getBytes(Charset charset)
总结:
编码:把看的懂的变成看不懂的,类似于加密
String – byte[]
解码:把看不懂的变成看的懂的,根据编码表
byte[] – String
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "晚上";
//String -- byte[]
byte[] gbk = s.getBytes("GBK");
for(byte b:gbk){
System.out.println(b);
}
System.out.println("************************");
byte[] utf = s.getBytes("UTF-8");
for(byte b1:utf){
System.out.println(b1);
}
System.out.println("************************");
byte[] unicodes = s.getBytes("Unicode");
for (byte b2:unicodes) {
System.out.println(b2);
}
System.out.println("************************");
//byte[] -- String
String s1 = new String(unicodes,"Unicode");
System.out.println(s1);
}
//-51
//-19
//-55
//-49
//************************
//-26
//-103
//-102
//-28
//-72
//-118
//************************
//-2
//-1
//102
//90
//78
//10
//************************
//晚上
字符流(也叫做转换流)
字符流 = 字节流 + 编码表
字符输出流
- public OutputStreamWriter(OutputStream out)
根据默认的编码用字符作为桥梁将字节流的数据转换成字符流 - public OutputStreamWriter(OutputStream out,String charsetName)
根据指定的编码用字符作为桥梁将字节流的数据转换成字符流
public static void main(String[] args) throws IOException {
//设置写出的编码格式
// OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("b.txt"),
// "GBK");
// OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("b.txt"),
// "UTF-8");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("b.txt"),
"Unicode");
outputStreamWriter.write("中华人民共和国万岁");
outputStreamWriter.close();
}
OutputStreamWriter写数据
- public void write(int c)
- public void write(char[] cbuf)
- public void write(char[] cbuf,int off,int len)
- public void write(String str)
- public void write(String str,int off,int len)
注意:close()与flush()的区别:
- close()关闭流对象,但是会先刷新一次缓冲区。关闭之后,就不能调用
- flush()仅仅只是刷新,刷新之后还能继续调用
public static void main(String[] args) throws IOException {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("b.txt"));
//public void write(int c)
//写数字,写进去的是ASCII码
// outputStreamWriter.write(99);
// outputStreamWriter.flush();
// public void write(char[] cbuf)
//写字符数组,写进去的是每个字符
// char[] chars = new char[]{'a','b','c','d'};
// outputStreamWriter.write(chars);
//public void write(char[] cbuf,int off,int len)
//写字符数组,带着偏移量;写进去的是每个字符,带着偏移量
// char[] chars = new char[]{'a','b','c','d'};
// outputStreamWriter.write(chars,0,2);
//public void write(String str)
//写字符串,写进去的是字符串
// String s = "helloworld";
// outputStreamWriter.write(s);
//public void write(String str,int off,int len)
//写字符串,带着偏移量;写进去的是字符串,带着偏移量
String s = "helloworld";
outputStreamWriter.write(s,0,4);
outputStreamWriter.flush();
outputStreamWriter.close();
}
字符输入流
- public InputStreamReader(InputStream in)
读取数据,根据默认的编码用字符作为桥梁将字节流数据转换成字符流 - public InputStreamReader(InputStream in,String charsetName)
读取数据,根据指定的编码用字符作为桥梁将字节流数据转换成字符流
public static void main(String[] args) throws IOException {
// InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("b.txt"));
// InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("b.txt"),
// "GBK");
// InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("b.txt"),
// "Unicode");
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("b.txt"),
"UTF-8");
//一次读取一个字符
int b = 0;
while ((b = inputStreamReader.read()) != -1){
System.out.print((char) b);
}
inputStreamReader.close();
}
InputStreamReader读数据
- public int read() 一次只读一个字符
- public int read(char[] cbuf) 一次只读一个字符数组
public static void main(String[] args) throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("b.txt"));
//一次只读取一个字符
// int b = 0;
// while ((b = inputStreamReader.read()) != -1){
// System.out.println((char)b);
// }
//一次只读取一个字符数组
char[] chars = new char[1024];
int len = 0;
while ((len = inputStreamReader.read(chars)) != -1){
System.out.println(new String(chars,0,len));
}
inputStreamReader.close();
}
使用字符流实现文本文件的复制
public static void main(String[] args) throws IOException {
/*
将当前项目目录下的a.txt内容复制到当前目录下
数据源:
a.txt -- 读取数据 -- 字符流 -- InputStreamReader
目的地:
aCopy.txt -- 写出数据 -- 字符流 -- InputStreamWriter
*/
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("a.txt"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("aCopy.txt"));
//读写数据
//第一种方式 只读取一个字符
// int b = 0;
// while ((b = inputStreamReader.read()) != -1){
// outputStreamWriter.write(b);
// outputStreamWriter.flush();
// }
//第二种方式 读取一个字符数组
int len = 0;
char[] chars = new char[1024];
while ((len = inputStreamReader.read(chars)) != -1){
outputStreamWriter.write(chars,0,len);
outputStreamWriter.flush();
}
outputStreamWriter.close();
inputStreamReader.close();
}
使用字符流简化书写的方式复制文本文件
简化方式:FileReader、FileWriter
由于我们常见的操作都是使用本地默认的编码,我们基本上在使用的时候不去指定编码,而又因为字符流的名称有点长,所以Java就提供了子类给我们使用
字符流 = 字节流 + 编码表
OutputStreamWriter = FileOutputStream + 编码表
InputStreamReader = FileInputStream + 编码表
public static void main(String[] args) throws IOException {
//原先的写法
// InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("a.txt"));
//改进的写法
FileReader fileReader = new FileReader("a.txt");
//原先的写法
// OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("aCopy.txt"));
//改进的写法
FileWriter fileWriter = new FileWriter("aCopy.txt");
//第一种方式 一次只读取一个字符
// int b = 0;
// while ((b = fileReader.read()) != -1){
// fileWriter.write(b);
// fileWriter.flush();
// }
//第二种方式 一次只读取一个字符数组
int len = 0;
char[] chars = new char[1024];
while ((len = fileReader.read(chars)) != -1){
fileWriter.write(chars,0,len);
fileWriter.flush();
}
fileWriter.close();
fileReader.close();
}
字符缓冲流
- BufferedWriter:字符缓冲输出流
- 将文本文件写入到字符输入流,缓冲各个字符,以提供单个字符,数组和字符串的高效写入。
- 可以指定缓冲区大小,或者接受默认大小
- 默认值足够大,可以不用再去指定了
public static void main(String[] args) throws IOException {
//原本的写法
// BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
//改进的写法
BufferedWriter bufferedWriter1 = new BufferedWriter(new FileWriter("a.txt"));
bufferedWriter1.write("hello");
bufferedWriter1.write("world");
bufferedWriter1.flush();
bufferedWriter1.close();
}
- BufferedReader:字符缓冲输入流
- 从字符输入流读取文本,缓冲字符,以提供字符,数组或行的高效读取
- 可以指定缓冲区的大小,或者可以使用默认大小
- 默认值足够大,不需要再做改变
public static void main(String[] args) throws IOException {
//原本的写法
// BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
//改进的写法
BufferedReader bufferedReader1 = new BufferedReader(new FileReader("a.txt"));
//方式一,一个字符的读取
// int b = 0;
// while ((b = bufferedReader1.read()) != -1){
// System.out.println((char)b);
// }
//方式二,一个字符数组的读取
char[] chars = new char[1024];
int len = 0;
while ((len = bufferedReader1.read(chars)) != -1){
System.out.println(new String(chars,0,len));
}
bufferedReader1.close();
}
字符缓冲流复制文本文件
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("aCopy.txt"));
//一次读取一个字符
int b = 0;
while ((b = bufferedReader.read()) != -1){
bufferedWriter.write(b);
bufferedWriter.flush();
}
// 一次读取一个字符数组
int len = 0;
char[] chars = new char[1024];
while ((len = bufferedReader.read(chars)) != -1){
bufferedWriter.write(chars,0,len);
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
字符缓冲流的特殊功能
- BufferedWriter:void newLine()
写一行行分隔符,根据系统决定换行符的
行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符(’\n’)字符 - BufferedReader:void readLine()
读一行文字,一次读取一行数据
一行被视为由换行符(’\n’),
回车符(’\r’)中的任何一个或者随后的换行符终止
包含行的内容的字符串,不包含任何终止字符,如果达到流的末尾,则为null
public static void main(String[] args) throws IOException {
write();
read();
}
public static void read() throws IOException {
//创建字符缓冲流
BufferedReader bufferedReader = new BufferedReader(new FileReader("a.txt"));
//public String readLine() 读一行文字,一次读取一行数据
// String s = bufferedReader.readLine();
// System.out.println(s);
//最终版本
String line = null;
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
bufferedReader.close();
}
public static void write() throws IOException{
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a.txt"));
for(int i=0;i<10;i++){
bufferedWriter.write("大数据");
bufferedWriter.newLine();//换行
bufferedWriter.flush();
}
bufferedWriter.close();
}
字符缓冲流的特殊功能复制文本文件
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("aCopy.txt"));
String s = null;
while ((s = bufferedReader.readLine()) != null){
bufferedWriter.write(s);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
有关字符流、字节流的小练习
复制图片,用字节流复制,四种方式
- 一次读取一个字节
- 一次读取一个字节数组
- 字节缓冲流一次读取一个字节
- 字节缓冲流一次读取一个字节数组(推荐这种写法)
public static void main(String[] args) throws IOException{
String input = "祥哥.jpg";
String out = "祥哥复制.jpg";
// fun1(input,out);
// fun2(input,out);
// fun3(input,out);
// fun4(input,out);
}
public static void fun1(String input,String out) throws IOException {
//一次读取一个字节
FileInputStream fileInputStream = new FileInputStream(input);
FileOutputStream fileOutputStream = new FileOutputStream(out);
int b = 0;
while ((b = fileInputStream.read()) != -1){
fileOutputStream.write(b);
fileOutputStream.flush();
}
fileOutputStream.close();
fileInputStream.close();
}
public static void fun2(String input,String out) throws IOException{
//一次只读取一个字节数组
FileInputStream fileInputStream = new FileInputStream(input);
FileOutputStream fileOutputStream = new FileOutputStream(out);
int len = 0;
byte[] bytes = new byte[2048];
while ((len = fileInputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0,len);
fileOutputStream.flush();
}
fileOutputStream.close();
fileInputStream.close();
}
public static void fun3(String input,String out) throws IOException{
//字节缓冲流 一次读取一个字节
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(input));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(out));
int b = 0;
while ((b = bufferedInputStream.read()) != -1){
bufferedOutputStream.write(b);
bufferedOutputStream.flush();
}
bufferedOutputStream.close();
bufferedInputStream.close();
}
public static void fun4(String input,String out) throws IOException{
//字节缓冲流,一次只读取一个字符数组
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(input));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(out));
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bufferedInputStream.read(bytes)) != -1){
bufferedOutputStream.write(bytes,0,len);
}
}
复制文本文件,使用字符流,五种方式
- 字符流一次只读取一个字符
- 字符流一次只读取一个字符数组
- 字符缓冲流一次只读取一个字符
- 字符缓冲流一次只读取一个字符数组
- 字符缓冲流特殊方法读写数据(推荐这种方法实现)
public static void main(String[] args) throws IOException{
String input = "a.txt";
String out = "aCopy.txt";
// fun1(input,out);
// fun2(input,out);
// fun3(input,out);
// fun4(input,out);
fun5(input,out);
}
public static void fun1(String input,String out)throws IOException {
//一次读取一个字符
// InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(input));
FileReader fileReader = new FileReader(input);
FileWriter fileWriter = new FileWriter(out);
int b = 0;
while ((b = fileReader.read()) != -1){
fileWriter.write(b);
fileWriter.flush();
}
fileWriter.close();
fileReader.close();
}
public static void fun2(String input,String out)throws IOException{
//一次只读取一个字符数组
FileReader fileReader = new FileReader(input);
FileWriter fileWriter = new FileWriter(out);
int len = 0;
char[] chars = new char[1024];
while ((len = fileReader.read(chars)) != -1){
fileWriter.write(chars,0,len);
fileWriter.flush();
}
fileWriter.close();
fileReader.close();
}
public static void fun3(String input,String out)throws IOException{
//字符缓冲流一次读取一个字符
BufferedReader bufferedReader = new BufferedReader(new FileReader(input));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(out));
int b = 0;
while ((b = bufferedReader.read()) != -1){
bufferedWriter.write(b);
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
public static void fun4(String input,String out)throws IOException{
//字符缓冲流一次只读取一个字符数组
BufferedReader bufferedReader = new BufferedReader(new FileReader(input));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(out));
char[] chars = new char[1024];
int len = 0;
while ((len = bufferedReader.read(chars)) != -1){
bufferedWriter.write(chars,0,len);
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
public static void fun5(String input,String out)throws IOException{
//使用字符缓冲流特殊方法读取数据
BufferedReader bufferedReader = new BufferedReader(new FileReader(input));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(out));
String s = null;
while ((s = bufferedReader.readLine()) != null){
bufferedWriter.write(s);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
把ArrayList集合中的字符串数据存储到文本文件
public static void main(String[] args) throws IOException {
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a.txt"));
for(String s : list){
bufferedWriter.write(s);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
}
键盘录入五个学生信息(姓名,语数英成绩)按总分高低存入文本文件
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a.txt"));
TreeSet<Student1> treeSet = new TreeSet<>(new Comparator<Student1>() {
@Override
public int compare(Student1 o1, Student1 o2) {
int i = o1.sum() - o2.sum();
return i;
}
});
Scanner sc = new Scanner(System.in);
System.out.println("请输入一些学生信息,姓名、语文成绩、英语成绩、数学成绩,#分割,输入exit结束");
while (true){
String x = sc.nextLine();
if ("exit".equals(x)){
break;
}
String[] split = x.split("#");
Student1 student1 = new Student1(split[0], Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]));
treeSet.add(student1);
}
bufferedWriter.write("学生信息如下");
bufferedWriter.write("姓名\t语文成绩\t英语成绩\t数学成绩");
bufferedWriter.newLine();
bufferedWriter.flush();
for(Student1 s:treeSet){
bufferedWriter.write(s.getName()+"\t"+s.getChinese()+"\t"+s.getEnglish()+"\t"+s.getMath());
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
}
对文件中一串字符串进行排序之后写入另一个文件
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a1.txt"));
BufferedReader bufferedReader = new BufferedReader(new FileReader("a.txt"));
String s = bufferedReader.readLine();
bufferedReader.close();
char[] chars = s.toCharArray();
Arrays.sort(chars);
// String s1 = chars.toString();
String s1 = new String(chars);
System.out.println(s1);
bufferedWriter.write(s1);
bufferedWriter.newLine();
bufferedWriter.close();
}
对IO的一个总结
序列化
- 序列化流:把对象按照流一样的方式存到文本文件或者在网络中传输
对象 – 流数据(ObjectOutputStream) - 反序列化:把文本文件中的流对象数据或者网络中的流数据还原成对象
流数据 – 对象(ObjectInputStream)
/**
* 未序列化的异常
* NotSerializableException: com.shujia.java.day21.Person
*
* 类的序列化由实现java.io.Serializable接口的类启用。
* 不实现此接口的类将不会使任何状态序列化或反序列化。
*
* 这个接口没有任何方法,类似于这种没有方法的接口,我们称之为标记接口
*
*
* InvalidClassException:
* com.shujia.java.day21.Person; local class incompatible:
* stream classdesc serialVersionUID = 301533426692145378,
* local class serialVersionUID = 1370790239890091773
*
* 为什么会有这种问题呢?
* Person类实现了序列化接口,它本身应该有个标记值
* 假设这个标记一开始是100.
* 开始时候:
* Person.class -- id=100
* write数据:oos.txt -- id=100
* read数据:oos.txt -- id=100
*
* 现在:
* Person.class -- id=200
* write数据:oos.txt -- id=100
* read数据:osos.txt -- id=100
*
* 但是,在实际开发中,需要保留历史数据,不能重新写入,怎么办呢?
*
* 由于我们知道的原因是id不匹配,每次修改java程序文件的时候,.class文件都会发生改变,对应的id值也会改变
* 所以就出现了这个问题。
* 如果说有一个办法可以让java程序文件的id值是一个固定的值,这样的话就算你再怎么改,id都不会变就更好了。
*
*
* 需求:
* 我现在不想序列化age成员变量,怎么办呢?
* Java提供了这么一个关键字:transient
*
*
*
* @author xiaohu
*/
public class Person implements Serializable {
private static final long serialVersionUID = 301533426692145378L; //加上这个之后,就可以读回来数据,怎么改变都可以了
private String name;
private int age;
// private transient int age; //有了这个东西之后,就固定了,不被改变,比如写入年龄25,加上这个,就不改变了
// int age; //这里第一次运行的是int age 之后 变成了 private int age 就读不回来了
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) {
//由于我们我们要对对象进行序列化,所以定义一个类
//序列化数据其实就是将对象持久化
try {
// write();
read();
} catch (IOException|ClassNotFoundException e) {
e.printStackTrace();
}
}
private static void read() throws IOException, ClassNotFoundException {
//创建ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
//Object readObject()
//从ObjectInputStream读取一个对象。
Object o = ois.readObject();
ois.close();
System.out.println(o);
}
private static void write() throws IOException {
//创建ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
//创建对象
Person zhangsan = new Person("zhangsan", 24);
//void writeObject(Object obj)
//将指定的对象写入ObjectOutputStream。
oos.writeObject(zhangsan);
oos.close();
}
感谢阅读,我是啊帅和和,一位大数据专业即将大四学生,祝你快乐。