IO
总共16个流
java.io.FileInputStream(掌握)
java.io.FileOutputStream(掌握)
java.io.FileReader
java.io.FileWriter
转换流(字节流->字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter
缓冲流
java.io.BufferedInputStream
java.io.BufferedOutputStream
java.io.BufferedReader
java.io.BufferedWriter
数据流
java.io.DataInputStream
java.io.DataOutputStream
标准输出流
java.io.PrintWriter
java.io.PrintStream(掌握)
对象专属流
java.io.ObjectInputStream(掌握)
java.io.ObjectOutputStream
1、掌握
FileInputStream
FileOutputStream
应用
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
使用FileInputStream + FileoutputStream完成拷贝,一边读一边写
使用字节流拷贝的时候,文件类型不限
*/
public class CopyTest {
public static void main(String[] args) {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
//创建输入流
fis=new FileInputStream("tempfile");
//创建输出流
fos=new FileOutputStream("C:\\Users\\Desktop\\java\\文件操作Test/tempfile");
byte[] bytes=new byte[100*1024];
int readCount=0;
while((readCount= fis.read(bytes))!=-1){
fos.write(bytes,0,readCount);
}
//输出流最后要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//分开try/catch相互不影响
if(fos!=null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
ObjectInputStream
ObjectOutputStream
涉及序列化和反序列化
应用:
Student类
import java.io.Serializable;
public class Student implements Serializable {
//Java虚拟机看到Serializable接口之后会自动生成一个序列化版本号
//这里没有手动写出来,Java虚拟机会默认提供这个序列化版本号
//序列化版本号
private int no;
private String name;
public Student() {
}
public Student(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
序列化
序列化也需刷新和关闭
import com.dhjavacode.java.Student;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
/*
Java对象从内存中放入硬盘中:序列化(Serialize)
因为不能一次直接把整个对象放过去,所以会分块,也就有了序列
Java对象从硬盘恢复到内存中:反序列化
因为内一块都有编号,能组装回去(DeSerialize)
ObjectOutputStream 负责序列化
ObjectInputStream 负责反序列化
参与序列化和反序列化的对象必须实现Serializable接口
public interface Serializable{
}
这个接口什么代码都没有,,其标识作用,Java虚拟机看到后会提供序列化版本号
*/
public class ObjectoutputStreamTest {
public static void main(String[] args) throws Exception {
Student stu1=new Student(1111,"zhangsan");
//序列化,序列化到文件students
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("students"));
//序列化对象
//**参与序列化对象所属类必须实现Serializable接口
oos.writeObject(stu1);
//刷新
oos.flush();
//关闭
oos.close();
}
}
2、了解
FileReader
文件输入流,只能读普通文本,读取文本内容方便
用法和FileInputStream相似
FileWriter
文件输出流,只能写普通文本
用法和FileOutputStream相似
输出完成之后也需调用.flush()方法
PrintWriter
PrintStream
默认输出到控制台(再看视频)
----------------------------------------------------------------分割线----------------------------------------------------------
File
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileTest01 {
public static void main(String[] args) throws IOException {
File f1=new File("D:/javacode/file");
System.out.println(f1.exists());//判断文件是否存在,当有file文件时返回true
//如果不存在,则以文件的形式创建
if(!f1.exists())f1.createNewFile();
//如果不存在,则以目录的形式创建。若上一层目录也不存在,则不会创建。
if(!f1.exists())f1.mkdir();
//多重目录新建
File f2=new File("D:/javacode/a/b/c");
if(!f2.exists())f1.mkdirs();
//常用方法
File f3=new File("D:/javacode/a/b/c");
//获取文件父路径
String parentPath=f3.getParent();
System.out.println(parentPath);
//获取父文件
File f4=f3.getParentFile();
//获取绝对路径
System.out.println(f4.getAbsoluteFile());
File f5=new File("D:/javacode/file");
//获取文件名
System.out.println("文件名"+f5.getName());
//判断是否是目录
System.out.println(f5.isDirectory());
//判断是否是文件
System.out.println(f5.isFile());
//最后一次修改时间
long haoMiao=f5.lastModified();//获取毫秒是从1970.1.1到现在的总毫秒
Date time = new Date(haoMiao);
System.out.println(time);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String sdTime =sdf.format(time);
System.out.println(sdTime);
//获取文件字节大小
System.out.println(f5.length());
//listFiles返回当前目录下所有子目录,返回File[] listFiles()
File f6=new File("D:/javacode");
File[] files=f6.listFiles();
for(File ff:files){
System.out.println(ff.getName());
}
}
}
注:多重目录是在已有的最后一位文件里创建
若将多重目录写成.mkdir()则不会创建任何也不会报错
应用:带目录文件拷贝
import java.io.*;
public class CopyAll {
public static void main(String[] args) {
//拷贝源
File srcFile=new File("C:\\Users\\代涵\\Desktop\\java");
//拷贝目标
File desFile=new File("D:\\javacode\\CopyTest");
copyDir(srcFile,desFile);
}
/*
srcFile 拷贝源
desFile 拷贝目标
*/
private static void copyDir(File srcFile, File desFile) {
if(srcFile.isFile()) {
//如果是文件,一边读一边写
FileInputStream in = null;
FileOutputStream out=null;
try {
//读文件
in=new FileInputStream(srcFile);
String path=desFile.getAbsolutePath().endsWith("\\")?desFile.getAbsolutePath()+srcFile.getAbsolutePath().substring(20):desFile.getAbsolutePath()+"\\"+srcFile.getAbsolutePath().substring(20);
out=new FileOutputStream(path);
byte[] bytes=new byte[1024*1024];
int readCount=0;
while((readCount=in.read(bytes))!=-1){
out.write(bytes,0,readCount);
}
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(out!=null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(in!=null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return;
}
//获取源下的子目录
File[] files=srcFile.listFiles();
for(File file:files){
if(file.isDirectory()){
//System.out.println(file.getAbsoluteFile());
//源C:\Users\代涵\Desktop\java
//目标D:\javacode\CopyTest
String srcDir=file.getAbsolutePath();
System.out.println(srcDir.substring(20));
String desDir=desFile.getAbsolutePath().endsWith("\\")?desFile.getAbsolutePath()+srcDir.substring(20):desFile.getAbsolutePath()+"\\"+srcDir.substring(20);
System.out.println(desDir);
File newFile=new File(desDir);
if(!newFile.exists()){
newFile.mkdirs();
}
}
//递归
copyDir(file,desFile);
}
}
}
反射机制
重点是通过反射机制获取并修改属性和调用方法
作用:
通过Java语言的反射机制可以操作字节码文件。可读可修改。操作代码片段
包:java.lang.reflect.*
反射机制相关重要类:
java.lang.Class:代表这个字节码,代表一个类
java.lang.reflect.Method:代表字节码中的方法字节码
java.lang.reflect.Constructor:代表字节码中的构造方法字节码
java.lang.reflect.Field:代表字节码中的属性字节码
获取类操作
要操作一个类的字节码,需要首先获取这个类的字节码。三种方式:
1、Class.forName(); 静态方法
2、实例.getClass()方法
3、实例.class属性
package com.javacode.reflect;
import java.util.Date;
public class ReflectTest1 {
public static void main(String[] args) throws Exception {
/*
Class.forName()
1、静态方法
2、参数是字符串
3、字符串需要是完整的类名
4、完整类名必须带有包名,java.lang包也不能省略
*/
Class c1=Class.forName("java.lang.String");
Class c2=Class.forName("java.util.Date");
Class c3=Class.forName("java.lang.Integer");
Class c4=Class.forName("java.lang.System");
//Java中任何一个对象都有一个方法叫做getClass()
String s="asd";
Class x=s.getClass();//x代表String.class字节码文件,x代表String类型
System.out.println(c1==x);//true
//Java中任何一种类型,包括基本数据类型,都是有.class属性的
Class z=String.class;
Class k= Date.class;
}
}
反射机制实例化对象
通过反射机制可以更灵活的创建对象
package com.javacode.reflect;
/*
获取到Class能做什么:更灵活的创建对象。
*/
public class ReflectTest2 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射机制获取Class,通过Class实例化对象
Class c=Class.forName("com.javacode.reflect.User");
try {
//返回对象,执行无参构造。** .newInstance()方法底层调用无参构造
Object o=c.newInstance();
System.out.println(o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
灵活创建例子:
通过Properties配置文件创建实例
package com.javacode.reflect;
import java.io.FileReader;
import java.util.Properties;
public class ReflectTest3 {
public static void main(String[] args) throws Exception {
FileReader reader=new FileReader("src\\com\\javacode\\reflect\\classname.Properties");
Properties pro=new Properties();
pro.load(reader);
//load()方法可以传入FileReader对象也可以FileInputStream对象
reader.close();
String classname= pro.getProperty("classname");
Class c=Class.forName(classname);
Object o=c.newInstance();
System.out.println(o);
}
}
获取Filed 属性
package com.javacode.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
Field
反射TStudent类中的Field
*/
public class ReflectTest5 {
public static void main(String[] args) throws Exception {
Class studentClass=Class.forName("com.javacode.bean.Student");
String className=studentClass.getName();
System.out.println(className);//com.javacode.bean.Student 完整类名(带包名)
String classSimpleName=studentClass.getSimpleName();
System.out.println(classSimpleName);//Student 简类名
//获取类中所有Field
Field[] fields=studentClass.getFields();
System.out.println(fields.length);//1
Field f=fields[0];
System.out.println(f.getName());//age
//注:.getFields()方法只能获取public修饰的属性
System.out.println("===================================");
Field[] fields2=studentClass.getDeclaredFields();
System.out.println(fields2.length);//4
for(Field ff:fields2){
//获取修饰符
int i=ff.getModifiers();//返回一个数字,这个数组是修饰符代号
System.out.println(i);
//将代号数字转换成字符串
String modifier=Modifier.toString(i);
System.out.println(modifier);
//获取属性类名
System.out.println(ff.getType().getName());
//获取简单名
System.out.println(ff.getType().getSimpleName());
//获取属性名
System.out.println(ff.getName());
}
//注:.getDeclaredFields()方法能获取全部属性
}
}
反射机制中的Field
获取Field
package com.javacode.reflect;
//通过反射机制反编译一个类的属性Field
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectTest6 {
public static void main(String[] args) throws Exception {
StringBuffer s=new StringBuffer();
Class studentClass=Class.forName("com.javacode.bean.Student");
s.append(Modifier.toString(studentClass.getModifiers())+"class " +studentClass.getSimpleName()+"{\n");
Field[] fields=studentClass.getDeclaredFields();
for(Field ff:fields){
s.append("\t");
//修饰符
s.append(Modifier.toString(ff.getModifiers()));
s.append(" ");
s.append(ff.getType().getSimpleName());
s.append(" ");
s.append(ff.getName()+";\n");
}
s.append("}");
System.out.println(s);
}
}
通过反射机制给属性赋值及获取属性值
package com.javacode.reflect;
import java.lang.reflect.Field;
/*
怎么通过反射机制
给属性赋值
获取属性值
*/
public class ReflectTest7 {
public static void main(String[] args) throws Exception {
//通过反射机制,访问一个对象的属性
Class studentClass=Class.forName("com.javacode.bean.Student");
//获取要操作的属性
Object o=studentClass.newInstance();//Student对象,调无参构造
//获取属性,获取属性靠属性名区分
Field noField=studentClass.getDeclaredField("no");
//给o对象的no属性赋值
noField.set(o,2222);//给o对象的no属性赋值2222
//获取o对象no的值
System.out.println(noField.get(o));
//访问私有属性
//获取要操作的属性
Field nameField=studentClass.getDeclaredField("name");
nameField.set(o,"jack");
System.out.println(nameField.get(o));//无法访问private修饰的
//非得访问就需要打破封装,这样设置完,在外部可以访问private
nameField.setAccessible(true);
nameField.set(o,"jack");
System.out.println(nameField.get(o));//无法访问private修饰的
}
}
反射机制中的Method
获取method
package com.javacode.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
反射Method
*/
public class ReflectTest8 {
public static void main(String[] args) throws Exception{
//获取类
Class userClass=Class.forName("com.javacode.service.UserService");
//获取所有Method,包括私有
Method[] methods=userClass.getDeclaredMethods();
System.out.println(methods.length);//2
for(Method m:methods){
//获取修饰符列表
System.out.println(Modifier.toString(m.getModifiers()));
//获取返回值类型
System.out.println(m.getReturnType().getSimpleName());
//获取方法名
System.out.println(m.getName());
//获取参数列表
Class[] parameterTypes=m.getParameterTypes();
for(Class p:parameterTypes){
System.out.println(p.getSimpleName());
}
}
}
}
通过反射机制调对象方法
package com.javacode.reflect;
import com.javacode.service.UserService;
import java.lang.reflect.Method;
/*
重点,通过反射机制调对象方法
*/
public class ReflectTest10 {
public static void main(String[] args) throws Exception {
//不使用反射机制调方法
UserService user=new UserService();
boolean login=user.login("admin","123");
System.out.println(login);
//使用反射机制调用对象的方法
Class userServiceClass=Class.forName("com.javacode.service.UserService");
//创建对象
Object o=userServiceClass.newInstance();
//获取Method,不仅要方法名,还需要参数列表
Method loginMethod=userServiceClass.getDeclaredMethod("login",String.class,String.class);
//调用方法,4要素:userServiceClass的对象o、方法名login、实参列表、返回值
/**最重要
* loginMethod是方法名
* o是对象
* "admin","123"是实参
* oback是返回值
*/
Object oback=loginMethod.invoke(o,"admin","123");
System.out.println(oback);
}
}
获取构造函数
不太重要
注:不含方法体
package com.javacode.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
/*
反编译一个类的Constructor方法
*/
public class ReflectTest11 {
public static void main(String[] args) throws Exception{
StringBuilder s=new StringBuilder();
Class vipClass=Class.forName("com.javacode.bean.Vip");
s.append(Modifier.toString(vipClass.getModifiers()));
s.append(" class ");
s.append(vipClass.getSimpleName());
s.append("{\n");
//拼接构造方法
Constructor[] constructors=vipClass.getDeclaredConstructors();
for(Constructor c:constructors){
s.append("\t");
s.append(Modifier.toString(c.getModifiers()));
s.append(" ");
s.append(vipClass.getSimpleName());
s.append("(");
//拼接参数
Class[] parameterTypes=c.getParameterTypes();
for(Class p:parameterTypes){
s.append(p.getSimpleName());
s.append(",");
}
//删除多余的逗号
if(s.charAt(s.length()-1)==',')s.deleteCharAt(s.length()-1);
s.append("){}");
s.append("\n");
}
s.append("}");
System.out.println(s);
}
}
通过反射机制获取父类和实现的接口
package com.javacode.reflect;
/*
重点:给定一个类,怎么获取父类,以及实现了哪些接口
*/
public class ReflecTest14 {
public static void main(String[] args) throws Exception{
//String举例
Class stringClass=Class.forName("java.lang.String");
//获取父类
Class superClass=stringClass.getSuperclass();
System.out.println(superClass.getName());
//获取String类实现的所有接口
Class[] interfaces=stringClass.getInterfaces();
for(Class i:interfaces){
System.out.println(i.getSimpleName());
}
}
}
注:
1、Class.forName(“完整类名”)方法 会使这个类的静态代码块执行。如果只是希望一个类的静态代码块执行,可以使用这个方式。
---------------------------------------------------------------------分割线----------------------------------------------------------
路径
以下写法的code移植性差
FileReader reader=new FileReader(“src\com\javacode\reflect\classname.Properties”);
可移植路径:
关于类加载器:
定义:专门负责加载类的命令/工具
ClassLoader
JDK带有三个类加载器:
父:启动类加载器:加载jre\lib\rt.jar 最核心
母:扩展类加载器:加载jre\lib\ext*.jar
应用类加载器:加载classpath中的jar包
优先级(双亲委派机制):父、母、应用类
package com.javacode.reflect;
import java.io.InputStream;
import java.util.Properties;
/*
研究路径
*/
public class AboutPath {
public static void main(String[] args) throws Exception {
//这种路径移植性差,在IDEA中默认的路径是当前project的根
//FileReader reader=new FileReader("src\\com\\javacode\\reflect\\classname.Properties");
/*通用路径(前提是:文件必须在类路径下也就是在src下)
Thread.currentThread()当前线程对象
.getContextClassLoader()线程对象的方法,获取当前线程类加载器对象
.getResource("") [获取资源] 类加载器对象方法,当前线程的类加载器默认从类的根路径下加载资源
*/
String path =Thread.currentThread().getContextClassLoader()
.getResource("classname2.Properties").getPath();
System.out.println(path);
//以上代码可以拿到文件的绝对路径
//获取db.Properties绝对路径。从类的根路径下开始
String path2=Thread.currentThread().getContextClassLoader()
.getResource("com/javacode/reflect/db.PRoperties").getPath();
System.out.println(path2);
//也可以直接以流的形式返回
InputStream reader=Thread.currentThread().getContextClassLoader()
.getResourceAsStream("classname2.Properties");
Properties pro=new Properties();
pro.load(reader);
String classname=pro.getProperty("classname");
System.out.println(classname);
}
}
更先进的路径获取:
(资源属性文件)
package com.javacode.reflect;
import java.util.ResourceBundle;
/*
java.util包下提供了资源绑定器,便于获取属性配置文件的内容
使用以下方式的时候,属性配置文件xxx.properties必须放到类路径下
*/
public class ResourceBundleTest {
public static void main(String[] args) {
//资源绑定器只能绑定xxx.properties文件。并且这个文件只能在src路径下。文件扩展名也必须是properties
//在写路径时,扩展名不写
ResourceBundle bundle=ResourceBundle.getBundle("classname2");
String classname=bundle.getString("classname");
System.out.println(classname);
}
}