IO总结:
1、File类,此类可以获取计算机上的目录或文件的信息参数信息(名称、大小、路径)
2、IO流
字节流:可以传输任意文件
字符流:中文传输
以下IO流都需要使用字节流参数 FileOutputStream
properties:store()、load()
缓冲流:提升效率 readLine()返回值是字符串 判断应是否为null
转换流:编码 读取文件的时候,设置的编码参数一定要与文件的编码一致,否则乱码
序列化:对java对象的操作 序列化版本ID保持一致,将ID设置静态
打印流:只输出信息
IO流:
数据传输的管道,流可以理解为管道的意思
File类
概述
分隔符
String separator = File.separator; //路径分隔符 windows:分号 linux:冒号
String pathSeparator = File.pathSeparator;//文件名称分隔符 windows 反斜杠 \ ; linux 斜杠 /
System.out.println(separator);
System.out.println(pathSeparator);
路径
构造方法
File(String pathname)
File(String parent,String child)
File(File parent , String child)
常用方法
功能方法
/*功能方法*/
file.getAbsolutePath();//绝对路径
file.getPath();//路径
file.getName();//最后结尾部分 文件名/文件夹名
file.length();//文件大小
判断方法
/*判断方法*/
file.exists();//是否存在
//使用前提是判断这个file路径是否存在 file.exists();为true
file.isDirectory();//是否是文件夹
file.isFile();//是否是文件
删除方法
/*创建删除方法*/
//1、创建文件,不能创建文件夹;2、路径必须存在,否则报错 3、文件存在则不创建,返回false
file.createNewFile();
file.mkdir();//创建单级空文件夹 历经不存在不会创建,没有返回值
file.mkdirs();//创建多级空文件夹
//1、删除文件或文件夹 2、删除文件夹的适合如果有文件则不会删除 3、删除不会走回收站,谨慎删除
file.delete();
遍历路径下的目录和文件
/*遍历路径下的目录和文件*/
//目录不存在,或者路径不是一个目录,报空指针异常
file.list(); //返回String String[]
file.listFiles();//返回信息封装到 File 中 File []
递归
递归 :
直接递归:自己调自己
间接递归:A调B、B调C
注意事项:
递归一定要有限定条件,否则栈溢出
递归次数不能太多,否则栈溢出
构造方法,禁止递归
递归效率低下,对内存占用较高,建议使用for循环
递归打印多级目录(重点)
/*递归打印多级目录*/
private void getAllFile(File dir) {
System.out.println(dir);
File[] files = dir.listFiles();
for (File file : files) {
if(file.isDirectory()){
//递归调用自身,打印下一级目录
getAllFile(file);
}else {
System.out.println(file);
}
}
}
递归查询文件类型(重点)
private void getAllFile(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
if(file.isDirectory()){
//递归调用自身,往下继续查找
getAllFile(file);
}else {
//满足条件打印
if(file.getPath().toLowerCase().endsWith(".java")){
System.out.println(file);
}
}
}
}
过滤器查询文件类型
FileFilter()
/*重写过滤规则*/
public class FileFilterImpl implements FileFilter {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
//不过滤目录,放过去,继续查询
return true;
}
return pathname.getPath().toLowerCase().endsWith(".java");
}
}
private void getAllFile(File dir) {
File[] files = dir.listFiles(new FileFilterImpl());
for (File file : files) {
if(file.isDirectory()){
//递归调用自身,往下继续查找
getAllFile(file);
}else {
System.out.println(file);
}
}
}
匿名内部类实现
private void getAllFile(File dir) {
File[] files = dir.listFiles(new FileFilter(){
//匿名内部类
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory()){
return true;
}
return pathname.getPath().toLowerCase().endsWith(".java");
}
});
for (File file : files) {
if(file.isDirectory()){
//递归调用自身,往下继续查找
getAllFile(file);
}else {
System.out.println(file);
}
}
}
Lambda表达式实现
private void getAllFile(File dir) {
File[] files = dir.listFiles((File pathname)->{
return pathname.isDirectory() || pathname.getPath().toLowerCase().endsWith(".java");
});
for (File file : files) {
if(file.isDirectory()){
//递归调用自身,往下继续查找
getAllFile(file);
}else {
System.out.println(file);
}
}
}
FilenameFilter()
private void getAllFile(File dir) {
File[] files = dir.listFiles((new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory() || name.toLowerCase().endsWith(".java");
}
}
));
for (File file : files) {
if (file.isDirectory()) {
//递归调用自身,往下继续查找
getAllFile(file);
} else {
System.out.println(file);
}
}
}
IO流
概念
字节流
一切文件皆为字节,字节流可以读取任意的文件
InputStream
OutputStream
是一切字节流的顶层父类,抽象类
FileOutputStream
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write(97);
fos.close();
写多个字节
FileOutputStream fos = new FileOutputStream("a.txt");
//byte[] bytes = new byte[]{65,66,67,68,69}; //ABCDE
byte[] bytes = new byte[]{-65,-66,-67,68,69}; //烤紻E
fos.write(bytes);
fos.close();
FileOutputStream fos = new FileOutputStream("a.txt");
byte[] bytes = new byte[]{-65,-66,-67,68,69};
fos.write(bytes,2,2);
fos.close();
追加写/换行
FileOutputStream fos = new FileOutputStream("a.txt");
byte[] bytes = new byte[]{-65,-66,-67,68,69};
for (int i = 0; i < 10; i++) {
fos.write("你好".getBytes());
fos.write("\r\n".getBytes());
}
FileInputStream
FileInputStream fis = new FileInputStream("a.txt");
int len= 0;
//不能写成 while (fis.read()!=-1) 是因为fis.read()本身就是读取一个字节,会造成读取的字节没有打印
while ((len = fis.read())!=-1){
System.out.println((char)len);
}
fis.close();
读取多个字节
FileInputStream fis = new FileInputStream("a.txt");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
System.out.println(new String(bytes,0,len));
}
实现复制
public static void main(String[] args) throws IOException {
FileInputStream fis =new FileInputStream("C:\\Users\\Administrator\\Desktop\\摄影原理.png");
FileOutputStream fos =new FileOutputStream("C:\\Users\\Administrator\\Desktop\\摄影原理-1.png");
byte[] bytes =new byte[1024];
int len = 0;
while((len = fis.read(bytes))!= -1){
fos.write(bytes,0,len);
}
fis.close();
fos.close();
}
字符流
字节流读取中文文件:
GBK:1个中文占2个字节
UTF-8:1个中文占3-4个字节
字节流是一个字节一个字节读取的,读到中文的话,每次只能读取中文的1/3字节,因此会产生乱码
FileReader
FileReader fr =new FileReader("C:\\Users\\Administrator\\Desktop\\a.txt");
char[] chars =new char[1024];
int len = 0;
while ((len =fr.read(chars))!= -1){
System.out.println(new String(chars));
}
fr.close();
FileWriter
FileWriter fw =new FileWriter("C:\\Users\\Administrator\\Desktop\\a.txt",true);
for (int i = 0; i < 10; i++) {
fw.write("我是大傻逼啊啊\r\n");
fw.flush();
}
fw.close();
Try{}catch(){}final{}处理异常
public static void main(String[] args) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\摄影原理.png");
fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\摄影原理-1.png");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
fis.close();
}
if(fos!=null){
fos.close();
}
}
}
1.7之后的try/catch新特性
直接在括号中定义对象
//流对象使用完毕之后自动关闭流对象,省掉了finally模块
try (定义流对象) {
} catch (Exception e) {
}
1.9之后的新特性
对象定义在外面,引入对象
A a = new A();
B b = new B();
try (a,b) {
} catch (IOException e) {
}
Properties类
Properties 流
store方法
Properties properties =new Properties();
properties.setProperty("a","1");
properties.setProperty("b","2");
properties.setProperty("c","3");
properties.setProperty("d","4");
FileOutputStream fos =new FileOutputStream("d");
properties.store(fos," ");
load方法
Properties properties =new Properties();
FileInputStream fis = new FileInputStream("d");
properties.load(fis);
Set<String> names = properties.stringPropertyNames();
for (String name : names) {
String property = properties.getProperty(name);
System.out.println(name+"="+property);
}
缓冲流
字节缓冲流
使用 byte[] bytes =new byte[1024];
接收字节也属于一种缓冲,数组缓冲
BufferedOutputStream
FileOutputStream fos = new FileOutputStream("c.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos,1024);
bos.write("abcde".getBytes());
bos.flush();
bos.close();
fos.close();
BufferedInputStream
FileInputStream fis = new FileInputStream("c.txt");
BufferedInputStream bos = new BufferedInputStream(fis,1024);
int len = 0 ;
//数组缓冲
byte[] bytes =new byte[1024];
while ((len = bos.read(bytes))!=-1){
System.out.println(new String(bytes));
}
字符缓冲流
BufferedWriter
BufferedWriter bw =new BufferedWriter(new FileWriter("f.txt"),10);
for (int i = 0; i < 10; i++) {
bw.write("abc");
bw.newLine();
}
bw.flush();
bw.close();
BufferedReader(特殊)
读取返回值不再是-1,而是null
BufferedReader br =new BufferedReader(new FileReader("f.txt"));
String line= null;
while ((line= br.readLine())!=null){
System.out.println(line);
}
br.close();
转换流
字符编码 字符集
编码:字符转换成字节
解码:字节转换成字符
·如果使用 A 规则编码 存储到计算机,但是使用 B 规则解码,就会出现乱码
字符集:支持所有字符的集合
ASCII编码:计算机最初的编码 美国标准
ISO-8859-1:兼容ASCII编码
GBK:国标 中文编码表
Unicode:万国码 utf-8 utf-16 utf-32
解决乱码问题
使用转换流转换编码格式
OutputStreamWriter
给文件指定格式
这样无论是操作系统,还是IDE,在打开这个文件的时候,不会使用默认的编码格式打开,而是会根据这个文件的编码格式,去打开
OutputStreamWriter osw =new OutputStreamWriter(new FileOutputStream("f.txt"),"GBK");
osw.write("你好");
osw.flush();
osw.close();
InputStreamReader
InputStreamReader isr = new InputStreamReader(new FileInputStream("f.txt"), "GBK");
int len = 0;
char[] chars = new char[1024];
while ((len = isr.read(chars)) != -1) {
System.out.println(new String(chars));
}
转换文件编码DEMO
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("f.txt"), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("h.txt"), "utf-8");
int len = 0;
char[] chars = new char[1024];
while ((len = isr.read(chars)) != -1) {
osw.write(chars,0,len);
osw.flush();
}
osw.close();
}
序列化(流)
java.io.InvalidClassException异常
通俗理解就是serialVersionUID是适用于Java的序列化机制,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是java.io.InvalidClassException。
理解:
继承序列化接口的类,在编译时,会对应生成一个版本号,序列化之后,会将版本号存到序列化信息中,反序列化的时候,从序列化信息中的版本号与class对象的版本号比对,如果一致,则反序列化成功,如果不一致则报异常;
修改类会导致版本号的变化
idea安装GenerateSerialVersionUID插件
使用快捷键Alt+Insert在实体类自动生成serialVersionUID
ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("w.txt"));
Person person = new Person();
person.setName("王罕");
person.setSex("男");
oos.writeObject(person);
oos.close();
ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("w.txt"));
Object object = ois.readObject();
System.out.println(object);
ois.close();
transient关键字
被static和transient关键字修饰的成员变量,不能被序列化;但对象本身依然可以序列化,只是会缺少静态/瞬态变量的信息
打印流
PrintStream ps = new PrintStream("hh.txt");
ps.write(97);
ps.write("\r\n".getBytes());
ps.println(98);
ps.println("aaa");
System.out.println("我在打印台输出");
PrintStream ps = new PrintStream("hh.txt");
System.setOut(ps);
System.out.println("我输出到打印流指定位置");