java——IO流

一、文件

1.1、什么是文件

文件,对我们并不陌生,文件是保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件...都是文件。它既可以保存一张图片,也可以保持视频,声音...

1.2、文件流

文件在程序中是以流的形式来操作的

1、流:数据在数据源(文件)和程序(内存)之间经历的路径

2、输入流:数据从数据源(文件)到程序(内存)的路径

3、输出流:数据从程序(内存)到数据源(文件)的路径

二、常用的文件操作

2.1、创建文件对象相关构造器和方法

new File(String pathname) //根据路径构建一个File对象
new File(File parent,String child) //根据父目录文件+子路径构建
new File(String parent,String child) //根据父目录+子路径构建

2.2、获取文件的相关信息

getName、getAbsolutePath、getParent、length、exists、isFile、isDirectory

2.3、目录的操作和文件删除

1、mkdir创建一级目录、mkdirs创建多级目录、delete删除空目录或文件

2、mkdir()和mkdirs()都是放回boolean值

三、IO流原理及流的分类

3.1、Java IO流原理

1、I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。

2、Java程序中,对于数据的输入/输出操作以”流(stream)”的方式进行。

3、java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据

4、输入input;读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

5、输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中

3.2、流的分类

按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件

按数据流的流向不同分为:输入流,输出流

按流的角色的不同分为:节点流,处理流/包装流

1) Java的IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。

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

四、IO 流体系图-常用的类

4.1、IO 流体系图

4.2、文件 VS 流

4.3、FileInputStream 介绍

public class FileInputStream_ {
    public static void main(String[] args) {

    }
    /**
     * 读取文件...
     * 单个字节的读取,效率比较低
     * -> 使用 read(byte[] b)
     */
    @Test
    public void readFile01() {
        String filePath = "e:\\hello.txt";
        int readData = 0;
        FileInputStream fileInputStream = null;
        try {
            //创建 FileInputStream 对象,用于读取 文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。
            //如果返回-1 , 表示读取完毕
            while ((readData = fileInputStream.read()) != -1) {
                System.out.print((char)readData);//转成char显示
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源.
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 使用 read(byte[] b) 读取文件,提高效率
     */
    @Test
    public void readFile02() {
        String filePath = "e:\\hello.txt";
        //字节数组
        byte[] buf = new byte[8]; //一次读取8个字节.
        int readLen = 0;
        FileInputStream fileInputStream = null;
        try {
            //创建 FileInputStream 对象,用于读取 文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取最多b.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。
            //如果返回-1 , 表示读取完毕
            //如果读取正常, 返回实际读取的字节数
            while ((readLen = fileInputStream.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));//显示
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源.
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

4.4、FileOutputStream 介绍

1. new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容
2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面
s.getBytes() 可以把 字符串-> 字

4.5、FileReader 和 FileWriter 介绍

4.6、FileReader 相关方法:

1) new FileReader(File/String)

2) read:每次读取单个字符,返回该字符,如果到文件末尾返回-1

3) read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1

相关API:

1) new String(char[]):将char[]转换成String

2) new String(char[],off,len):将char[]的指定部分转换成String

4.7、FileWriter 常用方法

1) new FileWriter(File/String):覆盖模式,相当于流的指针在首端

2) new FileWriter(File/String,true):追加模式,相当于流的指针在尾端

3) write(int):写入单个字符

4) write(char[]):写入指定数组

5) write(char[],off,len):写入指定数组的指定部分

6) write (string):写入整个字符串

7) write(string,off,len):写入字符串的指定部分

相关API:

String类:toCharArray:将String转换成char[]

注意:

FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

4.8、FileReader 和 FileWriter 应用案例

1、使用 FileReader 从 story.txt 读取内容,并显示

public class FileReader_ {
    public static void main(String[] args) {
    }
    /**
     * 单个字符读取文件
     */
    @Test
    public void readFile01() {
        String filePath = "e:\\story.txt";
        FileReader fileReader = null;
        int data = 0;
        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取 使用read, 单个字符读取
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 字符数组读取文件
     */
    @Test
    public void readFile02() {
        System.out.println("~~~readFile02 ~~~");
        String filePath = "e:\\story.txt";
        FileReader fileReader = null;
        int readLen = 0;
        char[] buf = new char[8];
        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取 使用read(buf), 返回的是实际读取到的字符数
            //如果返回-1, 说明到文件结束
            while ((readLen = fileReader.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

2、使用 FileWriter 将 “风雨之后,定见彩虹” 写入到 note.txt 文件中, 注意细节.

public class FileWriter_ {
    public static void main(String[] args) {
        String filePath = "e:\\note.txt";
        //创建FileWriter对象
        FileWriter fileWriter = null;
        char[] chars = {'a', 'b', 'c'};
        try {
            fileWriter = new FileWriter(filePath);//默认是覆盖写入
//            3) write(int):写入单个字符
            fileWriter.write('H');
//            4) write(char[]):写入指定数组
            fileWriter.write(chars);
//            5) write(char[],off,len):写入指定数组的指定部分
            fileWriter.write("韩顺平教育".toCharArray(), 0, 3);
//            6) write(string):写入整个字符串
            fileWriter.write(" 你好北京~");
            fileWriter.write("风雨之后,定见彩虹");
//            7) write(string,off,len):写入字符串的指定部分
            fileWriter.write("上海天津", 0, 2);
            //在数据量大的情况下,可以使用循环操作.
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //对应FileWriter , 一定要关闭流,或者flush才能真正的把数据写入到文件
            try {
                //fileWriter.flush();
                //关闭文件流,等价 flush() + 关闭
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("程序结束...");
    }
}

五、节点流和处理流

5.1 、基本介绍

1、节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter

2、处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供

更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter

5.2、节点流和处理流一览图

5.3、节点流和处理流的区别和联系

1、节点流是底层流/低级流,直接跟数据源相接。

2、处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。

3、处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]

5.4、处理流的功能主要体现在以下两个方面:

1、性能的提高:主要以增加缓冲的方式来提高输入输出的效率。

2、操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便

5.5、处理流-BufferedReader 和 BufferedWriter

1、BufferedReader 和 BufferedWriter 属于字符流,是按照字符来读取数据的

2、关闭时处理流,只需要关闭外层流即可

3、BufferedReader使用方法:

//创建 bufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String line; //按行读取, 效率高
//说明
//1. bufferedReader.readLine() 是按行读取文件
//2. 当返回 null 时,表示文件读取完毕
//说明: readLine 读取一行内容,但是没有换行
while ((line = bufferedReader.readLine()) != null) {
    System.out.println(line);
}
//关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流
bufferedReader.close();

4、BufferedWriter使用方法:

//1. new FileWriter(filePath, true) 表示以追加的方式写入
//2. new FileWriter(filePath) , 表示以覆盖的方式写入
String filePath = "e:\\ok.txt";
//创建 Buffered Writer
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
bufferedWriter.write("hello, 韩顺平教育!");
bufferedWriter.newLine();//插入一个和系统相关的换行
bufferedWriter.write("hello2, 韩顺平教育!");
bufferedWriter.newLine();
bufferedWriter.write("hello3, 韩顺平教育!");
bufferedWriter.newLine();
//说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
bufferedWriter.close();

5、注意:

1)BufferedReader 和 BufferedWriter 是按照字符操作

2)不要去操作 二进制文件[声音,视频,doc, pdf ], 可能造成文件损坏

5.6、处理流-BufferedInputStream 和 BufferedOutputStream

5.6.1、介绍BufferedInputStream

BufferedInputStream是字节流,在创建BufferedInputStream时,会创建一个内部缓冲区数组

5.6.2、介绍BufferedOutputStream

BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统

字节流可以操作二进制文件

使用:

public class BufferedCopy {
    public static void main(String[] args) {
        String srcFilePath = "e:\\a.java";
        String destFilePath = "e:\\a3.java";
        //创建BufferedOutputStream对象BufferedInputStream对象
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //因为 FileInputStream  是 InputStream 子类
            bis = new BufferedInputStream(new FileInputStream(srcFilePath));
            bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
            //循环的读取文件,并写入到 destFilePath
            byte[] buff = new byte[1024];
            int readLen = 0;
            //当返回 -1 时,就表示文件读取完毕
            while ((readLen = bis.read(buff)) != -1) {
                bos.write(buff, 0, readLen);
            }
            System.out.println("文件拷贝完毕~~~");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流 , 关闭外层的处理流即可,底层会去关闭节点流
            try {
                if(bis != null) {
                    bis.close();
                }
                if(bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

5.7、对象流-ObjectInputStream 和 ObjectOutputStream

1、序列化和反序列化

1)序列化就是在保存数据时,保存数据的值和数据类型

2)反序列化就是在恢复数据时,恢复数据的值和数据类型

3)需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的。

2、该类必须实现如下两个接口之一

-Serializable //这是一个标记接口,没有方法

-Externalizable //该接口有方法需要实现,因此我们一般实现上面的 Serializable接口

5.8、对象流介绍

5.8.1、功能

提供了对基本类型或对象类型的序列化和反序列化的方法

ObjectOutputStream 提供 序列化功能

ObjectInputStream 提供 反序列化功能

5.8.2、注意事项和细节说明

1)读写顺序要一致

2)要求序列化或反序列化对象,需要实现 Serializable

3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性

4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

5)序列化对象时,要求里面属性的类型也需要实现序列化接口

6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

5.9、标准输入输出流介绍

类型

默认设备

System.in 标准输入

InputStream

键盘

System.out 标准输出

PrintStream

显示器

5.10、转换流-InputStreamReader 和 OutputStreamWriter

5.10.1、介绍

1、InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(转换)Reader(字符流)

2、OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)

3、当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流

4、可以在使用时指定编码格弋(比如utf-8, gbk,gb2312, ISO8859-1等)

5.10.2、使用InputStream应用案例

编程将字节流FilelnputStream包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8/gbk 格式),进而在包装成 BufferedReader

public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "e:\\a.txt";
        //解读
        //1. 把 FileInputStream 转成 InputStreamReader
        //2. 指定编码 gbk
        //InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
        //3. 把 InputStreamReader 传入 BufferedReader
        //BufferedReader br = new BufferedReader(isr);

        //将2 和 3 合在一起
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "gbk"));
        //4. 读取
        String s = br.readLine();
        System.out.println("读取内容=" + s);
        //5. 关闭外层流
        br.close();
    }
}

六、打印流-PrintStream 和 PrintWriter

6.1、使用PrintStream

PrintStream out = System.out;
//在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
out.print("john, hello");
//因为 print 底层使用的是 write , 所以我们可以直接调用 write 进行打印/输出
out.write("你好".getBytes());
out.close();
//我们可以去修改打印流输出的位置/设备
//1. 输出修改成到 "e:\\f1.txt"
//2. "hello~" 就会输出到 e:\f1.txt
System.setOut(new PrintStream("e:\\f1.txt"));
System.out.println("hello~");

6.2、使用PrintStream

//PrintWriter printWriter = new PrintWriter(System.out);
PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\f2.txt"));
printWriter.print("hi, 北京你好~~~~");
printWriter.close();//flush + 关闭流, 才会将数据写入到文件..

七、Properties

7.1、看一个需求

7.2、基本介绍

1)专门用于读写配置文件的集合类

配置文件的格式:

键=值

键=值

2)注意:键值对不需要有空格,值不需要用引号一起来。默认类型是String

3) Properties的常见方法

load:加载配置文件的键值对到Properties对象

list:将数据显示到指定设备

getProperty(key):根据键获取值

setProperty(key,value):设置键值对到Properties对象

store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件。如果含有中文,会存储为unicode码

unicode查询工具icon-default.png?t=N7T8http://tool.chinaz.com/tools/unicode.aspx

7.3、应用案例

1.使用Properties类完成对mysql.properties的读取

public class Properties01 {
    public static void main(String[] args) throws IOException {
        //读取mysql.properties 文件,并得到ip, user 和 pwd
        BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));
        String line = "";
        while ((line = br.readLine()) != null) { //循环读取
            String[] split = line.split("=");
            //如果我们要求指定的ip值
            if("ip".equals(split[0])) {
                System.out.println(split[0] + "值是: " + split[1]);
            }
        }
        br.close();
    }
}

2.使用Properties类添加key-val到新文件 mysql2.properties中

public class Properties02 {
    public static void main(String[] args) throws IOException {
        //使用Properties 类来读取mysql.properties 文件
        //1. 创建Properties 对象
        Properties properties = new Properties();
        //2. 加载指定配置文件
        properties.load(new FileReader("src\\mysql.properties"));
        //3. 把k-v显示控制台
        properties.list(System.out);
        //4. 根据key 获取对应的值
        String user = properties.getProperty("user");
        String pwd = properties.getProperty("pwd");
        System.out.println("用户名=" + user);
        System.out.println("密码是=" + pwd);
    }
}

3.使用Properties类完成对mysql2.properties的读取,并修改某个key-val

public class Properties03 {
    public static void main(String[] args) throws IOException {
        //使用Properties 类来创建 配置文件, 修改配置文件内容
        Properties properties = new Properties();
        //创建
        //1.如果该文件没有key 就是创建
        //2.如果该文件有key ,就是修改
        properties.setProperty("charset", "utf8");
        properties.setProperty("user", "汤姆");//注意保存时,是中文的 unicode码值
        properties.setProperty("pwd", "888888");
        //将k-v 存储文件中即可
        properties.store(new FileOutputStream("src\\mysql2.properties"), null);
        System.out.println("保存配置文件成功~");
    }
}
  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值