Java的IO流

File类

概述

文件和目录路径名的抽象表示形式

(仅仅是一个路径的表示,并不代表具体的事物一定是存在的)

构造方法

public File(String pathname)

根据一个路径名称得到一个File对象

注意:File path=new File("."); 表示的是当前目录

public File(String parent,String child)

根据一个目录和一个子文件(目录)得到一个File对象

File path = new File("E:\Java"); 表示Windows下的E盘里的Java文件(或者是文件夹),注意要用双斜线\。

public File(File parent,Stirng child)

根据一个父的File对象和一个子文件(目录)得到一个File对象

File path = new File(new File("."),"bin"); 表示当前文件夹下的bin文件(文件夹),如果没有bin就会抛出NullPointerException异常。

成员方法

创建功能

public boolean createNewFile()

创建一个新的文件

如果该文件已经存在,就不会创建,不会报错

想要在指定目录下创建文件,前提是该目录必须存在,否则报错

public boolean mkdir()

在指定目录下创建文件夹

如果已经存在了这样的文件夹,就不会创建,返回false

public boolean mkdirs()

创建多级文件夹

(在开发中,要搞清楚你是要创建文件还是文件夹,创建文件需要添加后缀)

删除功能

public boolean delete()

(想要删除一个文件,该文件夹里面的内容必须是空的,即不能删除多级目录)

重命名功能

public boolean renameTo(File dest)

判断功能

public boolean isDirectory()

判断是否是文件夹

public boolean isFile()

判断是否是文件

public boolean exists()

判断文件是否存在

public boolean canRead()

判断文件是否可读

public boolean canWrite()

判断建否可写

public boolean isHidden()

判断文件是否隐藏

基本获取功能

public String getAbsolutePath()

获取绝对路径

public String getPath()

获取相对路径

public String getName()

获取名称

public long length()

获取文件的字节大小

public long lastModified()

返回最后一次被修改的时间戳,精确到了毫秒

高级获取功能

public String[] list()

public String[] list(FilenameFilter filter)

获取指定目录下的所有文件或者文件夹的名称,组成一个数组

list(FilenameFilter filter)方法调用了filter对象中的accept(File dir,String name)方法,而accept方法则是来自于FilenameFilter接口,所以要使用list(FilenameFilter filter)方法就必须实现FilenameFilter接口,accept方法由我们自己定义,所以你想要让什么样的文件名能够使得accept方法返回true(等价于你想要什么样的文件名能够被list方法返回)都由你自己决定了

//用匿名内部类实现list(FilenameFilter filter)
        File path3 = new File(".");  
        String[] nameList3 = path3.list(new FilenameFilter(){
            private Pattern pattern = Pattern.compile("s.*");  
            @Override  
            public boolean accept(File dir, String name) {  
                return pattern.matcher(name).matches();  
            }  
        });  
        for(String itemName : nameList3){  
            System.out.println(itemName);  
        }  

public File[] listFiles()

public File[] listFiles(FilenameFileter filter)

获取指定目录下的所有文件或者文件夹的File数组,第二个构造方法和上面同理

递归

概述

方法定义中调用方法本身的现象

Math.max(Math.max(a,b),c);这仅仅是方法的嵌套使用

递归注意实现

要有出口,否则就是死递归

次数不能太多,否则就内存溢出

构造方法不能递归使用

递归解决问题的思想

找到出口

找到规律

练习

/*
    兔子问题(斐波那契数列)
    1,1,2,3,5,8,13...
*/
public class Test01 {
    public static void main(String[] args) {
​
        //方法1:用数组解决
        int[] arr=new int[40];
        arr[0]=1;
        arr[1]=1;
        for(int i=2;i<40;i++){
​
            arr[i]=arr[i-1]+arr[i-2];
        }
        System.out.println(arr[arr.length-1]);
        System.out.println("################################");
​
        //方法2:用变量解决
        int a=1;
        int b=1;
        int count=0;
        while(count<38){
            int temp=a;
            a=b;
            b=temp+a;
            count++;
        }
        System.out.println(b);
        System.out.println("################################");
​
        //方法3:用递归解决
        int aa=mathList(40);
        System.out.println(aa);
    }
​
    public static int mathList(int a){
        if(a==2||a==1){
            return 1;
        }else{
            return mathList(a-1)+mathList(a-2);
        }
    }
}
​
//找出目标目录下所有以.jpg结尾的文件
public static void getFile(File file){
    File[] files=file.listFiles();
    
    for(File file:files){
        if(file.isDirectory()){
            getFile(file);
        }else if(file.getName().endsWith(".jpg")){
            System.out.println(file.getAbsolutePath());
        }
    }
}

IO流

概述

IO流用来处理设备之间的数据传输(上传文件和下载文件)

java对数据的操作是通过流的方式

java用于操作流的对象都是在IO包中

分类

按照数据流向

输入流 读入数据

输出流 写出数据

注:输入输出是相对java程序而言的,把java程序当做相对对象

按照数据类型

字节流

字符流

什么情况下使用哪种流

1、如果数据所在的文件通过Windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流

2、如果你什么都不知道就用字节流

常用基类

字节流的抽象基类

InputStream,OurputStream

字符流的抽象基类

Reader,Writer

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀

例如:InputStream的子类FileInputStream,Reader的子类FileReader

字节流写数据

FileOutputStream

OutputStream的子类

构造方法

FileOutputSream(File file,boolean append)

FileOutputStream(String name)

字节流写数据的方式

public void write(int b)

public void write(byte[] b)

public void write(byte[] b,int off,int len)

释放资源

关闭此文件输出流并释放与此流相关联的任何系统资源

字节输出流对象.close();

原因:

1、让字节输出流对象变成一个垃圾,这样就可以被回收了

2、去通知系统关闭相关资源

JVM创建字节输出流做了哪些事情

1、调用了系统的创建文件的功能

2、创建FileOutputStream对象

3、建立实际文件与该对象的联系,该对象就指向于这个文件

步骤

1、创建字节输出流对象

如果构造方法内的文件不存在就会自动创建

2、写数据

字节输出流对象.write("abc".getByte());

实现换行:

字节输出流对象.write("\r\n".getByte());

(每个系统的换行符是不一样的,Windows:\r\n Mac:\r Linux:\n)

实现数据追加:

追加:在原有的文件内容上继续添加一些其他内容

覆盖:将原有的文件内容先删掉,再添加一些其他内容

FileOutputStream(FIle file,boolean append)构造方法

创建文件输入流以写入由指定的FIle对象表示的文件,append是判断是否追加写入

追加写入 true代表的是追加写入,默认是false

3、释放资源

字节流读取数据

FileInputStream

InputStream的子类

构造方法

FileInputStream(File file)

FileInputStream(String name)

成员方法

public int read()

从该输入流读取一个字节的数据

当没有可读内容的时候返回-1

public int read(byte[] b)

从该输入流读取最多b.length个字节的数据为字节数组

步骤

1、创建FileInputStream对象

2、调用read方法读取数据,输出到控制台

1.一次一个字节的读取

public int read()

2.一次读取一个字节数组(最好给1024的倍数)

public int read(byte[] b)

File file=new file("E:\\a");
FileInputStream fis=new FileInputStream(file);
byte[] bys = new byte[1024];
int length=0;
while((length=fis.read(byte))!=-1){
    String s = new String(bys,0,bys.length);
    //建议使用String(byte[] a,int off,int len)的构造方法,因为最后的时候若内容不足数组长度会有默认    //值,如果不用len限制的话,会把默认值也读出来
    System.out.print(s);
}
fis.close();

3、释放资源

字节缓冲流

字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式),所以提供了字节缓冲区流

字节缓冲输出流

BufferedOutputStream

构造方法

new BufferedOutputStream(new FileOutputStream(...));

成员方法

bos.write(); //用法与字节流类似

bos.flush(); //将缓冲区的内容输出到文件

bos.close();

字节缓冲输入流

BufferedInputStream

构造方法

new BufferedInputStream(new FileInputStream(...));

成员方法

bis.read(); //用法与字节流类似

bis.close();

转换流

概述

由于字节流操作中文不是很方便,所以,java就提供了转换流

字符流=字节流+编码表

OutputStreamWriter字符输出流

构造方法

public OutputStreamWriter(OutputStream out)

public OutputStreamWriter(OutputStream out,String charsetName)

成员方法

public void write(int c)

public void write(char[] cbuf)

public void wirte(char[] cbuf,int off,int len)

public void write(String str)

public void write(String str,int off,int len)

public void flush() //刷新缓冲区,将缓冲区的内容写到文件中

public void close() //注:字符流的close()是先flush再关闭

InputStreamReader字符输入流

构造方法

public InputStreamReader(InputStream in)

public InputStreamReader(InputStream in,String charsetName)

成员方法

public int read() 一次只读一个字符

public int read(char[] cbuf) 一次读取一个字符数组

public void close()

转换流的简化写法

转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类

FIleWriter写数据

FileReader读取数据

注:用法与转换流一致,可在构造方法里直接写文件路径,不用再新创建一个FileInputStream

字符缓冲流

字符流为了高效读写,也提供了相对应的字符缓冲流

BufferedWriter字符缓冲输出流

将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入

可以指定缓冲区大小,或者可以接收默认大小

默认值足够大,可用于大多数用途

构造方法

new BufferedWriter(new FileWriter(...))

new BufferedWriter(new OutputStreamWriter(new FileOutputStream(...)))

成员方法

public void write()

public void flush()

public void close()

public void newLine()

写一行行分隔符,行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符('\n')(即由系统决定)

BufferedReader字符缓冲输入流

创建使用默认大小的输入缓冲区的缓冲字符输入流

构造方法

new BufferedReader(new FileReader(...))

new BufferedReader(new OutputStreamReader(new FileOutputStream(...)))

成员方法

public void read()

public void close()

public String readLine()

读取一行文字,到换行符终止,若没有内容则返回null

//用字符缓冲流实现文件复制
​
BufferedWriter bd=new BufferedWriter(new FileWriter("b.txt"));
BufferedReader br=new BufferedReader(new FileReader("a.txt"));
​
String len=null;
while((len=br.readLine())!=null){
    bd.write(len);
    bd.newLine();
    bd.flush();
}
br.close();
bd.close();

IO流总结

IO:是用来解之间数据传输的问题
​
按照流向进行划分:
    1、输入流
    2、输出流
​
按照数据类型划分:
    1、字节流
        1)基本字节流
            基本字节输入流
                InputStream(抽象类)
                    FileInputStream
                    读取数据的两种方式:
                        a:一次只读一个字节
                            int b = 0;
                            while((b=fis.read())!=-1){
                                System.out.print((char)b);
                            }
                            fis.close()
                        b:一次读取一个字节数组
                            byte[] bytes = new byte[1024];
                            int length = 0;
                            while((length = fis.read(bytes))!=-1){
                                System.out.print(new String(bytes,0,length));
                            }
                            fis.close()
            基本字节输出流
                OutputStream(抽象类)
                    FileOutputStream
                    写数据的三种方式:
                        一次只写一个字节
                        一次写一个字节数组
                        一次写一个字节数组的一部分
                    注意:每写完后,调用flush()刷新缓冲区
        2)字节缓冲流
            字节缓冲输入流
                BufferedInputStream
                创建对象:
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(...));
                    读取数据的两种方式:
                        a:一次只读一个字节
                            int b = 0;
                            while((b=bis.read())!=-1){
                                System.out.print((char)b);
                            }
                            bis.close();
                        b:一次读取一个字节数组
                            byte[] bytes = new byte[1024];
                            int length = 0;
                            while((length = bis.read(bytes))!=-1){
                                System.out.print(new String(bytes,0,length));
                            }
                            bis.close();
            字节缓冲输出流
                BufferedOutputStream
                创建对象:
                     BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(...));
                    写数据的三种方式:
                        一次只写一个字节
                        一次写一个字节数组
                        一次写一个字节数组的一部分
                        注意:每写完后,调用flush()刷新缓冲区
​
    2、字符流
        字符流 = 字节流 + 编码表
        1)基本字符转换流
            基本字符输入流 Reader
                A: InputStreamReader
                   创建对象:
                        InputStreamReader isr = new InputStreamReader(new FileInputStream(...));
                        读取数据的两种方式:
                        a) 一次只读取一个字符
                            int ch = 0;
                            while((ch = isr.read())!=-1){
                                System.out.println((char)ch);
                            }
                            isr.close();
                        b) 一次读取一个字符数组
                            char[] chars = new char[1024];
                            int length = 0;
                            while((length = isr.read(chars))!=-1){
                                System.out.print(new String(chars,0,length));
                            }
                            isr.close();
​
                B:简化写法:FileReader
                    创建对象:
                       FileReader fr = new FileReader(...);
                        读取数据的两种方式:
                        a) 一次只读取一个字符
                            int ch = 0;
                            while((ch = fr.read())!=-1){
                                System.out.println((char)ch);
                            }
                            fr.close();
                        b) 一次读取一个字符数组
                            char[] chars = new char[1024];
                            int length = 0;
                            while((length = fr.read(chars))!=-1){
                                System.out.print(new String(chars,0,length));
                            }
                            fr.close();
​
            基本字符输出流 Writer:
                A: OutputStreamWriter
                    创建对象:
                        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(...));
                        一次只写一个字符
                        一次写一个字符数组
                        一次写一个字符数组的一部分
                        注意:每写完后,调用flush()刷新缓冲区
                B:简化写法:FileWriter
                    创建对象:
                        FileWriter fw = new FileWriter(...);
                        一次只写一个字符
                        一次写一个字符数组
                        一次写一个字符数组的一部分
                        注意:每写完后,调用flush()刷新缓冲区
        2)字符缓冲流
            字符缓冲输入流:
                BufferedReader:
                    创建对象:
                        方式1:BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(...)));
                        方式2:BufferedReader br = new BufferedReader(new FileReader(...));
                    读取数据的三种方式:
                        a)一次读取一个字符
                        b)一次读取一个字符数组
                        c)特殊方法:readLine(),一次读取一行
                            String line = null;
                            while((line=br.readLine())!=null){
                                System.out.println(line);
                            }
                            br.close();
            字符缓冲输出流:
                BufferedWriter
                    创建对象:
                        方式1:BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(...)));
                        方式2:BufferedWriter bw = new BufferedWriter(new FileWriter(...));
                    写数据的四种方式:
                        a)一次只写一个字符
                        b)一次写一个字符数组
                        c)一次写一个字符数组的一部分
                        d)特殊方法:newLine();
                        注意:每写完后,调用flush()刷新缓冲区

补充

new BufferedReader(new InputStreamReader(System.in))
直接控制台读取数据
原因:
System.in是个字节流
InputStreamReader是个字符流和字节流之间的转换中介
BufferedReader是个字符流
整体意思就是用InputStreamReader这个中介把System.in这个字节流转换成字符流BufferedReader
这样输入的时候就可以不是一个一个字节读,而是一个一个字符读,再加上是个Buffer,效率会高很多。

序列化流和反序列化流

序列化流

把对象按照流一样的方式存到文本文件或者数据库或者网络中传输等

对象---流数据:ObjectOutputStream

将对象存入到文件中,其实就是将对象进行持久化

oos.writeObject(对象名); //将指定的对象写入ObjectOutputStream

ObjectOutputStream oos=new ObjectOutputStream(new FIleOutputStream(...));
Person person=new Person();
oos.writeObject(person);
oos.close();

注意:

Java.io.NotSerializableException 未序列化异常

类的序列化由实现java.io.Serializable接口的类启用

不实现此接口的类将不会使任何状态序列化或反序列化。

可序列化类的所有子类型都是可序列化的。

序列化接口没有方法或者字段,仅用于标识可串行化的语义

反序列化流

把文本文件中的流对象数据或者网络中的流数据给还原成一个对象

流对象---对象:ObjectInputStream

ois.readObject(); //从ObjectInputStream读取一个对象

ObjectInputStream ois=new ObjectInputStream(new FileInputStream(...));
​
Object o=ois.readObject();
Person p=(Person)o;
​
ois.close();
​
System.out.pintln(p);

如果完成对象的序列化之后,修改了对象类的内容(比如把private改成public),再反序列化存储的对象会发生报错

原因:

Person类实现了Serializable标记接口,它本身就应该有一个标记值。

假设一开始这个标记值是id=100

在没有修改Person类的之前:

Person.class -- id=100

写数据的时候:obj.txt -- id=100

读数据的时候:obj.txt -- id=100

进行修改后:(把private删了)

Person.class -- id=200

写数据的时候:obj.txt -- id=100

读数据的时候:obj.txt -- id=100

正常解决的情况:按照修改后的Person类重新再存一次

在实际开发中,我们因业务问题,不允许重复往文件或者某数据库重复存储(写入),那怎么办呢

这个问题是由于id值的不匹配(class文件的id值与文件中存储对象的id不匹配)导致的。

如果说有一个办法可以让这个ID值固定不变就好了

Java在序列化中提供了一个ID值,可以让我们去设定。

serialVersionUID(在类名上按alt+enter自动生成)

需求:

现在我不想在序列化的时候把年龄也序列化存到文件中

java中提供了一个关键字transient,可以让我们在序列化的时候选择那些成员不被序列化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值