1 IO流
1.1 各种流
- 抽象基类:InputStream / OutputStream / Reader / Writer
- 流数据有序;写入 / 读取后自动后移;各种流的底层都是基于字节流的操作,自动寻找对应码表
- 按数据流向分:
- 输入流:数据从硬盘(读)到JVM内存 / 程序,实现Closeable
- 输出流:实现Closeable, Flushable强制刷出
- 按处理的数据单位分:
- 字节流:8位;Stream结尾的流
- 字符流:16位;方便文字的解析,字节流和编码表封装成字符流;Reader/Writer结尾的流;特有方法append(string)
- 按角色功能划分:
- 节点 / 文件流:程序用于直接操作目标设备所对应的类;底层物理存储节点直接关联底层设备,如构造器参数直接是文件/路径名
- FileInputStream / FileOutputStream / FileReader / FileWriter:访问文件;参数可接收字符串,而其他类参数需要File实例
- ByteArrayInputSteam / ByteArrayOutputSteam / CharArrayReader / CharArrayWriter:访问字节字符数组;数据传输快,底层常用
- PipedInputStream / PipedOutputStream / PipedReader / PipedWriter:管道流;进程间的通信
- StringReader / StringWriter:当参数为StringBuffer时可有写入字符串操作
- 处理流:装饰器设计模式;因为不同物理存储节点获取字节流的方式不一样,所以包装了节点流,消除不同节点流的不同实现,统一输入输出功能等处理,即程序通过间接类去调用节点流类(类的构造器参数是节点流),更加方便和灵活的处理数据
- FilterInputStream / FilterOutputStream / FilterReader / FilterWriter / BufferedInputStream / BufferedOutputStream / BufferedReader / BufferedWriter;缓冲(高效读写)流;默认缓存8KB,数组存满时会将数据写入文件并将缓存下标归零;依赖文件流即File file = new File(""); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
- ObjectInputStream / ObjectOutputStream:对象流;对象序列化
- DataInputStream / DataOutputStream:数据流
- PrintStream / PrintWriter:打印(输出)流
- InputStreamReader / OutputStreamWriter:字节流转为字符流
- ZipInputStreanm / ZipOutputStream:文件压缩/解压
- 节点 / 文件流:程序用于直接操作目标设备所对应的类;底层物理存储节点直接关联底层设备,如构造器参数直接是文件/路径名
1.2 流操作
- int read([bytes, [offset, maxLength]):无参则从输入流中读取一个数据字节;有参则将最多bytes.length/maxLength个字节数据一次性读取;字符流则使用char[];返回-1即读到文件末尾,read()/write()底层是native方法,即java不知道其具体实现
- close() / flush():通知系统关闭连接和释放资源;强制刷新输出流
- void write(int / bytes / chars / string, [offset, length]):
// 1、创建源;2、选择流;3、操作数据;4、关闭 // 统一抛出IOException;输入输出配合实现文件拷贝,配合递归拷贝文件夹 // 可能 FileNotFoundException FileInputStream / FileReader fileIn = new FileInputStream / FileReader("in.txt"); // 读取键盘录入(InputStream字节流的实例,为了方便将其转为字符流,后来用Scanner) // BufferedReader bufread = new BufferedReader(new InputStreamReader(System.in)); // 构造器参数2默认为false即下次写入的内容会覆盖原内容,true则表示写入的内容追加 FileOutputStream / FileWriter fileOut = new FileOutputStream / FileWriter("out.txt"); // 输出到控制台 // BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out)); // 长度太小或奇数个字节,某一次读取可能读到半个,导致乱码 byte[] bytes = new bytes[1024]; int hasRead = 0; while ((hasRead = fileIn.read(bytes)) > 0) { // 建议使用,此规定了每次写入长度的重载函数;如读取一个101字节的文件后写入另一文件,每次读取length = 10字节即hasRead = fileIn.read(bytes) = 10,第十一次读取时hasRead = 1,如果没有参数3规定长度变量,则还是写入10字节,后面9字节是垃圾内容 fileOut.write(bytes, 0, hasRead); // new String(bytes, 0, hasRead); } // String line = null; // while ((line = bufread.readLine()) != null) // if (line.equals(“q”)) System.exit(1); // 直接写入字符串(如果是字节流则先将字符串转为字节数组string.getBytes(); fileOut.write("abcde"); // 针对字符操作流:刷新缓冲区,write()将数据写入到流中即缓存,刷新或关闭流以后才将缓冲区中的数据刷到物理节点/文件中;属性缓存大小默认1024KB;字节操作流则直接读取和写入 fileOut.flush(); fileOut / fileIn.close(); // 关闭流(系统底层资源)
代码:
import java.io.*; import java.nio.charset.Charset; import java.util.Properties; public class TestIOStream { private static void out() { File file = new File("c:\\"); try { OutputStream out = new FileOutputStream(file); String content = "输出的内容"; out.write(content.getBytes()); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static void in() { File file = new File("c:\\"); try { InputStream in = new FileInputStream(file); byte[] bytes = new byte[1024*10]; int length = -1; StringBuilder stringBuilder = new StringBuilder(); while ((length = in.read(bytes)) != -1){ stringBuilder.append(new String(bytes)); } in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static void charRead(InputStream inputStream){ Reader reader = new InputStreamReader(inputStream, Charset.forName("UTF-8")); } // Properties类:配置文件读取类 private static void readProperties() { Properties properties = new Properties(); try { InputStream inputStream = new FileInputStream("cogfig.properties"); properties.load(inputStream); // 加载配置文件 // 读取配置文件中的信息 String name = properties.getProperty("name"); // 。。。 inputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
2 File
- 与平台无关的文件和文件夹(目录)处理,即增,删,重命名文件和目录;区别用流操作其中的数据
- 增:
- File file = new File(filePath); // 如“F:/或\”(系统分隔符默认\,java需转义);或者 "F:" + File.separator + "test.txt";默认相对路径;重载方法参数1为父路径;注意这是将文件或路径实例化为一个File对象,而不是创建文件或路径的语句
- boolean createNewFile() throw IOException:不存在时,创建该文件
- static File createTempFile(prefix, suffix [,directory]):以给定前缀和后缀生成文件名
- booleanmkdir() / mkdirs():创建目录;前者若某层目录不存在则最终创建失败,后者则会创建整个目录
- 删:
- boolean delete():删除文件或目录
- void deleteOnExit():在虚拟机终止时,删除文件或目录
- 查:
- long length():文件大小,字节数;路径或不存在的文件返回0
- String getName():目录或文件名
- String getParant():父目录或文件名,无则为null
- StringgetPath() / getAbsolutePath():绝对路径名字符串
- long lastModified():最后一次修改时间的毫秒数
- File.pathSeparator:系统路径分隔符;File.separator / File.separatorChar
- File getAbsoulteFile()
- File[] listFiles():文件或目录名数组;当前目录下文件以file对象返回,后可操作file对象;名字需满足特定过滤器
- String[] list():当前目录下文件或目录名做字符串数组
- static File[] listRoots()
- 改:
- boolean renameTo(newName):重命名
- boolean exists():是否存在
- boolean canWrite() / canRead() / canExcute():是否可写 、可读、可执行
- boolean isDirectory():是否目录
- boolean isFile():是否文件
- boolean isHidden():是否隐藏
- boolean isAbsolute():是否绝对路径
import java.io.File; import java.io.IOException; public class TestFile { public static void main(String[] args) { searchFile(new File("C:\\Users\\Administrator\\Desktop\\File"), ".txt"); } // 创建文件 private static void creatNewFile() { // File file = new File("C:\\Users\\Administrator\\Desktop\\File"); File file = new File("C:" + File.separator + "File" + File.separator + "test.txt"); if (!file.exists()) { try { file.createNewFile(); // 创建文件 } catch (IOException e) { e.printStackTrace(); } } } // 查找文件 private static void searchFile(File targetFile, String endWithName) { if (null == targetFile) return; // 如果是目录,遍历所有文件 if (targetFile.isDirectory()) { File[] files = targetFile.listFiles(); // 如果文件中还有文件,递归遍历;慎用 if (null != files) { for (File file : files) { searchFile(file, endWithName); } } } else { String fileName = targetFile.getName().toLowerCase(); System.out.println(fileName); if (fileName.endsWith(endWithName)) { System.out.println(targetFile.getAbsolutePath()); } } } }
- 导出CSV文件:https://www.cnblogs.com/hanfengyeqiao/p/9471694.html
- 代码
import java.io.File; import java.io.IOException; public class TestFile { public static void main(String[] args) { searchFile(new File("C:\\Users\\Administrator\\Desktop\\File"), ".txt"); } // 创建文件 private static void creatNewFile() { // File file=new File("C:\\Users\\Administrator\\Desktop\\File"); File file = new File("C:" + File.separator + "File" + File.separator + "test.txt"); if (!file.exists()) { try { file.createNewFile(); // 创建文件 } catch (IOException e) { e.printStackTrace(); } } } // 查找文件 private static void searchFile(File targetFile, String endWithName) { if (null == targetFile) return; // 如果是目录,遍历所有文件 if (targetFile.isDirectory()) { File[] files = targetFile.listFiles(); // 如果文件中还有文件,递归遍历;慎用 if (null != files) { for (File file : files) { searchFile(file, endWithName); } } } else { String fileName = targetFile.getName().toLowerCase(); System.out.println(fileName); if (fileName.endsWith(endWithName)) { System.out.println(targetFile.getAbsolutePath()); } } } }
3 FileUtils
- org.apache.commons.io.
- 工具类,提供大量便捷操作,包括读写文件/夹,复制,移动,上传,下载
4 序列化与反序列化
- 在持久化存储,或网络传输数据时,需要将对象序列化
- 序列化:将对象的状态信息转为平台无关二进制(即字节数组)流,可以持久化保存(因为JVM停止运行时对象状态随之丢失),或允许网络中直接传输对象;序列化保存的是实例信息 ,静态数据不能被序列化,因为它存储在静态方法区而不是堆
- 反序列化:将字节序列或xml编码格式解析成对象,区别于新建对象
- 实现方式:对象开启序列化支持,即java.io.Serializable接口
- Serializable:没有字段和方法,仅用于标识可序列化的语义;不支持此接口的类,序列化时异常NotSerializableException
- 子接口Externalizable,定义的抽象方法writeExternal()和readExternal()必须实现才能序列化成功,且提供无参构造器(读取对象时构造对象)
- transient:修饰属性可阻止敏感变量如密码等被序列化到文件,序列化时该变量以默认值初始化;如输出到本地文件后,该值为null
- ObjectInput / ObjectOutput:接口扩展DataInput / DataOutput,用于从二进制流中读取字节,并重构为基本数据类型 / 将基本数据类型转为字节写入流;ObjectInputStream的readObject()读取对象和ObjectOutputStream的writeObject()写入对象并持久化;如配合FileOutputStream将对象序列化输出到本地文件中
- 传统:输入输出流通过字节移动来处理数据;面向流;低效;线程可能阻塞如read()时没有数据
- new IO:采用内存映射文件的方式处理IO,面向块;文件或其部分映射到内存;java.nio;缓冲区实质为一个数组,对数据结构化访问,类型为包装类型+Buffer,常用ByteBuffer,它提供字节的get/set及其他操作;缓冲区三个状态变量:position未存储内容起始号(空内容起始下标),limit限制及空白区大小,capacity容量;缓冲区反转方法flip()
- 核心对象:
- Channel:通道,所有数据以此传输
- map():映射数据到内存
- Buffer:缓冲
- Properties类:配置文件读取类:
Properties properties = new Properties(); InputStream inputStream = new FileInputStream("cogfig.properties"); properties.load(inputStream); // 加载配置文件 properties.put(key,value); properties.store(); // 写入配置文件 // 读取配置文件中的信息 String name = properties.getProperty("name"); //。。。
5 反射
- 反射机制Reflection:在运行状态中,对于任意对象,都能调用它的任意属性和方法。运行时动态获取信息和调用对象的方法的功能,即为Java反射机制;万物皆对象,类也是对象
- 每个类对应唯一一个反射类对象;基本数据类型也有反射实例,如Class intClass = int.class;
- 获取反射类对象:
- 使用Object类中的方法:对象.getClass(),需要先创建该类对象
- 使用Object的静态属性class:类.class;需要先明确该类
- 使用Class类的静态方法:Class.forName(“类名字符串”);推荐
- 调用无参构造器实例化:clazz.newInsrance();返回Object;但推荐调用有参构造器,则先需要获得构造器对象clazz.getConstructor(...),参数为类型如(String.class,int.class);然后可通过构造器实例化对象constructor.newInstance(实参列表)
- 实例化对象后,作为参数传入set()反射操作实例的值,如设置属性或调用方法;涉及异常IllegalAccessException安全检查,即访问了私有方法或属性;setAccessible(true)取消安全检查,注意并不是设置能否访问;Accessible属性继承自AccesibleObject类,用于提升调用的性能
// 类中包含信息:constructors,fields,methods // 注意javaPath中不是系统分隔符,而是.,如com.zgh.User,没有.java后缀 Class clazz = Class.forName(javaPath); // 只包含公共的构造器;参数不传或传递null则调用无参构造器,传递指定参数列表,则获取对应参数的构造器 Constructor[] constructors = clazz.getConstructors(); // 包含私有的 constructors = clazz.getDeclaredConstructors(); for(Constructor con : constructors) { System.out.println(con); } // 所有公有属性,包含私有的则getDeclaredFields() Field[] fields=clazz.getFields(); // 获取的是该类中的公有方法和父类中的公有方法 Method[] methods = clazz.getMethods(); // 获取本类中的方法,包含私有方法 methods = clazz.getDeclaredMethods(); for(Method method : methods) { System.out.println(method); } // 获取指定名称的方法 Method method = clazz.getMethod("show", int.class,String.class); // 使用方法对象执行obj对象中的方法 method.invoke(obj, 39,"hehehe"); // 获取类所在的包,getName() Package getPackage();
反射操作泛型、注解: