转换流
处理流二:转换流的使用
1,转换流:属于字符流
InputStreamRead:将一个字节的输入流转换为字符的输入流;
OutputStreamWriter:将一个字符的输出流转换为字节的输出流;
2.作用:提供字节流与字符流之间的转换;
3.解码:字节、字节数组–>字符数组、字符串
编码:字符数组、字符串–>字节、字节数组
4.字符集
针对中文编码(gb2312,gbk),我们这里最多两个两个字节。如何判断是一个字节表示一个字符还是两个字节表示一个字符。判断标准是,如果开头是0那么是一个字节表示一个字符;如果是开头是1那么表示是两个字节表示一个字符。
ANSI:美国国家标准学会(AMERICAN NATIONAL STANDARDS INSTITUTE: ANSI )
InputStreamReader的使用,实现字节的输入流到字符的输入流的转换
package com.atguigu.java;
import org.junit.Test;
import java.io.*;
public class InputStreamReaderTest {
//InputStreamReader的使用,实现字节的输入流到字符的输入流的转换
@Test
public void testInputStreamReader() throws IOException {
FileInputStream fis = new FileInputStream("dbcp.txt");
//InputStreamReader isr = new InputStreamReader(fis);//默认使用系统默认的字符集
//参数二指明了字符集,具体使用哪个字符集,取决于文件保存时使用的字符集;大小写不敏感
InputStreamReader isr = new InputStreamReader(fis,"utf-8");//这里的字符集的选择是当初创建时是什么字符集就用什么字符集
char[] cbuf = new char[20];
int len;
while((len= isr.read(cbuf))!=-1){
String str = new String(cbuf, 0, len);
System.out.print(str);
}
isr.close();
}
}
综合使用InputStreamReader和OutputStreamWriter,这里输出的为用gbk编码的文件。
@Test
//综合使用InputStreamReader和OutputStreamWriter
public void test1() throws IOException {
File file1 = new File("dbcp.txt");
File file2 = new File("dbcp_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis, "utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
char[] cbuf = new char[20];
int len;
while((len=isr.read(cbuf))!=-1){
osw.write(cbuf,0,len);
}
osw.close();
isr.close();
}
对象流要掌握,其他流了解。
练习题答案:
package com.atguigu.java;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//其他流的使用
/*
1.标准的输入输出流
2.打印流
3.数据流
*/
//练习:从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至输入
//字符“e”或字符“exit”退出
public class otherStreamTest {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
while (true){
System.out.println("请输入字符串:");
String data = br.readLine();
//这里是避免控制人问题,不建议这种写法
//(data.equalsIgnoreCase("e")||data.equalsIgnoreCase("exit"))
if ("e".equalsIgnoreCase(data)||"exit".equalsIgnoreCase(data)){
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println(upperCase);
}
br.close();
}
}
标准输入输出流,实现我们自己的scanner。
package com.atguigu.exer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyInput {
//Read a String from keyboard
public static String readString() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//Declare and initialize the string
String string = "";
//Get the string from the keyboard
try {
string = br.readLine();
} catch (IOException ex) {
System.out.println(ex);
}
//Return the string obtained from the keyboard
return string;
}
//Read an int value from the keyboard
public static int readInt(){return Integer.parseInt(readString());}
//Read a double value from the keyboard
public static double readDouble(){return Integer.parseInt(readString());}
//Read a byte value from the keyboard
public static double readByte(){return Integer.parseInt(readString());}
//Read a short value from the keyboard
public static double readShort(){return Integer.parseInt(readString());}
//Read a long value from the keyboard
public static double readLong(){return Integer.parseInt(readString());}
//Read a float value from the keyboard
public static double readFloat(){return Integer.parseInt(readString());}
}
System.setOut()方法就是不会在控制台输出,在指定文件输出。
中间for循环代码生成结果:
@Test
//将内存中字符串、基本数据类型的变量写出到文件中
public void test() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeUTF("孔空");
dos.flush();//刷新操作,将内存中的数据写入文件。
dos.writeInt(21);
dos.flush();
dos.writeBoolean(true);
dos.flush();
dos.close();
}
@Test
//这里不要直接打开文件,操作是不对的,得读完之后在控制台看
//将文件中存储的基本数据类型变量和字符串读取在内存中,保存在变量中
public void test1() throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
//顺序很重要,写进去什么顺序读进去就是什么顺序
String name = dis.readUTF();
int age = dis.readInt();
boolean isMale = dis.readBoolean();
System.out.println("name:"+name);
System.out.println("age:"+age);
System.out.println("isMale:"+isMale);
dis.close();
}
对象流
在这里插入图片描述
这里针对的是对象流阐述的序列化,其实在客户端与服务端,app之间也是用的序列化和反序列化。
序列化机制:
对象序列化机制云南徐把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上,或者通过网络讲这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以回复称原来的Java对象。(跨进程访问,都要求可序列化(就是json))
String类的序列和反序列:
package com.atguigu.java;
import org.junit.Test;
import java.io.*;
public class ObjectInputOutputStreamTest {
/*
首先是序列化过程,将内存中的Java对象保存在磁盘中或通过网络传输出去
使用objectOutputStream实现
*/
@Test
public void test1() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("即使再小的帆也能远航"));//String是内存层面的,有可能会被内存回收,我们把它写入到硬盘就不会了,也就是持久
oos.flush();
oos.close();
}
/*
反序列化,将磁盘文件中的对象还原为内存中的一个Java对象
*/
@Test
public void test2() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String) obj;
System.out.println(str);
ois.close();
}
}
自定义类的序列和反序列:
package com.atguigu.java;
import org.junit.Test;
import java.io.*;
public class ObjectInputOutputStreamTest {
/*
首先是序列化过程,将内存中的Java对象保存在磁盘中或通过网络传输出去
使用objectOutputStream实现
要想一个Java对象是可序列化的,需要满足相应的要求,见person类
*/
@Test
public void test1() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("即使再小的帆也能远航"));//String是内存层面的,有可能会被内存回收,我们把它写入到硬盘就不会了,也就是持久
oos.flush();
oos.writeObject(new Person("孔空",21));
oos.flush();
oos.close();
}
/*
反序列化,将磁盘文件中的对象还原为内存中的一个Java对象
*/
@Test
public void test2() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String) obj;
Person p = (Person) ois.readObject();
System.out.println(p);
System.out.println(str);
ois.close();
}
}
不加的话,如果对对象进行修改。就会报错,因为Java自己帮你生成的是随机的,下次你改过以后他就不认识了。
package com.atguigu.java;
import java.io.Serializable;
/*
1.必须要继承Serializable接口。
该接口没有任何方法声明,故我们称此类为标识接口
2.一定要给一个全局常量,随意给一个值就行
3.除了当前Person类实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的(默认情况下基本数据类型就是可序列化的)。
补充:ObjectInputStream和ObjectOuputStream不能序列化static和transient修饰的成员变量(将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。)。
*/
public class Person implements Serializable {
public static final long serialVersionUID = 242142142142L;
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
随机存取文件流
package com.atguigu.java;
import org.junit.Test;
import java.io.IOException;
import java.io.RandomAccessFile;
/*
RandomAccessFile的使用
1.直接继承于Object类,实现了DataInput和DataOutput接口
2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
如果写出道德文件存在,则会对原有文件进行覆盖,默认从头开始覆盖。
4.可以通过线管操作,实现RandomAccessFile 插入效果
*/
public class RandomAccessFileTest {
@Test
public void test1() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("QQ图片20211018170403.png", "r");
RandomAccessFile raf2 = new RandomAccessFile("QQ图片202110181704037.png", "rw");
byte[] buffer = new byte[1024];
int len;
while((len=raf1.read(buffer))!=-1){
raf2.write(buffer,0,len);
}
raf1.close();
raf2.close();
}
}
使用RandomAccessFile实现数据的插入:
/*
使用RandomAccessFile实现数据的插入
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf2 = new RandomAccessFile("data.txt", "rw");
raf2.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("data.txt").length());//StringBuilder实际上造的是一个数组,这里的.length是他早的数组的长度
byte[] buffer = new byte[20];
int len;
while ((len=raf2.read(buffer))!=-1){
builder.append(new String(buffer,0,len));
}
//调回指针,写入“xyz”
raf2.seek(3);
raf2.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf2.write(builder.toString().getBytes());
raf2.close();
//思考:可以将StringBuilder替换为ByteArrayOutputStream
}
ByteArrayOutputStream的使用:
最后了解: