IO流的分类:
按照数据流向分类:
输入流:读入数据
输出流:写出数据
按照数据类型分类:
字节流
字符流
什么情况下使用哪种流呢?
如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流。
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
字符缓冲流:
BufferedWriter:字符缓冲输出流
BufferedReader:字符缓冲输入流
String类中的编码和解码
public String(byte[] bytes, Charset charset):通过使用指定的字符集解码字节数组。
public byte[] getBytes(Charset charset):使用指定的字符集把字符串编码为字节数组。
编码:把看得懂的变成看不懂的
解码:把看不懂的变成看的懂的。
把字符串编码为字节数组:默认是gbk
String s = “你在吗?”;
byte[] bys = s.getBytes(); //默认是gbk
byte[] bysGBK = s.getBytes(“gbk”);
byte[] bysUTF = s.getBytes(“UTF-8”);
System.out.println(Arrays.toString(bys)); //[-60, -29, -44, -38, -62, -16, -93, -65]
System.out.println(Arrays.toString(bysGBK)); //[-60, -29, -44, -38, -62, -16, -93, -65]
System.out.println(Arrays.toString(bysUTF)); //[-28, -67, -96, -27, -100, -88, -27, -112, -105, -17, -68, -97]
把字节数组解码为字符串:默认也是gbk
String s = “你在吗?”;
byte[] bys = s.getBytes(); //通过默认编码(gbk)编码转换为字节数组
String ss = new String(bys); //通过默认编码(gbk)解码转换为字符串
String ssGBK = new String(bys,“gbk”);
System.out.println(ss); //你在吗?
System.out.println(ssGBK); //你在吗?
解码和编码的格式必须一致才能正确:
String s = “你在吗?”;
byte[] bys = s.getBytes(“UTF-8”); //采用UTF-8字符集来编码
String ssUTF = new String(bys,“UTF-8”); //通过UTF-8字符集来解码
String ssGBK = new String(bys,“gbk”); //通过gbk字符集来解码(跟编码的字符集不相同,因此会报错)
System.out.println(ssUTF); //你在吗?
System.out.println(ssGBK);
OutputStreamWriter 字符输出流
public OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流(gbk)
public OutputStreamWriter(OutputStream out, String charsetName):根据指定编码把字节流数据转换为字符流
字节流 = 字符流 + 编码表
OutputStreamWriter = FileOutputStream + 编码表(默认gbk)
编码格式问题
//创建对象(默认gbk)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“osw.txt”));
OutputStreamWriter oswGBK = new OutputStreamWriter(new FileOutputStream(“oswGBK.txt”), “gbk”);
//向文件中写数据
osw.write(“我是用默认编码写的:想你”);
oswGBK.write(“我是用gbk写的:想你”);
osw.close();
oswGBK.close();
1
2
3
4
5
6
7
8
9
10
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):写一个字符串的一部分
//创建对象(默认gbk)(向文件中写数据,相对于程序来说,就是向外输出,向外去写,所以是OutputStreanWriter)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“osw.txt”));
osw.write(‘a’); //写一个字符
osw.write(97); //写一个字符
osw.write(’\n’); //写一个字符
char[] chs = {‘i’,‘l’,‘o’,‘v’,‘e’,‘y’,‘o’,‘u’};
osw.write(chs); //写一个字符数组
osw.write(’\n’); //写一个字符
osw.write(chs, 1, 4); //写一个字符数组的一部分
osw.write(’\n’); //写一个字符
osw.write(“你最漂亮”,1, 3); //写一个字符串的一部分
osw.close(); //close方法会先刷新,然后在关闭。
close()和flush()的区别是什么?
1、close():关闭流对象前,要先刷新缓冲区。在关闭该流之后,流对象不可以继续再使用,再调用 write() 或 flush() 将导致抛出 IOException。
2、flush():仅仅刷新缓冲区,刷新之后流对象还可以继续使用。
数据之前保存在缓冲区,当flush刷新之后数据才会写入文件中。
InputStreamReader 字符输入流
public InputStreamReader(InputStream in):用默认的编码读取数据(gbk)
public InputStreamReader(InputStream in,String charsetName):用指定的编码读取数据
字节流 = 字符流 + 编码表
InputStreamReader = FileInputStream + 编码表(默认gbk)
编码格式问题:解码使用的字符集格式必须和编码使用的字符集格式相同此案呢个者却的解码
InputStreamReader isr = new InputStreamReader(new FileInputStream(“osw.txt”));
//从文件中一次读取一个字符(char)(采用默认编码格式读取)
int ch = 0;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
System.out.println();
System.out.println("-------");
//采用gbk编码读取文件中字符
InputStreamReader isrGBK = new InputStreamReader(new FileInputStream(“osw.txt”),“gbk”);
int chGBK = 0;
while((chGBK = isrGBK.read()) != -1){
System.out.print((char)chGBK);
}
InputStreamReader的方法:
int read():一次读取一个字符
int read(char[] chs):一次读取一个字符数组
InputStreamReader isr = new InputStreamReader(new FileInputStream(“osw.txt”));
//一次读取一个字符:read()(效率很低)
int ch = 0;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
//一次读取一个字符数组
char[] chs = new char[1024];
int len = 0;
while((len = isr.read(chs)) != -1){
System.out.print(new String(chs,0,len));
}
实现文件的复制:
//数据源
InputStreamReader isr = new InputStreamReader(new FileInputStream(“a.txt”));
//目的地
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“b.txt”));
//读写数据
char[] chs = new char[1024];
int len = 0;
while((len = isr.read(chs)) != -1){
osw.write(chs,0,len); //写字符数组的指定部分
osw.flush(); //当资源多的时候,需要flush,少可以不用
}
osw.close();
isr.close();
转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。FileWriter和FileReader作为子类来代替InputStreamReader和OutputStreamWriter
FileWriter 和 FileReader( 作为OutputStreamWriter 和 InputStreamReader的子类)
public class FileWriter extends OutputStreamWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream上构造一个 OutputStreamWriter。
复制文本文件
//封装数据源
FileReader fr = new FileReader(“a.txt”);
//封装目的地
FileWriter fw = new FileWriter(“c.txt”);
//一次一个字符
int ch = 0;
while((ch = fr.read()) != -1){
fw.write(ch);
}
// 一次一个字符数组
char[] chs = new char[1024];
int len = 0;
while((len = fr.read(chs)) != -1){
fw.write(chs, 0, len);
fw.flush();
}
fw.close();
fr.close();
反射总结
如何获取.Class文件对象
1, 通过Object类 getClass()方法获取 Class对象
2, 通过类名.class 方式 获取 Class对象
3, 通过反射的方式, Class.forName(String classname) 获取Class对象
public static Class<?> forName(String className)throws ClassNotFoundException
返回与带有给定字符串名的类或接口相关联的 Class 对象
通过反射, 获取类中的构造方法,并完成对象的创建
获取指定的构造方法
public Constructor getConstructor(Class<?>… parameterTypes)
获取指定的public修饰的构造方法
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)
获取指定的构造方法,包含私有的
获取所有的构造方法
public Constructor<?>[] getConstructors() 获取所有的public 修饰的构造方法
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法,包含私有的
通过反射, 获取类中的构造方法,并完成对象的创建
步骤:
1,获取字节码文件对象
2,通过字节码文件对象 ,获取到指定的构造方法
getConstructor(参数);
3,通过构造方法,创建对象
public T newInstance(Object… initargs)
私有构造方法,创建对象
1,获取字节码文件对象
2,通过字节码文件对象 ,获取到指定的构造方法
getDeclaredConstructor (参数);
3,暴力访问
con.setAccessible(true);
4,通过构造方法,创建对象
public T newInstance(Object… initargs)
通过反射,获取Class文件中的方法
获取指定的方法
public Method getMethod(String name, Class<?>… parameterTypes)
获取指定的public方法
public Method getDeclaredMethod(String name, Class<?>… parameterTypes)
获取指定的任意方法,包含私有的
获取所有的方法
public Method[] getMethods() 获取本类与父类中所有public 修饰的方法
ublic Method[] getDeclaredMethods()获取本类中所有的方法,包含私有的
通过反射,调用方法
步骤:
1,获取Class对象
2,获取构造方法,创建对象
3,获取指定的public方法
4,执行方法
public Object invoke(Object obj, Object… args)
私有方法的调用:
1,获取Class对象
2,获取构造方法,创建对象
3,获取指定的private方法
4,开启暴力访问
m5.setAccessible(true);
5,执行方法
public Object invoke(Object obj, Object… args)
通过反射,获取成员变量(字段)
获取指定的成员变量
public Field getField(String name) 获取public修饰的成员变量
public Field getDeclaredField(String name) 获取任意的成员变量,包含私有
获取所有的成员变量
public Field[] getFields() 获取所有public修饰的成员变量
public Field[] getDeclaredFields() 获取司所有的成员变量,包含私有
通过反射,获取成员 变量,并赋值使用
步骤:
1,获取字节码文件对象
2,获取构造方法,创建对象
3,获取指定的成员变量
4,对成员变量赋值\获取值操作
public void set(Object obj, Object value) 赋值
public Object get(Object obj) 获取值
私有成员变量的使用
步骤:
1,获取字节码文件对象
2,获取构造方法,创建对象
3,获取指定的成员变量
4,开启暴力访问
5,对成员变量赋值\获取值操作
public void set(Object obj, Object value) 赋值
public Object get(Object obj) 获取值