【java】IO流

一、流的概念

是内存与存储设备之间传输数据的通道。

二、流的分类

1. 按照方向分:

(1)输入流:将<存储设备>中的内容读入到<内存>中

(2)输出流:将<内存>中的内容写入到<存储设备>中

2. 按处理单位分:

(1)字节流:以字节为单位,可以读写所有数据

(2)字符流:以字符为单位,只能读写文本数据

3. 按功能分:

(1)节点流:具有实际传输数据的读写功能。

(2)过滤流:在节点流的基础之上增强功能。

三、字节流

3.1 字节流

字节流的父类(抽象类):InputStream:字节输入流(read)、OutputStream:字节输出流(write)

文件字节流:FileInputStream、FileOutputStream

案例:

//单个字节读取
public static void main(String[] args) throws Exception {//这里为了代码可读性,异常暂时抛出
    //1. 创建FileInputStream,并指定文件路径
    FileInputStream fis = new FileInputStream("d:\\aa.txt");
    //2. 读取文件 data对象用来保存我们读取的字节
    int data = 0;
    //如果都读取完了,会返回-1 ,不过这个read方法读取比较慢,是一个字节一个字节的读
    while ((data=fis.read())!=-1){
    System.out.println((char)data);//假设txt文件中存的是abcdefg ,那么每次会输出一个
    }
    //3. 关闭
    fis.close();
}

//多个字节读取
public static void main(String[] args)  throws Exception{
    //1. 创建FileInputStream,并指定文件路径
    FileInputStream fis = new FileInputStream("d:\\aa.txt");
    //2. 创建一个数组用来存放读取到的字节,这里暂定长度为3
    byte[] buf = new byte[3];
    //3. 读取文件 count就是我们实际读取的字节数
    int count = 0;
    //如果都读取完了,会返回-1 ,这个read方法,是按照上面数组的长度,即三个三个的读
    while ((count=fis.read(buf))!=-1){
    System.out.println(new String(buf,0,count));//假设txt文件中存的是abcdefg ,那么每次会输出三个
    }
    //4. 关闭
    fis.close();
}

//输出流写入
public static void main(String[] args) throws Exception{
    //1. 创建文件字节输出流对象 ,没有此文件会创建,有此文件调用下面的write方法的时候会覆盖txt里的内容。
    FileOutputStream fos = new FileOutputStream("d:\\bb.txt");
    //可以通过加参数 true 来实现非覆盖而是追加的效果
    //FileOutputStream fos = new FileOutputStream("d:\\bb.txt",true);
    //2. 写入文件.
    String str = "helloword";
    //str.getBytes()意思为获取这个字符串所对应的字符数组
    fos.write(str.getBytes());
    //3. 关闭
    fos.close();
}

//使用文件字节流(输入流和输出流)实现文件的复制
//注意:文件字节流不带缓冲效率会比较低
public static void main(String[] args) throws Exception{
    //1. 创建流
    //1.1 文件字节输入流 ,如果没有会报错java.io.FileNotFoundException: d:\001.jpg (系统找不到指定的文件。)
    FileInputStream fis = new FileInputStream("d:\\001.jpg");
    //1.2 文件字节输出流
    FileOutputStream fos = new FileOutputStream("d:\\002.jpg");
    //2. 一边读,一边写
    byte[] buf = new byte[1024];
    int count =0;
    while((count=fis.read(buf))!=-1){
    fos.write(buf,0,count);
    }
    //3. 关闭
    fis.close();
    fos.close();
}

3.2 字节缓冲流

缓冲流:BufferedInputStream、BufferedOutputStream

作用:

(1)提高IO效率,减少访问磁盘的次数

(2)数据存储在缓存区中,flush是将缓存区的内容写入文件中,也可以直接close.

//输入缓冲流
public static void main(String[] args) throws Exception{
    //1. 创建文件输入流
    FileInputStream fis = new FileInputStream("d:\\aa.txt");
    //2. 创建缓冲流,来增强文件输入流
    BufferedInputStream bis = new BufferedInputStream(fis);
    //3. 读取
    int data = 0;
    //注意:这里read并非一个个的读,而是一次读8k到缓冲区,即BufferedInputStream源码中的private static int DEFAULT_BUFFER_SIZE = 8192;
    while ((data=bis.read())!=-1){
        System.out.println((char)data);
    }

    //当然也可以自己定义缓冲区
    //byte[] buf = new byte[1024];
    //int count =0;
    //while ((count=bis.read(buf))!=-1){
        //System.out.println(new String(buf,0,count));
    //}

    //4. 关闭 只关闭缓冲流即可,它内部会把文件输入流也关闭了.
    bis.close();
}


//输出缓冲流
public static void main(String[] args) throws Exception{
    //1. 创建字节输出流
    FileOutputStream fos = new FileOutputStream("d:\\cc.txt");
    //2. 创建字节输出缓冲流
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    //3. 写入文件
    for(int i=0;i<10;i++){
    bos.write("helloworld".getBytes());//只要不超过8k都会写入到8k缓冲区,此时文件中实际上是没有内容的
    bos.flush();//只有刷新才会将数据刷新到硬盘
    }
    //4. 关闭(内部也会调用flush方法)
    bos.close();
}

3.3 对象流+(反)序列化

对象流:ObjectOutputStream、ObjectInputStream 使用流传输对象的过程称为序列化/反序列化。

作用:

(1)增强了缓冲区功能。

(2)增强了读写8中基本数据类型和字符串功能。

(3)增强了读写对象的功能 readObject() 从流中读取一个对象  writeObject(Object obj) 向流中写入一个对象。

要求:

(1)序列化类必须要实现Serializable接口

(2)序列化类中对象属性也要求实现Serializable接口

(3)序列化版本号ID(serialVersionUID),保证序列化的类和反序列化的类是同一个类

(4)使用transient(瞬间的)修饰属性,这个属性不能序列化

(5)静态属性也不能序列化

(6)序列化多个对象 即下面的例子中可以创建多个对象,之后将多个对象放入一个list中,当然获取的时候返回的也是一个List即可

案例:

//使用ObjectOutputStream实现对象的序列化 
public static void main(String[] args) throws Exception{
    //1. 创建文件输出流
    FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
    //2. 创建文件输入流
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    //3. 创建一个对象并赋值
    //注意:这里要求必须要对象实现序列化,否则会报错java.io.NotSerializableException: com.company.Student
    Student stu = new Student();
    stu.setAge(21);
    stu.setName("张三");
    //4. 写入操作(序列化)
    oos.writeObject(stu);
    //5. 关闭
    oos.close();
}

//这里要求对象必须实现序列化
public class Student implements Serializable {
    private String name;
    private int age;
    //private transient int age;//被transient修饰的不能序列化,即序列化后再反序列化是没值的
    private static final long serialVersionUID = -8778349856468359639L;
    //省略setter、getter、toString方法
}

//使用ObjectInputStream实现反序列化(读取重构成对象)
public static void main(String[] args) throws Exception{
    //1. 创建文件输入流
    FileInputStream fis = new FileInputStream("d:\\stu.bin");
    //2. 创建对象流
    ObjectInputStream ois = new ObjectInputStream(fis);
    //3. 读取文件(反序列化)
    Student stu = (Student)ois.readObject();
    //4. 关闭
    ois.close();
    System.out.println(stu.toString());//结果:  Student{name='张三', age=21}
}

四、编码方式

常见编码字符

1. ISO-8859-1 收录除了ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号

2. UTF-8  针对Unicode码表的可变长度字符编码

3. GB2312 简体中文

4. GBK  简体中文、扩充

5. BIG5  台湾,简体中文

当编码方式和解码方式不一致时,会出现乱码。

五、字符流

5.1 字符流

涉及到汉字的一般用字符流 FileReader、FileWriter

字符流的父类(抽象类):Reader:字符输入流  read()、Writer:字符输出流  write()

案例:

//FileReader读取文件
public static void main(String[] args) throws Exception{
    //1. 创建FileReader 文件字符输入流
    FileReader fr = new FileReader("d:\\hello.txt");
    //2. 读取 (单个字符读取)
    int data = 0;
    while ((data=fr.read())!=-1){
        System.out.println((char)data);
    }
    //3. 关闭
    fr.close();
}

//FileWriter写入文件
public static void main(String[] args) throws Exception{
    //1. 创建FileWriter对象
    FileWriter fw = new FileWriter("d:\\write.txt");
    //2. 写入
    for(int i=0;i<10;i++){
        fw.write("你好");
        fw.flush();
    }
    //3. 关闭
    fw.close();
}

//使用FileWriter和FileReader复制文件
//注意:只能复制文本文件,不能复制图片和二进制文件(声音/视频等) 字节流可以复制任何文件
public static void main(String[] args) throws Exception{
    //1. 创建FileWriter和FileReader
    FileReader fr = new FileReader("d:\\write.txt");
    FileWriter fw = new FileWriter("d:\\write2.txt");
    //2. 读写
    int data=0;
    while ((data=fr.read())!= -1){
        fw.write(data);
        fw.flush();
    }
    //3. 关闭
    fr.close();
    fw.close();
}

5.2 字符缓冲流

缓冲流:BufferedReader、BufferedWriter

作用:

(1)高效读写(缓冲区)

(2)支持输入换行符

(3)可一次读/写一行

//使用字符缓冲流读取文件 (单个字符读+一行一行读)
public static void main(String[] args) throws Exception{
    //1. 创建缓冲流
    FileReader fr = new FileReader("d:\\write.txt");
    BufferedReader br = new BufferedReader(fr);
    //2. 读取
    //2.1 第一种
    //char[] buf = new char[1024];
    //int count = 0;
    //while ((count=br.read())!=-1){
    //System.out.println(new String(buf,0,count));
    //}
    //2.2 第二种 一行一行读
    String line = null;
    while ((line=br.readLine())!=null){
        System.out.println(line);
    }
    //3. 关闭
    br.close();
}

//使用字符缓冲流写入文件
public static void main(String[] args) throws Exception{
    //1. 创建缓冲流
    FileWriter fw = new FileWriter("d:\\buffer.txt");
    BufferedWriter bw = new BufferedWriter(fw);
    //2. 写入
    for(int i=0;i<10;i++){
        bw.write("你好");
        bw.newLine();//写入一个换行符 windows:\r\n   linux:\n
        bw.flush();
    }
    //3. 关闭
    bw.close();
}

六、打印流

PrintWriter:

作用:

(1)封装了print() / println() 方法,支持写入后换行

(2)支持数据原样打印

//PrintWriter的使用
public static void main(String[] args) throws Exception{
    //1. 创建打印流
    PrintWriter pw = new PrintWriter("");
    //2. 打印
    pw.println(97);//换行 打印到文件之后不会变成a,仍然是97
    pw.print(true);//不换行 打印到文件里是true字符串
    pw.println('a');//打印到文件里是a
    //3. 关闭
    pw.close();
}

七、转换流

又称为桥转换流:InputStreamReader、OutputStreamWriter

(1)可将字节流转换为字符流

(2)可设置字符的编码方式

案例:

//使用InputStreamReader读取文件,指定使用的编码
public static void main(String[] args) throws Exception{
    //1. 创建InputStreamReader对象
    FileInputStream fis = new FileInputStream("d:\\write.txt");
    InputStreamReader isr = new InputStreamReader(fis,"utf-8");//gbk
    //2. 读取文件
    int data=0;
    while ((data=isr.read())!=-1){
        System.out.println((char)data);
    }
    //3. 关闭
    isr.close();
}

//使用OutputStreamWriter写入文件,指定使用的编码
public static void main(String[] args) throws Exception{
    //1. 创建OutputStreamWriter对象
    FileOutputStream fos = new FileOutputStream("d:\\info.txt");
    OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
    //2. 写入文件
    for(int i=0;i<10;i++){
        osw.write("你好");
        osw.flush();
    }
    //3. 关闭
    osw.close();
}

八、File对象

8.1 概念和方法

概念:代表物理盘符中的一个文件或者文件夹

方法:

(1)createNewFile()   # 创建一个新文件

(2)mkdir()    # 创建一个新目录

(3)delete()    # 删除文件或空目录

(4)exists()    # 判断File对象所代表的对象是否存在

(5)getAbsolutePath() # 获取文件的绝对路径

(6)getName()   # 取得文件的名字

(7)getParent()   # 获取文件/目录所在的父目录

(8)isDirectory()  # 是否是目录

(9)isFile()    # 是否是文件

(10)length()   # 获得文件的长度

(11)listFiles()   # 列出目录中的所有内容

(12)renameTo()   # 修改文件名为

8.2 文件操作

8.2.1 分隔符

路径分隔符+名称分隔符

案例:

//分隔符
public static void main(String[] args) throws Exception{
    separator();
}

public static void separator(){
    //路径分隔符,结果为一个分号 ;  (还记得配置环境变量中的path里都是用分号隔开的嘛)
    System.out.println(File.pathSeparator); 
    //名称分隔符 结果为一个斜线 \  (windows下电脑文件的目录)
    System.out.println(File.separator); 
}

8.2.2 文件操作

创建文件+删除文件+获取文件信息+判断

案例:

//文件操作
public static void main(String[] args) throws Exception{
    //1. 创建文件
    File file = new File("d:\\file.txt");
    //判断文件是否存在
    if(!file.exists()){
        //判断文件是否创建成功 如果文件没有返回true: 成功  如果文件已经存在返回false
        boolean b = file.createNewFile();
    }
    //2. 删除文件 删除成功true
    boolean result = file.delete();
    // 使用jvm退出时删除文件
    //file.deleteOnExit();
    //加5s延时是为了看到效果
    //Thread.sleep(5000);
    //3. 获取文件信息 绝对路径 getPath为相对路径,即上面写什么就是什么
    String url = file.getAbsolutePath();//结果为d:\file.txt
    //获取名称
    String name = file.getName();//结果为:file.txt
    //获取父目录
    String parentsource = file.getParent();//结果为:d:\
    //获取文件的长度  字节数
    long length = file.length();
    //获取文件的创建时间
    String data = new Date(file.lastModified()).toLocaleString();//结果为年月日时分秒的结构
    //4.判断
    //判断是否可写
    boolean iswrite = file.canWrite();
    //判断是否是文件
    boolean isFile = file.isFile();
    //判断是否是隐藏的
    boolean ishide = file.isHidden();
}

8.2.3 文件夹操作

创建+删除+获取信息+判断+遍历

案例:

//文件夹操作
public static void main(String[] args) throws Exception{
    //1. 创建文件夹
    File dir = new File("d:\\aa\\bb\\cc");
    //判断文件夹是否存在
    if(!dir.exists()){
        //创建文件夹  mkdir:创建单级目录 mkdirs:创建多级目录
        boolean b = dir.mkdirs();
    }
    //2. 删除文件夹 这个删除是只删除最底层的,比如上面的cc目录,并且要求里面是空的
    boolean result = dir.delete();
    // 使用jvm退出时删除文件夹
    //dir.deleteOnExit();
    //加5s延时是为了看到效果
    //Thread.sleep(5000);
    //3. 获取文件夹信息 绝对路径 getPath为相对路径,即上面写什么就是什么
    String url = dir.getAbsolutePath();//结果为d:\aa\bb\cc
    // 获取名称
    String name = dir.getName();//结果为:cc
    //获取父目录
    String parentsource = dir.getParent();//结果为:d:\aa\bb
    //获取文件的创建时间
    String data = new Date(dir.lastModified()).toLocaleString();//结果为年月日时分秒的结构
    //4.判断
    //判断是否是文件夹
    boolean isdirectory = dir.isDirectory();
    //判断是否是隐藏的
    boolean isFile = dir.isHidden();
    //5. 遍历文件夹
    File dir2 = new File("d:\\图片");
    String[]  files = dir2.list();//返回的是字符串数组
    //File[] files2 = dir2.listFiles();//返回的是file数组
    for(String str:files){
        System.out.println(str);
    }
}

8.3 FileFilter接口

public interface FileFilter     boolean accept(File pathname)

当调用File类中的listFiles()方法时,支持传入FileFilter接口接口实现类,对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中.

案例:

public static void main(String[] args) throws Exception{
    File dir = new File("d:\\图片");
    File[] files = dir.listFiles(new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            //只筛选.jpg结尾的文件
            if(pathname.getName().endsWith(".jpg")){
                return true;
            }
            return false;
        }
    });
    for(File file:files){
        System.out.println(file.getName());
    }
}

8.4 递归遍历和递归删除

递归遍历文件夹+递归删除文件夹

public static void main(String[] args) throws Exception{
    //递归遍历文件夹
    listDir(new File("d:\\myfiles"));
    //递归删除文件夹
    deleteDir(new File("d:\\myfiles"));
}
//递归遍历文件夹
public static void listDir(File dir){
    File[] files = dir.listFiles();
    if(files!=null&&files.length>0){
        for(File file:files){
            if(file.isDirectory()){
                listDir(file);//这用到了递归
            }else {
                System.out.println(file.getAbsoluteFile());
            }
        }
    }
}
//递归删除文件夹
public static void deleteDir(File dir){
    File[] files = dir.listFiles();
    if(files!=null&&files.length>0){
        for(File file:files){
            if(file.isDirectory()){
                deleteDir(file);//递归
            }else{
                file.delete();
            }
        }
    }
    dir.delete();
}

8.5 Properties

Properties:属性集合

特点:

(1)存储属性名和属性值

(2)属性名和属性值都是字符串类型

(3)没有泛型

(4)和流有关

案例:

 public static void main(String[] args) throws Exception{
     //1. 创建一个集合
     Properties properties = new Properties();
     //2. 添加数据
     properties.setProperty("username","zhangsan");
     properties.setProperty("age","20");
     System.out.println(properties.toString());//结果为:{age=20, username=zhangsan}
     //3. 遍历
     //3.1 keySet
     //3.2 entrySet
     //3.3 stringPropertiesNames()
     Set<String> pronames = properties.stringPropertyNames();
     for(String pro:pronames){
         System.out.println(pro+"---"+properties.getProperty(pro));//结果:age---20  username---zhangsan
     }
     //4. 和流有关的方法
     //-----------list------------
     PrintWriter pw = new PrintWriter("d:\\print.txt");
     properties.list(pw); //之后print.txt文件中就有两条数据了 age=20  username=zhangsan
     pw.close();
     //-----------store保存-----------
     FileOutputStream fos = new FileOutputStream("d:\\print.properties");
     properties.store(fos,"注释");
     fos.close();
     //-----------load加载------------
     Properties properties2 = new Properties();
     FileInputStream fis = new FileInputStream("d:\\store.properties");
     properties2.load(fis);
     fis.close();
 }

 

 

参考:

1. 千锋教育视频

持续更新!!!

posted @ 2020-07-31 10:26  夏夜凉凉  阅读(180)  评论(0编辑  收藏  举报