File类
File类:封装文件、目录的各种信息,对文件、目录进行操作,但是不能获取文件、目录中的内容
对文件进行操作
public class TestFile {
public static void main(String[] args) throws IOException {
//将文件封装为file类的对象
File f=new File("d:\\test.txt");
File f1=new File("d:/test.txt");
//File.separator这个属性可以帮我们获取当前操作系统的路径拼接符号
File f2=new File("d:"+File.separator+"test.txt");//建议使用这种,可以跨平台windows或linux
//常用方法:
System.out.println("文件是否可读:"+f.canRead());
System.out.println("文件是否可写:"+f.canWrite());
System.out.println("文件的名字:" +f.getName());
System.out.println("上级目录:" +f.getParent());
System.out.println("是否是一个目录:" +f.isDirectory());
System.out.println("是否是一个文件:" +f.isFile());
System.out.println("是否隐藏:" +f.isHidden());
System.out.println("文件大小:" +f.length()+"字节");
System.out.println("是否存在:" +f.exists());
if(f.exists()){//如果文件存在,就删除文件
f.delete();
}else{//如果文件不存在,就创建文件
f.createNewFile();
}
System.out.println("两个文件的地址是否一致:"+(f==f1));//比较两个对象的地址false
System.out.println("两个文件的路径是否一致:"+(f.equals(f1)));//并比较两个对象对应的文件路径
//与路径相关的
System.out.println("文件的绝对路径:"+f.getAbsolutePath());
System.out.println("文件的相对路径:"+f.getPath());
System.out.println("toString:"+f.toString());
File f4=new File("demo.txt");
if(!f4.exists()){
f4.createNewFile();
}
System.out.println("-------------");
System.out.println("文件的绝对路径:"+f4.getAbsolutePath());
System.out.println("文件的相对路径:"+f4.getPath());
System.out.println("toString:"+f4.toString());//toString的效果永远是相对路径
//绝对路径指的是:真实的精准的路径
//相对路径指的是:有参照物,是相对这个参照物的路径
//在main方法中,相对路径值得就是:C:\Users\sky\IdeaProjects\untitled
}
}
对路径进行操作
public class Test01 {
public static void main(String[] args) {
//将目录封装为file对象
File f=new File("C:\\Users\\sky\\IdeaProjects");
System.out.println("目录是否可读:"+f.canRead());
System.out.println("目录是否可写:"+f.canWrite());
System.out.println("目录的名字:" +f.getName());
System.out.println("上级目录:" +f.getParent());
System.out.println("是否是一个目录:" +f.isDirectory());
System.out.println("是否是一个文件:" +f.isFile());
System.out.println("是否隐藏:" +f.isHidden());
System.out.println("目录大小:" +f.length()+"字节");
System.out.println("是否存在:" +f.exists());
System.out.println("目录的绝对路径:"+f.getAbsolutePath());
System.out.println("目录的相对路径:"+f.getPath());
//与目录相关的方法:
File f1=new File("D:\\a");
//创建一层目录
f1.mkdir();
File f2=new File("D:\\b\\c\\d");
//创建多层目录
f2.mkdirs();
//删除:如果是删除目录的话,只会删除一层,并且前提是目录为空,里面没有内容,如果有内容就不会删除
f1.delete();
f2.delete();//只删除了d目录
//查看:
String[] list = f.list();
for(String s:list){
System.out.println(s);//输出此目录下文件和目录的名字
}
System.out.println("---------------------");
File[] files = f.listFiles();//作用更加广泛
for(File file:files){
System.out.println(file);//输出此目录下文件和目录的绝对路径
System.out.println(file.getName()+":"+file.getAbsolutePath());
}
}
}
IO流
IO流体系:
FileReader,FileWriter类
案例:通过程序完成文件的复制
功能分解1:文件—》程序:File Reader
用File Reader一个字符一个字符的将文件中的内容读取到程序中
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestCopy {
public static void main(String[] args) throws IOException {
//功能分解1:文件---》程序:FileReader
//1.有一个具体文件:
File f=new File("D:\\test.txt");
//2.利用FileReader这个流,把这个管怼到文件上去----》创建FileReader这个流的对象
FileReader fr=new FileReader(f);
//3.进行吸的操作-----》读取动作
/*下面的代码我们验证了:如果读到文件的结尾处,那么读取的内容为-1
int n1 = fr.read();
int n2 = fr.read();
int n3 = fr.read();
int n4 = fr.read();
int n5 = fr.read();
int n6 = fr.read();
System.out.println(n1);//97
System.out.println(n2);//98
System.out.println(n3);//99
System.out.println(n4);//25105
System.out.println(n5);//26159
System.out.println(n6);//-1*/
//方式1:
int n=fr.read();
while(n!=-1){
System.out.println(n);//输出的是对应unicode码
n=fr.read();
}
//方式2:
int m;
while((m=fr.read())!=-1){
System.out.println((char)m);
}
//4.管不用了,就要关闭----》关闭流
//流,数据库,网络资源靠jvm本身没有办法帮我们关闭,此时必须程序员手动关闭
fr.close();
}
}
想一次性读取多个字符,不够的话,下次再来:利用缓冲数组
public class TestCopys {
public static void main(String[] args) throws IOException {
//功能分解1:文件---》程序:FileReader
//1.有一个具体文件:
File f=new File("D:\\test.txt");
//2.创建FileReader这个流的对象
FileReader fr=new FileReader(f);
//3.读取动作,一次读取多个
//引入一个”快递员小车“,这个小车一次拉5个字符
char[] ch=new char[5];//缓冲数组
int len = fr.read(ch);//一次读取5个:返回值是数组中的有效长度
while(len!=-1){
//System.out.println(len);
/*错误方式:
for (int i = 0; i <ch.length ; i++) {
System.out.println(ch[i]);
}*/
//正确方式1:
for (int i = 0; i <len ; i++) {
System.out.println(ch[i]);
}
//正确方式2:将数组转为String,但是要注意输出长度
String str=new String(ch,0,len);
System.out.print(str);
len=fr.read(ch);
}
//4.关闭流
fr.close();
}
}
功能分解2:程序—》文件:FileWriter
一个字符一个字符的向外输出
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestPaste {
public static void main(String[] args) throws IOException {
//1.有一个目标文件
File f=new File("d:\\demo.txt");//如果目标文件不存在的话,会自动创建文件
//2.FileWriter管子怼到文件上去
FileWriter fw=new FileWriter(f,true);
//加上false意味着只覆盖不追加;加上true意味着只追加不覆盖;不加==加上false
//3.开始动作:输出动作:一个字符一个字符往外输出
String str=new String("hello,我是sky");
//如果目标文件存在的话,new FileWriter(f) 相当于对源文件进行覆盖操作
for (int i = 0; i <str.length() ; i++) {
fw.write(str.charAt(i));
}
//4.关闭字符流
fw.close();
}
}
如果目标文件不存在的话,会自动创建文件
如果目标文件存在的话,new FileWriter(f) 相当于对源文件进行覆盖操作;new FileWriter(f,false)加上false意味着只覆盖不追加;new FileWriter(f,true);加上true意味着只追加不覆盖
n个字符n个字符的向外输出
public class TestPastes {
public static void main(String[] args) throws IOException {
//1.有一个目标文件
File f=new File("d:\\demo.txt");
//2.FileWriter管子怼到文件上去
FileWriter fw=new FileWriter(f);
//3.开始动作:输出动作:n个字符n个字符往外输出
String str="skyyyyy";
char[] chars = str.toCharArray();
fw.write(chars);
//4.关闭字符流
fw.close();
}
}
功能分解3:利用FileReader和 FileWriter完成文件复制
public class TestWhole {
public static void main(String[] args) throws IOException {
File ori=new File("d://test.txt");//源文件
File goal=new File("d://demo.txt");//目标文件
FileReader fr=new FileReader(ori);//输入管
FileWriter fw=new FileWriter(goal);//输出管
//开始动作
//方式1.一个字符一个字符
/*int n=fr.read();
while(n!=-1){
fw.write(n);
n=fr.read();
}
fw.close();//关闭流的时候,一般倒着关闭,后用谁,先关谁
fr.close();*/
//方式2.利用缓冲数组
/*char[] orich=new char[5];
int len=fr.read(orich);//返回有效长度
while(len!=-1){
fw.write(orich,0,len);//将缓冲数组中有效长度写出
len=fr.read(orich);
}
fw.close();//关闭流的时候,一般倒着关闭,后用谁,先关谁
fr.close();*/
//方式3.将缓冲数组转成字符串输出
char[] orich=new char[5];
int len=fr.read(orich);//返回有效长度
while(len!=-1){
String s=new String(orich,0,len);//将缓冲数组中有效长度转成字符串
fw.write(s);
len=fr.read(orich);
}
fw.close();//关闭流的时候,一般倒着关闭,后用谁,先关谁
fr.close();
}
}
警告:不要用字符流去操作非文本文件
文本文件:纯文本的 .txt .java .c .cpp ------->建议使用字符流操作
非文本文件:.jpg .mp3 .mp4 .doc .ppt --------->建议使用字节流操作
利用try-catch-finally处理异常
public class TestWhole {
public static void main(String[] args) {
File ori=new File("d://test.txt");
File goal=new File("d://demo.txt");
FileReader fr= null;
FileWriter fw=null;
try {
fr = new FileReader(ori);
fw=new FileWriter(goal);
char[] orich=new char[5];
int len=fr.read(orich);
while(len!=-1){
String s=new String(orich,0,len);
fw.write(s);
len=fr.read(orich);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fw!=null){//防止空指针异常
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fr!=null){//防止空指针异常
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream,FileOutputStream类
1、利用字节流读取文本文件
public class TestFileInputStream {
//利用字节流将文本文件中的内容读取到程序中来
public static void main(String[] args) throws IOException {
//1.一个源文件
File f=new File("d:\\test.txt");
//2.将源文件对上字节流管子
FileInputStream fis=new FileInputStream(f);
//3.开始读取动作
/*细节1:文件是UTF-8进行存储的,英文字符底层占1个字节,中文字符底层占3个字节
* 细节2:如果是文本文件,不要使用字节流,用字符流
* 细节3:read读取一个字节,返回值是int类型而不是byte类型?
* read方法底层做了处理,返回的值都是正数,就是为了避免如果字节返回的是-1的话,这到底是读入的字节还是文件结尾?*/
int n = fis.read();
while(n!=-1){
System.out.println(n);
n=fis.read();
}
//4.关闭流
fis.close();
}
}
2、利用字节流读取非文本文件,一个字节一个字节读取
public class TestFileInputStream02 {
//读取非文本文件
public static void main(String[] args) throws IOException {
//1.一个源文件
File f=new File("d:\\tu.jpg");
//2.将源文件对上字节流管子
FileInputStream fis=new FileInputStream(f);
//3.开始读取动作
int count=0;//定义一个计数器,用来计读入的字节的个数
int n = fis.read();
while(n!=-1){
System.out.println(n);
n=fis.read();
count++;
}
System.out.println("总字节数:"+count);
//4.关闭流
fis.close();
}
}
public class TestFileInputStream03 {
//读取非文本文件
public static void main(String[] args) throws IOException {
//1.一个源文件
File f=new File("d:\\tu.jpg");
//2.将源文件对上字节流管子
FileInputStream fis=new FileInputStream(f);
//3.开始读取动作,利用缓冲数组
int count=0;
byte[] b=new byte[1024*8];//缓冲数组
int len=fis.read(b);//len指的是读取的数组的有效长度
while(len!=-1){
for (int i = 0; i <len ; i++) {
System.out.println(b[i]);
count++;
}
System.out.println("-----------");
len=fis.read(b);
}
//4.关闭流
System.out.println("count="+count);
fis.close();
}
}
3、FileInputStream,FileOutputStream完成非文本文件的复制
public class TestFileIOStream {
//读取非文本文件
public static void main(String[] args) throws IOException {
//1.一个源文件
File orif=new File("d:\\tu.jpg");
//2.目标文件
File objf=new File("d:\\copytu.jpg");
//3.将源文件对上字节流管子
FileInputStream fis=new FileInputStream(orif);
//4.将目标文件对上字节流管子
FileOutputStream fos=new FileOutputStream(objf);
//5.开始复制:边读边写
//方式1.读入一个字节写一个字节
int n=fis.read();
while(n!=-1){
fos.write(n);
n=fis.read();
}
//方式2.利用缓冲数组
byte[] b=new byte[1024*8];
int len=fis.read(b);
while(len!=-1){
fos.write(b,0,len);//注意!不写长度的话,两个图片大小不一样,虽然看不出来
len=fis.read(b);
}
//6.关闭流,倒着关闭,先用后关
fos.close();
fis.close();
}
}
利用缓冲数组写入的时候一定要注意长度
缓冲流
缓冲字节流(处理流)
BufferedInputStream,BufferedOutputStream类
完成图片复制:
public class TestBufferedIOStream {
public static void main(String[] args) throws IOException {
//1.一个源文件
File orif=new File("d:\\tu.jpg");
//2.目标文件
File objf=new File("d:\\copytu.jpg");
//3.将源文件对上字节流管子
FileInputStream fis=new FileInputStream(orif);
//4.将目标文件对上字节流管子
FileOutputStream fos=new FileOutputStream(objf);
//5.功能加强,在FileInputStream外面套一个管,BufferedInputStream
BufferedInputStream bis=new BufferedInputStream(fis);
//6.功能加强,在FileOutputStream外面套一个管,BufferedOutputStream
BufferedOutputStream bos=new BufferedOutputStream(fos);
//7.开始操作
long startTime=System.currentTimeMillis();
byte[] b=new byte[1024];
int len=bis.read(b);
while(len!=-1){
bos.write(b,0,len);
/*bos.flush();//底层已经帮我们做了刷新缓冲区的操作,不用手动刷新;底层调用flushbuffer()*/
len=bis.read(b);
}
long endTime=System.currentTimeMillis();
System.out.println("用时:"+(endTime-startTime));
//8.关闭流
//倒着关
//如果处理流包裹着节点流的话,那么只要关闭高级流(处理流),那么里面的节点流也会随之关闭
bos.close();
bis.close();
/*fos.close();
fis.close();*/
}
}
缓冲字符流(处理流)
BufferedReader,BufferedWriter类
完成文本文件的复制:
public class TestBufferedRW {
public static void main(String[] args) throws IOException {
//1.源文件
File orif=new File("d:\\llla.txt");
//2.目标文件
File objf=new File("d:\\copy.txt");
//3.源小管
FileReader fr=new FileReader(orif);
//4.目标小管
FileWriter fw=new FileWriter(objf);
//5.源大管
BufferedReader br=new BufferedReader(fr);
//6.目标大管
BufferedWriter bw=new BufferedWriter(fw);
//7.开始动作
long startTime=System.currentTimeMillis();
//方式1.一个字节一个字节来
int n=br.read();
while(n!=-1){
bw.write(n);
n=br.read();
}//用时:254
//方式2.利用缓冲数组
char[] c=new char[1024];
int len=br.read(c);
while(len!=-1){
bw.write(c,0,len);
len=br.read(c);
}//用时:78
//方式3.String方法
String str=br.readLine();//每次读取文本文件中的一行,返回字符串
while(str!=null){
bw.write(str);
//在文本文件中应该有个换行操作
bw.newLine();//新起一行
br.readLine();
}//110
long endTime=System.currentTimeMillis();
System.out.println("用时:"+(endTime-startTime));
//8.关闭
bw.close();
br.close();
}
}
转换流
字符流
InputStreamReader,OutputStreamWriter类
转换流:将字节流和字符流进行转换
InputStreamReader:字节输入流--------》字符输入流
OutputStreamWriter:字符输出流------》字节输出流
4、将输入的字节流转换为输入的字符流,然后完成文件----》程序
public class TestInputStreamReader {
public static void main(String[] args) throws IOException {
//1.源文件
File orif=new File("d:\\test.txt");
//2.字节流
FileInputStream fis=new FileInputStream(orif);
//3.转换流
//将字节转换为字符时,需要指定一个编码,这个编码需要与文件本身的编码格式统一
//如果编码格式不统一,那么会出现乱码
//InputStreamReader isr=new InputStreamReader(fis,"utf-8");
//会获取程序本身的编码格式
InputStreamReader isr=new InputStreamReader(fis);
//4.开始动作
char[] chars=new char[20];
int len=isr.read(chars);
while(len!=-1){
System.out.print(new String(chars,0,len));
len=isr.read(chars);
}
//5.关闭流
isr.close();
}
}
完整复制
public class TestIOStreamRW {
public static void main(String[] args) throws IOException {
//1.源文件
File orif=new File("d:\\test.txt");
//2.目标文件
File objf=new File("d:\\demo.txt");
//3.输入方向
FileInputStream fis=new FileInputStream(orif);
InputStreamReader isr=new InputStreamReader(fis,"utf-8");
//4.输出方向
FileOutputStream fos=new FileOutputStream(objf);
OutputStreamWriter osw=new OutputStreamWriter(fos,"gbk");//ANSI指的就是GBK
//5.开始动作
char[] chars=new char[20];
int len=isr.read(chars);
while(len!=-1){
osw.write(chars,0,len);
len=isr.read(chars);
}
//6.关闭流
osw.close();
isr.close();
}
}
System类对IO流的支持
System.in:“标准”输入流------------》默认情况下,从键盘输入
InputStream
public class TestSystem {
public static void main(String[] args) throws IOException {
//得到的是标准的输入流------》从键盘输入
InputStream in = System.in;
//调用方法
int n=in.read();//read方法等待键盘的输入,所以这个方法是阻塞方法
System.out.println(n);
//以前案例:从键盘输入一个int类型数据
//从上面代码证明,键盘录入实际上是System.in完成的
//形象的理解:System.in管,这个管对倒键盘上,所以从键盘录入的话,就从这个管到程序中了
//Scanner的作用:扫描器:起扫描的作用,扫键盘的从这跟管出来的数据
Scanner sc=new Scanner(System.in);
int x=sc.nextInt();
System.out.println(x);
//既然Scanner是扫描的作用,那么它不一定非得扫System.in进来的东西,还可以扫描其他管的内容
Scanner sc1=new Scanner(new FileInputStream(new File("d:\\test.txt")));
while(sc1.hasNext()){
System.out.print(sc1.next());
}
}
}
System.out:“标准”输出流。--------》默认情况下,输出到控制台 PrintStream
public class TestSystemO {
public static void main(String[] args) {
//写到控制台
PrintStream out = System.out;
//调用方法
out.print("nihao");//直接写在控制台,不换行
out.println("wuhhhh");//直接在控制台写出,并且换行
System.out.println("lalala");
}
}
练习:将键盘录入的内容输出到文件中
public class TestSF {
public static void main(String[] args) throws IOException {
//键盘的标准输入流:字节流
InputStream is=System.in;
//输入转换流:字节流---》字符流
InputStreamReader isr=new InputStreamReader(is);
//输入处理流:加强字符流
BufferedReader br=new BufferedReader(isr);
//目标文件
File objf=new File("d:\\obj.txt");
//输出字符流
FileWriter fw=new FileWriter(objf);
//输出处理流
BufferedWriter bw=new BufferedWriter(fw);
//开始动作
String s=br.readLine();
while(!s.equals("exit")){//注意退出条件
bw.write(s);
bw.newLine();//文件中换行
s=br.readLine();
}
//关闭
bw.close();
br.close();
}
}
数据流
DataInputStream,DataOutputStream类
数据流、:用来操作基本数据类型和字符串
利用DataOutputStream向外写出变量
public class TestDataOutputStream {
public static void main(String[] args) throws IOException {
//DataOutputStream:
File f=new File("d:demo.txt");
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos= new DataOutputStream(fos);//相当于加强操作
//合到一起
//DataOutputStream dos= new DataOutputStream(new FileOutputStream(new File("d:demo.txt")));
//向外将变量写到文件中去
dos.writeUTF("呜哈哈哈哈哈");
dos.writeBoolean(false);
dos.writeDouble(9.8);
dos.writeInt(82);
//关闭流
dos.close();
}
}
乱码了
这个内容我们看不懂,是给程序看的
public class TestDataInputStream {
public static void main(String[] args) throws IOException {
//DataInputStream
DataInputStream dis=new DataInputStream(new FileInputStream(new File("d:\\demo.txt")));
//将文件中内容读取到程序中
//按刚才的顺序读
System.out.println(dis.readUTF());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
//关闭流
dis.close();
}
}
结果:
验证:那个文件我们看不懂,程序可以懂
要求:写出的类型与读入的类型必须要匹配!
对象流
ObjectInputStream,ObjectOutputStream类
将一个字符串对象,写入到文件中去--------》序列化
public class TestObjectOutputStream {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("d:\\demo1.txt")));
//将内存中的字符串写出到文件中
oos.writeObject("你好");
//关闭流
oos.close();
}
}
结果
我们看不懂文件内容,但程序可以看懂,所以写一个程序读取内容—》反序列化
public class TestObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//将看不懂文件读入
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("d:\\demo1.txt")));
//在控制台输出
//System.out.println(ois.readObject());
String s=(String)(ois.readObject());
System.out.println(s);
//关闭流
ois.close();
}
}
上述两过程就叫做序列化和反序列化
操作自定义类的对象
自定义的Person类
public class Person implements java.io.Serializable {
private static final long serialVersionUID=156649879625656L;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
测试类
public class TestZidingyi {
public static void main(String[] args) throws IOException {
//序列化:将内存中的对象-----》文件
//创建自定义对象
Person p=new Person("sky",23);
//有对象流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("d:\\demo1.txt")));
//向外写
oos.writeObject(p);
//关闭流
oos.close();
}
}
运行时出现异常:没有序列化异常
出现异常的原因:Person类没有实现序列化接口
你想要序列化对象对应的类,必须要实现一个接口:Serializable
接口内部什么都没有,这种接口叫做标识接口,起到标识作用
标识什么呢?
只有实现这个接口的类的对象才能序列化,否则不可以。
实现接口后,发现序列化成功,person具有了序列化能力
用程序把上面看不懂的东西进行反序列化
public class TestFan {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("d:\\demo1.txt")));
//System.out.println(ois.readObject());
//读入内存
Person p = (Person)(ois.readObject());
System.out.println(p);
//关闭流
ois.close();
}
}
输出的结果是这样是因为我们没有重写toString,证明反序列化成功
静态变量改为静态常量
加入toString后,出现异常:
出现异常的原因:
重新运行写入程序后结果
但是,不能总是通过重新运行写入程序解决
解决办法:给这个类加入一个序列号:serialVersionUID
序列化的细节
如密码等需要保护的东西,不想被序列化的可以被transient修饰
静态的被类共享的用static修饰