java流

IO流

  • IO流用来处理设备之间的数据传输,传输是通过流的方式
  • Java用于操作流的对象都在java.io包中
  • 流就是指一连串流动的字符,以先进先出的方式发送信息的通道。

流的方式

按照流的方向划分
  • 输入流:将外部数据源的数据转换成流,程序通过读取流中的数据,完成对数据源读取的访问
  • 输出流:将流中的数据转换到对应的数据源中,程序通过向流中写入数据,完成对数据源写入
按照类型划分
  • 字节流:以字节为单位(8位),可以访问所有文件

  • 字符流:以字符为单位(16位Unicode),只能访问文本文件

  • 输出流
    比如我们经常使用的 System.out.println("cocci"); 就是将字符串输出到控制台中,或者说输出到屏幕中,这里的屏幕就是输出设备,由程序将cocci通过流输出到目的地。
    输出设备除了屏幕,还有打印机、文件等。

  • 输入流
    比如使用键盘接收数据 Scanner sc = new Scanner(System.in); 这里的System.in就是输入流,程序从数据源这里指键盘去读取数据通过流输入到程序当中。
    输入设备除了键盘,还有扫描仪、文件等。

File类

文件和目录路径名的抽象表示形式,表示磁盘上的文件或目录
文件:可认为是相关记录或放在一起的数据的集合

构造方法

示例:以下三种方式等价,各有不同的使用场景

//Windows中路径分隔可使用/或者\\
File file1 = new File("d:\\java\\a.txt");
File file2 = new File("d:\\java","a.txt");
File file3 = new File(new File("d:\\"),"java\\a.txt");
常用方法

在这里插入图片描述

注意事项

  • delete()方法在删除目录时如果其内有内容则无法删除,需要先清空目录下的内容,再删除目录本身
  • isDirectory()和isFile()方法在判断是否为文件或者目录时,如果文件或目录不存在则返回false
  • createNewFile()方法在创建文件时,如果文件所在的目录不存在则创建失败并抛出异常
  • String[] list()和 File[] listFiles() 都是返回对象包含的所有的文件和目录,返回类型不同
文件与目录的相关操作
public static void main(String[] args) {
    
    /*目录的创建与删除*/
    File file=new File("d:\\test\\java");
    if(file.exists()){
        System.out.println("目录存在,删除目录");
        file.delete(); //只会删除一级目录,即java
    }else{
        boolean b=file.mkdirs();  //创建多级目录
        System.out.println("创建文件目录结果:" + b);
    }
    /*文件的创建与删除*/
    File file2=new File("d:\\test\\a.txt");
    if(file2.exists()){
        System.out.println("文件存在,删除文件");
        file2.delete();
    }else{
        try {
            file2.createNewFile(); //创建文件
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("创建文件");
    }
    //重命名,把a.txt重命名为b.txt
    //file2.renameTo(new File("d:\\test\\b.txt"));
    //把b.txt剪切到java目录下并重命名为c.txt
    file2.renameTo(new File("d:\\test\\java\\c.txt"));
}

获取File对象的所有子文件和目录

public class TestFile {
    public static void main(String[] args) {
        //获取磁盘的所有根目录
       File[] files =File.listRoots();
       for(int i=0;i<files.length;i++){
           System.out.println(files[i].getPath());
           //输出的是  C:\  D:\
       }    
       TestFile tf = new TestFile();
       //打印Silly目录下的所有子目录和文件
       File file=new File("d:\\Silly");
       tf.printFile(file,"");       
    }   
    /**
     * 打印指定目录下的所有子文件和子目录
     * @param file
     * @param str
     */
    public void printFile(File file,String str){
        System.out.println(str + file.getName());
        if(file.isDirectory()){
            File[] files=file.listFiles();
            for(int i=0;i<files.length;i++){
                //递归调用
                printFile(files[i], str+"\t");     
            }               
        }       
    }
}

字节流

字节输入流

InputStream,此抽象类是表示字节输入流的所有类的超类,其主要子类如下
在这里插入图片描述

字节输出流

OutputStream,此抽象类是字节输出流的所有类的超类,其主要子类如下
在这里插入图片描述

文件输入输出流
FileInputStream

从文件系统中的某个文件中获得输入字节
用于读取诸如图像数据之类的原始字节流

构造方法

在这里插入图片描述

主要方法

read方法不带参数的返回值为读取的单个字节值,带参数的返回值表示读取的字节长度。如果返回值为-1,则表示已经达到文件末尾!
在这里插入图片描述

FileOutputStream
构造方法

在这里插入图片描述

主要方法

在这里插入图片描述

演示Demo
public class IOTest {
    
    public static void main(String[] args) {
        OutputStream fos = null;
        InputStream fis = null;
        try {
            /********* 输出流写文件 ***********/
            fos=new FileOutputStream("d:\\silly.txt");
            String str="最好的我们隔了一整个青春";
            byte[] words=str.getBytes(); //把字符串编码成字节序列
            //写入操作
            fos.write(words, 0, words.length);
            System.out.println("写入成功!");
            
            /********* 输入流读文件 ***********/
            fis = new FileInputStream("d:\\silly.txt");
            StringBuilder sb = new StringBuilder();
            byte[] buf = new byte[1024]; //字节数组缓存数据
            int n = 0; //记录读取的字节长度
            //循环读取数据
            while((n = fis.read(buf)) != -1){
                //这里使用三个参数的构造方法,因为最后一次读取的长度可能达不到buf数组的长度
                //所以根据实际读取的长度n去构造对象更合理
                sb.append(new String(buf, 0, n));
                buf = new byte[1024]; //重新初始化,避免数据重复
            }
            System.out.println(sb.toString());
            
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                //释放资源
                if(fos != null) fos.close();
                if(fis != null) fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
 public static void main(String[] args) {
        //将d盘的图片复制到桌面
         InputStream is = null;  
         OutputStream os = null;
         try {
           //实例化输入输出流对象
            is = new FileInputStream("d:\\girl.jpg");
            os = new FileOutputStream("C:\\Users\\ruoxiyuan\\Desktop\\mm.jpg");
            //定义一个2048字节的缓存
             byte[] buffer=new byte[2048];
             int len= 0; //读取的字节长度
             while((len = is.read(buffer)) != -1){
                 //最后一次读取的长度len不一定能达到buffer数组的长度,也就是空间有可能富余
                 //如果直接使用write(buffer)方法可能导致写入更多的字节,新文件会稍大
                 os.write(buffer, 0, len);
             }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                //释放资源
                if(is != null) is.close();
                if(os != null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

字符流

字符输入流

Reader,此抽象类是表示字符输入流的所有类的超类,其主要子类如下
在这里插入图片描述

字符输出流

Writer,此抽象类是表示字符输出流的所有类的超类,其主要子类如下
在这里插入图片描述

字节字符转换流

InputStreamReader:是字节流通向字符流的桥梁,它使用指定的 charset 读取字节并将其解码为字符。
OutputStreamWriter:是字符流通向字节流的桥梁,它使用指定的 charset 将写入其中的字符编码成字节。
其使用的字符集可以由构造方法指定,或者使用平台默认的字符集。

FileReader

用来读取字符文件的便捷类,使用默认字符集进行编码,InputStreamReader的子类

构造方法

在这里插入图片描述

常用方法

在这里插入图片描述

FileWriter

用来写入字符文件的便捷类,使用默认字符集进行编码,OutputStreamWriter的子类

构造方法

如果使用new FileWriter(file),已有文件内容此时会被清空,设置第二个参数为true表示追加内容
在这里插入图片描述

常用方法

在这里插入图片描述

演示Demo
public class IOTest {
    public static void main(String[] args) {
        try {
            /*****写文件*****/
            FileWriter writer = new FileWriter("d:\\silly.txt");
            String str = "成功的人只会去做他们该做的事情,只会面对他们的困难,不会有抱怨,"
                    + "更不会有羡慕,因为他们心中有目标,理想,动力以及那颗沉淀的心";
            writer.write(str);
            writer.flush(); //刷新缓冲区
            
            /*****读文件*****/
            FileReader reader = new FileReader("d:\\silly.txt");
            char[] buffer = new char[1024];//定义缓冲区
            int len = 0;
            while((len = reader.read(buffer)) != -1){
                String res = new String(buffer, 0, len);
                System.out.println(res);
            }
            writer.close();
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

缓冲流

使用缓冲流可以提高读写速度,注意缓冲流在调用write方法写入数据时,是写入的缓冲区,如果缓冲区满了自动执行写操作,缓冲区不满则需要执行flush方法强制写入到输出设备,调用close方法也会强制写入

字节缓冲流

缓冲输入流BufferedInputStream,缓冲输出BufferedOutputStream
只是对字节流进行了包装,使用方式和字节流基本一致
构造方法:

public BufferedInputStream(InputStream in)
public BufferedOutputStream(OutputStream out)
字符缓冲流
  • 缓冲输入流BufferedReader
    构造方法:public BufferedReader(Reader in)
    特殊方法:String readLine() 读取一个文本行

  • 缓冲输出流BufferedWriter
    构造方法:public BufferedWriter(Writer out)
    特殊方法:void newLine() 写入一个行分隔符

  • 演示Demo

public class IOTest {
    
    public static void main(String[] args) {
        try {
            /*****写文件*****/
            FileWriter writer = new FileWriter("d:\\silly.txt");
            BufferedWriter bw = new BufferedWriter(writer);
            bw.write("书山有路勤为径");
            bw.newLine(); //写入换行符(根据平台写入对应的换行符)
            bw.write("学海无涯苦作舟");
            bw.newLine();
            //windows下使用\r\n也能换行
            bw.write("世间安得两全法" + "\r\n");
            bw.write("不负如来不负卿");
            bw.flush(); //必须刷新缓冲区
            
            /*****读文件*****/
            String record = null; //存储文件的内容
            int count = 0; //记录行数
            FileReader reader = new FileReader("d:\\silly.txt");
            BufferedReader br = new BufferedReader(reader);
            //每次读取一整行数据,返回值为空时说明读取到文件末尾
            while((record = br.readLine()) != null){
                count++;
                System.out.println("当前行数"+count+":"+record);
            }
            /**输出结果
            当前行数1:书山有路勤为径
            当前行数2:学海无涯苦作舟
            当前行数3:世间安得两全法
            当前行数4:不负如来不负卿
            */
            bw.close();
            br.close();
            writer.close();
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

对象序列化与反序列化

  • 序列化:把Java对象转换为字节序列的过程
  • 反序列化:把字节序列恢复为Java对象的过程

只有实现了Serializable接口的类的对象才能被序列化

序列化用途

把对象的字节序列永久保存在硬盘上,通常放在一个文件中
在网络上传送对象的字节序列
相关类

  • 对象输入流类:ObjectInPutStream
  • 对象输出流类:ObjectOutPutStream
序列化步骤

创建一个对象输出流:ObjectOutPutStream out = new ObjectOutPutStream(OutPutStream out);
调用方法对对象进行序列化 out.writeObject(Object obj); 把对象序列化,得到字节序列写入流中
刷新缓冲并关闭流 out.flush(); out.close();
反序列化步骤
创建一个对象输入流:ObjectInPutStream in = new ObjectInPutStream(InPutStream in);
调用方法 in.readObject(); 读取字符序列,把参数反序列化成对象,返回该对象
关闭流 in.close();

演示Demo
  • 定义一个学生类实现Serializable接口
public class Student implements Serializable{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}
  • 实现对象序列化与反序列化
public class IOTest {
    
    public void save(Student stu){
        OutputStream os=null;
        try {
            os = new FileOutputStream("d:\\stu.dat");
            ObjectOutputStream oos = new ObjectOutputStream(os);
            oos.writeObject(stu);
            //写入其他类型数据
            oos.writeBoolean(true);
            oos.flush();
            oos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public Student read(){
        InputStream is=null;
        Student stu=null;
        try {
            is = new FileInputStream("d:\\stu.dat");
            ObjectInputStream ois = new ObjectInputStream(is);
            stu = (Student)ois.readObject();
            //注意读取顺序要和写入顺序保持一致
            System.out.println(ois.readBoolean());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally{
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return stu;
    }
    
    public static void main(String[] args) {
        Student stu = new Student("小小", 18);
        IOTest test = new IOTest();
        test.save(stu);
        Student res = test.read();
        System.out.println(res);
        //true
        //Student [name=小小, age=18]
    }
}
Serializable接口
  • 实现该接口会按默认方式进行序列化和反序列化

  • 默认方式序列化
    这种序列化方式仅对非transient的实例变量进行序列化
    不会序列化对象的transient的实例变量,也不会序列化静态变量

  • 默认方式反序列化
    如果内存中对象所属的类还没有被加载,那么会先加载并初始化这个类,如果classpath中不存在该类文件,那么抛出ClassNotFoundException;
    在反序列化时不会调用类的任何构造方法
    如果希望控制类的序列化方式添加如下方法

private void writeObject(ObjectOutputStream out) throws IOException
private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException

可序列化类添加该方法后进行可序列化操作会执行该方法,否则按默认方式执行。在以上方法中可以先调用默认的defaultWriteObject()read方法

序列化说明

对于包含敏感信息的对象,可以先加密后再序列化,反序列化时需要解密
默认序列化方式会序列化整个对象图,需要递归遍历对象图,如果对象图复杂,递归遍历需要消耗大量空间和时间,图内部数据结构为双向列表
实际应用中,如果对某些成员变量改为transient类型,可以节省空间和时间,提高可序列化的性能

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值