java IO流

Java IO流

什么是流?

概念:内存和存储设备之间传输数据的通道。

数据借助流传输。

流分类:

  • 按照方向:输入流(将存储设备中的内容读入到内存中)和输出流(将内存中的内容写入到存储设备中)
  • 按照单位:字节流(以字节为单位,可以读写所有数据)和字符流(以字符为单位,只能读取文本数据)
  • 按照功能:节点流(具有实际传输数据的读写功能)和过滤流(在节点流的基础之上增强功能)

字节流

字节流的父类(抽象类):

  • InputStream:字节输入流:提供一些如read(),close()的方法
  • OutputStream:字节输出流:提供一些如write(),close()的方法

文件字节流

  • FileInputStream:文件字节输入流,继承字节输入流
  • FileOutputStream:文件字节输出流,继承字节输入流

文件字节输入流操作:

//创建FileInputStream并且指定文件路径
FileInputStream fis = new FileInputStream("d:\\aa.txt");
int data = 0;
//read返回的int,当等于-1表示读完了,如果是字符返回对应的asc码
//一次读取一个字节
while ((data=fis.read())!=-1){
    System.out.println((char) data);
}
/*
a
b
c

什么为一次读取一个字节的情况

当需要一次读取多个字节

//创建FileInputStream并且指定文件路径
FileInputStream fis = new FileInputStream("d:\\aa.txt");
//一次读取多个个字节
byte[] buf = new byte[3];
//本处read返回实际读取个数,读完返回-1,并且将读取到的存储在buf中
//因为数组大小一次读取三个
System.out.println(fis.read(buf));
System.out.println(new String(buf));
fis.close();
/*
3
abc
*/

//或者

FileInputStream fis = new FileInputStream("d:\\aa.txt");
        byte[] buf = new byte[3];
        int count=0;
        while ((count=fis.read(buf))!=-1){
         System.out.println(new String(buf,0,count));
        }
        fis.close();
/*
abc
def
g

本处只是例子,实际操作时缓冲区数组不需要创建得太小,可以是1024以上

文件字节输出流操作:

//创建文件字节输出流,为true代表文件已经存在时追加,false每次都会覆盖(默认)
FileOutputStream fos=new FileOutputStream("d://aa.txt",false);
fos.write(97);
fos.write('b');
fos.write('c');

//文件中:abc

//要写入字符串:转成byte数组
String s = "helloworld";
fos.write(s.getBytes());

//文件中:abchelloworld

实现复制操作:

FileInputStream fis = new FileInputStream("d:\\aa.txt");
FileOutputStream fos = new FileOutputStream("d:\\bb.txt");
byte[] buf = new byte[1024];
int count=0;
while ((count=fis.read(buf))!=-1){
    fos.write(buf,0,count);
}
fis.close();
fos.close();

字节缓冲流

  • 缓冲流:BufferedInputStream/BufferedOutputStream
  • 继承了过滤流(FilterOutputStream/FilterInputStream),而过滤流又继承了文件字节流
  • 内置了缓存区(8k)
  • 作用:提高IO效率,减少访问磁盘次数;数据存储在缓存区,flush是将缓冲区的内容写入文件中,也可以直接close,后面实现缓冲区的类类似

字节输入缓冲流:

//        创建BufferedInputStream,需要传入一个底层流
        FileInputStream fis = new FileInputStream("d:\\aa.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);
//        读取:类似,但是这个有缓冲区效率更高
        int data = 0;
        while ((data=bis.read())!=-1){
            System.out.print((char)data);
        }
        //当然也可以和文件字节流一样,直接再创建一个缓冲区实现,一模一样但是因为内部缓冲区的存在效率更高
        
//        关闭这一个就行
        bis.close();

//out:abchelloworld

字节输出缓冲流:

FileOutputStream fos = new FileOutputStream("d://bb.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
//转义符如换行等也可以写入也可以
String s = "hello\r\n";
bos.write(s.getBytes());//这是写入了缓冲区,没有写入文件
bos.flush();//需要刷新才能从缓冲区真正写入文件
bos.close();//当然close时自动flush

对象流

  • 对象流:ObjectOutputStream/ObjectInputStream
  • 可以实现写入或者读取对象
  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串的功能,不只是能读写int和byte
  • readObject()从流中读取一个对象;writeObject(Object obj)向流中写入一个对象
  • 使用流传输对象的过程被称为序列化(写入)和反序列化(读取)
  • 继承文件字节流,需要基于其才能创建
  • 序列化和反序列化的对象类都必须实现Serializable接口(该接口本身没有任何方法仅仅标志该类可以序列化),而且其中关联的其他类也要实现该接口
  • 可以在类中自定义生成常量private static final long serialVersionUID ,该常量为序列化版本号用来标识该类,即使是同一个类如果UID不同依旧被认为不是同一个类无法反序列化不同UID的类
  • 使用transient修饰实现,表示该属性不需要序列化(例如:private transient int age )
  • 静态属性不能序列化

序列化:

public class  Student  implements Serializable {}



//main:
FileOutputStream fos = new FileOutputStream("d://aa.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
//        序列化
        Student student = new Student();
        oos.writeObject(student);
//        oos.writeBoolean();写入boolean
//         oos.writeBytes("hellow");//写入字符串
//        其他基本类型也有相应的办法写入
        oos.close();

反序列化:

FileInputStream fis = new FileInputStream("d://aa.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
//读取存入的第一个对象
Student s = (Student)ois.readObject();
ois.close();

序列化、反序列化多个对象时可以使用集合:

//序列化 
FileOutputStream fos = new FileOutputStream("d://aa.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
//        序列化
        Student student = new Student();
        Student student1 = new Student();
        ArrayList<Student> arrayList = new ArrayList<>();
        arrayList.add(student);
        arrayList.add(student1);
        oos.writeObject(arrayList);
        oos.close();

//反序列化
FileInputStream fis = new FileInputStream("d://aa.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ArrayList<Student> arrayList = (ArrayList<Student>) ois.readObject();
        ois.close();

常见字符编码

字符流

问题的引出:

FileInputStream fis = new FileInputStream("d://aa.txt");
int data = 0;
while ((data=fis.read())!=-1){
    System.out.println((char)data);
}
fis.close();
//上述代码当我们读取的文件中为中文时得到乱码。
//原因:我们是运用字节流一个一个字节读取文件,而本处的文件编码方式是utf-8(中文常见的编码方式),每个中文字占3个字节。当一个一个字节读取时出现乱码

这种情况下我们需要字符流

字符流的父类(抽象类):

Reader(字符输入流)和Writer(字符输出流)

只能用于文本文件

文件字符流

  • FileReader和FileWriter
  • 父类是InputStreamReader和OutputStreamWriter,而这两者的父类又是Reader和Writer
  • 采用默认字符编码

FileReader:

FileReader fr = new FileReader("d://aa.txt");
       //单个字符的读取
//        int data = 0;
//        while ((data=fr.read())!=-1){//读取一个字符
//            System.out.println((char)data);
//        }
//创建缓冲区读取
//缓冲区为2字符
        char[] buf = new char[2];
        int count = 0;
        while ((count = fr.read(buf))!=-1){
            System.out.println(new String(buf,0,count));
        }
        fr.close();
/*out:
你好
呀

FileWriter:

FileWriter fw = new FileWriter("d://aa.txt");
fw.write("你好吗");
fw.flush();
fw.close();

字符缓冲流

  • 缓冲流:BufferedReader/BufferedWriter
  • 高效读写
  • 支持输入换行符
  • 可以一次写一行、读一行
  • 可以指定缓冲区大小,也可以默认(8K)
  • 新建需要基础字符流(文件字符流)
  • 继承Reader和Writer

读取:

FileReader fr = new FileReader("d://aa.txt");
       BufferedReader br = new BufferedReader(fr);
//        和上面其他类类似的方法不再重写
//        特有的:读一行,末尾返回null
        String s = null;
        //一行一行的读取
        while ((s=br.readLine())!=null){
            System.out.println(s);
        }
        br.close();
//out:你好呀

写入:

      FileWriter fw = new FileWriter("d:\\aa.txt");
      BufferedWriter bw = new BufferedWriter(fw);
//      写入
        bw.write("好好学习");
//        写入一个换行windows:\r\n linux:\n
        bw.newLine();
        bw.write(",天天向上");
        bw.close();
/*文件:
好好学习
,天天向上

打印流

  • PrintWriter:

    • 支持print()/println(),支持写入后换行
    • 支持数据原样打印
    • 继承Writer类
    • 类似PrintStream,但是PrintWriter只能打印字符流,而PrintStream可以打印字节流
     PrintWriter pw = new PrintWriter("d://aa.txt");
    //      打印并且换行
            pw.println(97);
            pw.println(true);
    //打印
            pw.print("a");
    		pw.print("b");
            pw.close();
    /*文件中:
    97
    true
    ab
    
    

转换流

  • 也叫桥转换流:InputStreamReader/OutputStreamWriter
  • 可以将字节流转换为字符流
  • 可设置字符的编码方式
  • 继承字符流Reader/Writer
  • 创建时需要基本的文件字符流

InputStreamReader:

FileInputStream fis = new FileInputStream("d://aa.txt");
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
int data=0;
//一个一个字符读取
while ((data=isr.read())!=-1){
    System.out.print((char)data);
}
isr.close();

OutputStreamWriter:

FileOutputStream fos = new FileOutputStream("d://aa.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
for(int i=0;i<10;i++){
    osw.write("我爱中国\r\n");
    osw.flush();
}
osw.close();

File类

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

//        分隔符
        System.out.println("路径分割符"+File.pathSeparator);
        System.out.println("名字分割符"+File.separator);

        File file = new File("d://cc.txt");
//        判断文件是否存在
        if(!file.exists()){
//            创建文件
            boolean b = file.createNewFile();
            System.out.println("创建结果:"+b);
        }
       if(file.exists()) {
//           直接删除
           System.out.println("删除结果" + file.delete());
           //使用jvm退出时删除
           file.deleteOnExit();
       }
//       获取文件信息
        System.out.println("绝对路径"+file.getAbsolutePath());
       //看你创建时传入的路径
        System.out.println("获取路径"+file.getPath());
//        获取名称
        System.out.println("获取名称"+file.getName());
//        获取父目录
        System.out.println("获取父目录"+file.getParent());
//        获取文件长度
        System.out.println("获取文件长度"+file.length());
//        文件创建时间
        System.out.println("文件创建时间"+new Date(file.lastModified()).toString());

//        判断文件是否可写
        System.out.println("是否可写"+file.canWrite());
//        是否是文件
        System.out.println("是否是文件"+file.isFile());
//        是否隐藏
        System.out.println("是否隐藏"+file.isHidden());

/*
路径分割符;
名字分割符\
创建结果:true
删除结果true
绝对路径d:\cc.txt
获取路径d:\cc.txt
获取名称cc.txt
获取父目录d:\
获取文件长度0
文件创建时间Thu Jan 01 08:00:00 CST 1970
是否可写false
是否是文件false
是否隐藏false

文件夹操作:

File dir = new File("d://cc/aa");
//        判断文件是否存在
        if(!dir.exists()){
//            创建文件夹:只能创建单集目录
//            boolean b = dir.mkdir();
//            创建多级目录
            boolean b = dir.mkdirs();
            System.out.println("创建结果:"+b);
        }
       if(dir.exists()) {
//           直接删除:最下层且必须为空目录
           System.out.println("删除结果" + dir.delete());
           //使用jvm退出时删除,休眠结束后删除
           dir.deleteOnExit();
           Thread.sleep(5000);
       }
//       获取文件信息
        System.out.println("绝对路径"+dir.getAbsolutePath());
       //看你创建时传入的路径
        System.out.println("获取路径"+dir.getPath());
//        获取名称
        System.out.println("获取名称"+dir.getName());
//        获取父目录
        System.out.println("获取父目录"+dir.getParent());
//        文件创建时间
        System.out.println("文件创建时间"+new Date(dir.lastModified()).toString());


//        判断是否是文件夹
        System.out.println("是否可写"+dir.isDirectory());
//        是否隐藏
        System.out.println("是否隐藏"+dir.isHidden());
//        遍历文件夹
        String[] file = dir.list();

FileFilter接口

  • public interface FileFIlter

    • boolean accept(File pathname)
  • 当调用File类的listFiles()方法时,支持传入一个实现了FileFilter接口的实现类对文件进行过滤,只有满足条件的文件才能出现在listFiles()返回值中

  • 实现过滤

File dir = new File("d://cc/aa");
File[] files= dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                //如果名字以.jpg结尾返回,否则不返回
                if(pathname.getName().endsWith(".jpg")){
                    return  true;
                }
                else{
                    return  false;
                }
            }
        });

递归遍历文件夹(递归删除文件夹:先把文件内删空再删除文件夹):

public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    listDir(new File("d://aa"));
}

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.getAbsolutePath());
            }
        }
    }
}

Prorerties

  • 属性集合

  • 特点:

  1. 存储属性名和属性值
  2. 属性名和属性值都是字符串类型
  3. 没有泛型
  4. 继承Hashtable集合,具体看集合那一章笔记
  5. 和流有关
//        创建集合
        Properties properties = new Properties();
//        添加数据
        properties.setProperty("username","zhangsan");
        properties.setProperty("age","20");
        System.out.println(properties.toString());

        //遍历
//        1.keySet遍历
//        properties.keySet();
//         2.entrySet遍历
//        3.stringPropertyNames变量
        Set<String> set = properties.stringPropertyNames();
        for (String s : set) {
            System.out.println(s+":"+properties.getProperty(s));
        }
//        和流有关的办法
//        list方法
          PrintWriter pw = new PrintWriter("d://aa.txt");
        //将properties写入该文件
            properties.list(pw);
            pw.close();
 //store方法保存写入该文件
        FileOutputStream fos = new FileOutputStream("d://aa.txt");
        properties.store(fos,"这是注释");
        fos.close();
/*
{age=20, username=zhangsan}
age:20
username:zhangsan
Properties properties1 = new Properties();
FileInputStream fis = new FileInputStream("d://aa.txt");
properties1.load(fis);
fis.close();
System.out.println(properties1.toString());
//{age=20, username=zhangsan}

热门相关:骑士归来   学霸女神超给力   法医王妃不好当!   豪门重生盛世闲女   战神