1.File
- File类代表文件或者文件的类
- 创建文件类的对象,在创建对象的过程中没有检测路径的信息是否存在,会把路径信息放在对象的身上。即若路径信息不存在,创建对象的语句编译和运行都不会报错。
File file=new File(路径);
- 新建文件,新建文件为空文件,若路径信息的指定文件已经存在的话,返回值将会为false
boolean b=file.createNewFile();
- 创建文件夹(多级)
File f1=new File("E:\\IDEA\\workspace\\JAVASE2007\\Day18\\src\\cn\\tedu\\file\\a\\b\\c");
//创建文件夹(多级)
boolean b1=f1.mkdirs();
System.out.println(b1);
- 删除文件,无论文件是否有内容均可以删除,但是只能删除空文件夹,该方法操作需要慎重,删除文件无法还原。
boolean b2=file.delete();
- 获取文件或是文件夹的名称,若为文件时,将会返回文件名+后缀名字/文件夹名字
File file=new File(路径信息);
//文件名+后缀名/文件夹名字
System.out.println(file.getName());
- 返回当前所在文件夹
System.out.file(file.getParent());
- 返回对象所在的路径信息
System.out/println(file.getPath());
- 返回文件上次修时间----即从1970年1月1日0时0分0秒到现在的毫秒值
System.out.println(file.lastModified());
- 设置文件上一次修改时间
file.setLastModified(233333333L);
- 返回文件抽象路径表示的长度,如果file表示的是一个具体的文件,则返回的文件的字节大小,如果File表示一个目录,则返回值不能确定,如果目录或是文件不存在,则返回为0L.
System.out.println(file.length());
- 返回文件夹下的所有文件,把当前文件夹下的所有信息当作File对象放入到数组中
File[] fs=file.listFiles();
- 过滤文件,根据一定的过滤规则筛选出符合条件的文件,下面为不同的两种方法
File f=new File("E://");
//把E盘下含有数字的文件或者文件夹进行输出
//把过滤之后的File类对象返回到数组中
File[] fs=f.listFiles(new FileFilter() {
//重写方法--过滤规则
@Override
public boolean accept(File pathname) {
//正则语法----匹配字符串中含有数字
return pathname.getName().matches(".*\\d.*");
}
});
//遍历数组
for(File f1:fs)
System.out.println(f1);
//
File[] fss=file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.matches(".*\\d.*");
}
});
- 重命名文件的抽象路径名
//创建代表文件类的对象
File file=new File("E:\\IDEA\\workspace\\JAVASE2007\\Day18\\src\\cn\\tedu\\file\\123.txt");
//重命名
//底层是由剪切来实现的
boolean b=file.renameTo(new File("E:\\IDEA\\workspace\\JAVASE2007\\Day18\\src\\cn\\tedu\\file\\a\\七夕.txt"));
System.out.println(b);
- 判断是否是文件夹
System.out.println(file.isDirectory());
- 判断是否是文件
System.out.println(file.isFile());
- 练习:删除文件夹下的所有文件内容(包括文件以及文件夹)
package cn.tedu.test;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
File file=new File("E:\\IDEA\\workspace\\JAVASE2007\\Day18\\src\\cn\\tedu\\file\\a");
//调用方法删除文件
deleteFiles(file);
}
//定义删除文件方法
public static void deleteFiles(File file){
//判断是否是文件夹
if(file.isDirectory()){
//说明是文件夹,需要展开当前文件夹所有信息
//获取当前文件夹所有信息
//放入到数组中
File [] fs=file.listFiles();
//遍历当前数组
for(File f:fs){
//递归调用
deleteFiles(f);
}
}
//删除文件以及空文件夹
file.delete();
}
}
- 统计工程里.java文件的个数以及.class文件个数
package cn.tedu.test;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
public class TestDemo1 {
//表示java文件的个数
private static int countJava=0;
//表示class文件的个数
private static int countClass=0;
public static void main(String[] args) throws IOException {
File file = new File("E:\\IDEA\\workspace\\JAVASE2007");
//统计方法统计文件数
countFiles(file);
//输出java文件的个数
System.out.println("java文件个数:"+countJava);
System.out.println("class文件个数:"+countClass);
}
//定义方法来统计文件数
public static void countFiles(File file){
//判断文件是否是文件夹
if(file.isDirectory()){
//说明是文件夹
//获取文件夹里的信息
File [] fs=file.listFiles();
//遍历数组
for(File f:fs){
countFiles(f);
}
}
//统计java文件个数
if(file.getName().endsWith(".java")){
countJava++;
}
//统计class文件的个数
if(file.getName().endsWith(".class")){
countClass++;
}
}
}
2.IO流
1)概念:本质上是一套数据传输的机制
2)图例:若将A文件写入到B文件中将会涉及到数据传输机制,即涉及到IO流。
3)三要素:将内存看作是参照物
- 根据传输的方向
输入流:往内存来传输数据
输出流:从内存往外传输数据 - 根据传输的方式
字符流:传输字符形式的数据
字节流:传输字节形式的数据 - 根据数据存放/获取的位置
硬盘、内存、网络、外设设备
4)四大基本流(下面的四个类均为抽象类)
- 字符输入流:Reader
- 字符输出流:Writer
- 字节输入流:InputStream
- 字节输出流:OutputStream
5)硬盘
- 字符流
A、给硬盘上.txt文件写入数据-----文件字符输出流--FileWriter
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建文件字符输出流对象
//创建对象的过程中会检测路径信息是否存在
//若存在会创建新的空文件进行覆盖
//当未指定append的值时,append的值将会默认为false
//当append为true时,不会会覆盖文件的原有内容,若为false,将会覆盖原有内容
FileWriter fw=new FileWriter("Test\\src\\file\\a.txt",true);
//写入数据
//写入int数据
fw.write(1);
//写入char数组数据
char c[]={'a','b','c'};
fw.write(c,1,2);
//写入String数据
fw.write("你好");
}
}
但是,当我们这样的写程序的时候会发现,文件中并未存在我们写入的内容,原因是什么呢?接下来,我们看一下FileWriter的大致写入过程。
由上图可知,我们上述程序未写入的原因就是缓冲区并未存放满,那么缓冲区的容量大概是多少?又如何将未存放满的数据存放到文件中。
由资料查找可知,缓冲区的容量为8kb,而当我们需要将数据从缓冲区中拿取出来时可以采用flush()函数来冲刷缓冲区。完整程序代码如下:
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建文件字符输出流对象
//创建对象的过程中会检测路径信息是否存在
//若存在会创建新的空文件进行覆盖
//当未指定append的值时,append的值将会默认为false
//当append为true时,不会会覆盖文件的原有内容,若为false,将会覆盖原有内容
FileWriter fw=new FileWriter("Test\\src\\file\\a.txt",true);
//写入数据
//写入int数据
fw.write(1);
//写入char数组数据
char c[]={'a','b','c'};
fw.write(c,1,2);
//写入String数据
fw.write("你好");
//底层为了提高和保证数据传输效率,会提供缓冲区来传输数据并且要求缓冲区
//存满了才会进行数据传输。若此时数据没有充满缓冲区且并未冲刷缓冲区
//数据将会滞留在缓冲区并且丢失
//冲刷缓冲区
fw.flush();
//关流
//含有自动冲刷的过程
fw.close();
//将流对象置为null,等待系统进行回收
fw=null;
}
}
B、从硬盘上的.txt文件读取数据-----文件输入流---FileReader
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建文件输入流对象
FileReader fr=new FileReader("Test\\src\\file\\a.txt");
//返回单个字符的编码值
/*System.out.println(fr.read());
System.out.println(fr.read());
//当读取完毕之后将会返回-1
System.out.println(fr.read());*/
//采用循环来实现上述过程
int i=-1;
while((i=fr.read())!=-1){
System.out.println(i);
}
//关流
fr.close();
}
}
在上述过程中,我们采用了read()方法读取单个字符的编码值,但是很明显单个字符进行读取的时候数据传输效率并不是很高,但是在底层我们也没有像字符输出流一样拥有缓冲区,那么我们该怎样提高数据传输效率?答案就是自建缓冲区,代码实例如下:
public static void main(String[] args) throws IOException {
//创建文件输入流对象
FileReader fr=new FileReader("Test\\src\\file\\a.txt");
//自建缓冲区
//创建新数组,存放我们要读取的数据就
char cs[]=new char[5];
//把读取到的数据存放到数组中
while(fr.read(cs)!=-1){
System.out.println(cs);
}
//关流
fr.close();
}
接下来我们查看一下文档内容是否和输出内容一致。
很明显,结果不相同,那么原因又是什么呢?我们来看一下该段程序的大致执行过程。
由图可知,我们想要解决这个问题,必须对输出的数据进行截取,只能截取文件内容输出完毕,即文件内容输出完毕,数据同样也输出相同长度。代码见如下:
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建文件输入流对象
FileReader fr=new FileReader("Test\\src\\file\\a.txt");
//自建缓冲区
//创建新数组,存放我们要读取的数据就
char cs[]=new char[5];
int len=-1;
//把读取到的数据存放到数组中
//方法返回值就是读取字符的个数,返回-1读取完毕
while((len=fr.read(cs))!=-1){
//输出数组内容
System.out.println(new String(cs,0,len));
}
//关流
fr.close();
}
}
- 字节流(常见)
A、给硬盘上.txt文件写入数据(txt文件较为特殊,可以把字节转字符,也可以把字符转为字节)---文件字节输出流----FileOutputStream
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建文件字节输出流对象
//底层不存在缓冲区
FileOutputStream fos=new FileOutputStream("Test\\src\\file\\a.txt");
//写出数据
fos.write("你好".getBytes());
//关流
fos.close();
}
}
B、从硬盘上.txt文件读取数据----文件字节输入流--FileInputStream
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建文件字节输入流对象
FileInputStream fis=new FileInputStream("Test\\src\\file\\a.txt");
//返回一个字节对应的编码值
/*文件存放内容为:你好
编码方式为utf-8
故对应字节为6个,所以应该读取六次读取完毕
*/
/*System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
//读取完毕返回-1
System.out.println(fis.read());*/
//采用自建缓冲区的方式来读取数据
byte [] bs=new byte[15];
int len=-1;
//返回的是读取到的字节数,遇到-1读取完毕
while((len=fis.read(bs))!=-1){
//输出可能出现?的原因是:相应的字节数可能无法组成一个汉字
System.out.println(new String(bs,0,len));
}
//关流
fis.close();
}
}
6)IO流中异常捕获
我们都知道处理异常的方式有两种,一是抛出,而是捕获,那IO中的异常又是如何捕获的?
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args){
//由于在创建IO流对象时可能会抛出异常,所以IO流对象对象的初始化过程需要放在
//try块里,但是不论流对象是否真正的初始化成功,我们都需要把流对象
//置为null以及关流,故该对象需要再finally中使用,所以我们将IO流对象
//的创建过程分为初始化和声明两个过程。
//1.声明流对象,并且赋值为null
FileWriter fw=null;
try{
//流对象进行初始化
fw=new FileWriter("Test\\src\\file\\a.txt");
//写入数据
fw.write("你好");
//虽然我们关流时会进行自动冲刷缓冲区,但是同样的关流也同样有可能会发生异常
//所以我们需要添加手动冲刷的过程,两者一起发生错误的几率还是很小的
//4.手动冲刷
fw.flush();
}catch (IOException e){
}finally {
//2.判断流对象是否成功初始化
if(fw!=null)
//成功初始化
//关流
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
//3.无论关流成功与否都要把流对象置为null
fw=null;
}
}
}
}
7)缓冲流(给IO流提供缓冲区)
在之前,当我们一次性传输多个数据时,我们会采用自建缓冲区的方式,但是选取一个合适的缓冲区长度将会是一个问题,这时Java提供给我们一个缓冲流,用来给IO流提供缓冲区。
- BufferedReader---给字符输入流提供缓冲区
readLine()读取一行数据
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建缓冲流对象
//BufferedReader和FileReader都是Reader的子类---同类
//br对象具有FileReader的所有功能,但是还在此基础上增加了别的功能
//所以,若将FileReader看作本类对象,BufferedReader作为同类对象
//同类对象给本类对象增强(完善)功能---称为装饰者设计模式
BufferedReader br=new BufferedReader(new FileReader
("Test\\src\\file\\a.txt"));
//读取数据
//读取一行数据
/*
文件中内容:你好
helloworld
总共分为两行
*/
/*System.out.println(br.readLine());
System.out.println(br.readLine());
//当内容读取完毕之后将会返回null
System.out.println(br.readLine());*/
//使用循环实现上述功能
String str="";
while((str=br.readLine())!=null){
System.out.println(str);
}
//关流
br.close();
}
}
- BufferedWriter--给字符输出流提供缓冲区(虽然字符输出流自带缓冲区,但是BufferedWriter能够提供更大的缓冲区)
newLine():换行
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建缓冲流对象
BufferedWriter bw=new BufferedWriter(new FileWriter(
"Test\\src\\file\\a.txt",true
));
//写出数据
bw.write("你好");
//换行
bw.newLine();
bw.write("加油");
//关流
bw.close();
}
}
8)转换流
在数据传输的过程中,我们有时候会遇到这样的情况:比如我们需要得到字符流的数据,但是现在我们所拥有的只有字节流对象,或是我们可能会遇到需要字节流但是只有字符里的情况。那么,在这种情况下,我们就需要将字节流和字符流进行相互转换,这时我们会用到我们的转换流。
- OutputStreamWriter----字符流转成字节流
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建转换流对象
//转换对象是由文件字节输出流对象构建
//底层真正进行传输数据的是文件字节输出流对象
//接受准备数据时需要用的是字符形式数据,底层真正往外写出数据的是字节流形式
//所以OutputStreamWriter转换流是将字符流转换成字节流
OutputStreamWriter ow=new OutputStreamWriter(new FileOutputStream(
"Test\\src\\file\\a.txt"
));
//写出数据
//当我们需要写出数据时,我们需要提前准备字符形式的数据
ow.write("你好");
//g关流
ow.close();
}
}
- InputStreamReader----字节流转成字符流
package cn.tedu.test;
import java.io.*;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建转换流对象
//转换流对象是由文件自建输入流对象来提供的
//底层真正读取数据的是文件字节输入流
//先根据文件字节输入流来读取数据,再根据字符流来展示数据
//所以InputStreamReader是将字节流数据转换成为字符流
InputStreamReader isr=new InputStreamReader(new FileInputStream(
"Test\\src\\file\\a.txt"
));
//读取数据
char [] cs=new char[10];//自建缓冲区
int len=-1;
//展示数据为字符形式数据
//展示的数据由字符流来提供
while((len=isr.read(cs))!=-1){
System.out.println(new String(cs,0,len));
}
//关流
isr.close();
}
}
9)系统流
我们首先来看下面的代码:
package cn.tedu.test;
import java.io.*;
import java.util.Scanner;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//输出正确结果
//out---字节输出流对象
System.out.println(1);
//输出错误结果
//err---字节输出流对象
System.err.println(1);
//in---字节输入流对象
Scanner sc=new Scanner(System.in);
int num=sc.nextInt();
System.out.println(num);
}
}
由上面程序可知,out、err、in都是字节流。那么由之前的操作我们可以得知,流对象是可以关闭的,那么我们能否对其进行关闭呢?
package cn.tedu.test;
import java.io.*;
import java.util.Scanner;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
Scanner sc=new Scanner(System.in);
int num=sc.nextInt();
System.out.println(num);
//关流
sc.close();
Scanner sc1=new Scanner(System.in);
int num1=sc1.nextInt();
System.out.println(num1);
}
}
结果如下:
有结果来看,很明显是不可以的,而发生这种情况的原因就是,在底层代码中in是静态流对象,如果关闭了,其他地方无法使用。所以,我们需要注意的是:系统流都是静态的流对象,使用完毕之后不能关流(且系统流不会占用太多内存)
10)打印流
在上一块代码中,我们可以看到out以及err都是PrintStream的对象,PrintStream称为打印流,是字节输出流。
package cn.tedu.test;
import java.io.*;
import java.util.Scanner;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建打印流对象
PrintStream pw=new PrintStream( "Test\\src\\file\\a.txt");
//写出数据
pw.print("123");
pw.println();
pw.print(123);
//关流
pw.close();
}
}
我们的print以及println方法都是定义在打印流中的,我们之前之所以能够将数据打印到控制台中,是因为在System中指定了路径信息为打印台,所以同样的,我们也可以采用一样的方式将信息打印到我们的文件中。
12)序列化与反序列化
在我们的日常生活中,我们面对数据传输时我们往往是需要将大量的数据信息进行传输,更具Java一切皆对象的思想,我们可以将数据封装对象来进行传输或是接收,这样过的过程我们称之为序列化与反序列化
- 序列化:把对象以及相关信息转成字节数组
反序列化:把字节数组转成相应的对象 - 注意:
1.类实现了Serializable接口产生的对象才能被序列化
2.如果属性被static/transient来修饰不能被序列化过去,方法不会被序列化过去
3.serialVersionUID(序列化版本号):在序列化之前会根据类里的属性和方法来计算出一个版本号,随着对象一起序列化过去。在反序列化之前会再次根据类里的属性和方法来计算出一个版本号,根据前后两个版本号进行对比,如果对比结果一致可以进行正常的反序列化,如果对比结果不一致则反序列化失败。(解决方法----提供版本号)
4.集合对象和映射对象都不能直接进行序列化,只能依次遍历元素对象一一进行序列化。(其存放内容的属性均被static修饰,无法被序列化过去) - 实例代码
序列化:
package cn.tedu.test;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class TestDemo1 {
public static void main(String[] args) throws IOException {
//创建对象
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(
"Test\\src\\file\\person.data"
));
//提供对象
Person p=new Person("爱丽丝",12);
//把对象转换成字节数组进行序列化
oos.writeObject(p);
//关流
}
}
//定义代表人的类
class Person implements Serializable{
//java自动提供的序列化版本号
private static final long serialVersionUID = -109039264791201202L;
//提供版本号--java就不再计算版本号
//private static final long serialVersionUID=1555555555L;
//属性
private String name;
private int age;
//属性会被序列化过去
//静态属性不会被序列化过去
//强制属性不会被序列化过去
transient double weight;
//静态属性
private static String classroom;
//方法不会被序列化过去
//定义有参构造
public Person(String name,int age){
this.name=name;
this.age=age;
}
//提供get方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
//重写toString
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
反序列化
package cn.tedu.test;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class TestDemo1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建对象
ObjectInputStream o=new ObjectInputStream(new FileInputStream(
"Test\\src\\file\\person.data"
));
//读取相应的字节数组转换成对应的对象---反序列化
Person p=(Person)o.readObject();
//关流
o.close();
//输出
System.out.println(p);
}
}