Java之IO流

IO流

FILE类

FILE类的一个对象代表一个文件或者一个文件目录

路径分隔符

  • 路径中的每级目录之间用一个路径分隔符隔开
  • 路径分隔符和系统有关:
    • windows和DOS系统默认使用’\’
    • UNIX和URL使用’/’
  • Java支持跨平台运行,因此路径分隔符要慎用
  • 为了解决这个隐患,File类提供了一个常量File.seperator

构造器

@Test
public void test1()
{
    // 构造器1
    File file = new File("Hello.txt");
    File file2 = new File("e:\\STUDY\\java");
    // which equals to
    File file3 = new File("e:"+File.separator+"STUDY"+File.separator+"java");
    
    File file4 = new File("e:\\STUDY\\java","day01.md");
    System.out.println(file4);
	
    File file5 = new File(file3,"day01.md");
    System.out.println(file5);
	
    //e:\STUDY\java\day01.md
    //e:\STUDY\java\day01.md
}

常用功能

获取相关信息
@Test
public void test2()
{
    File file = new File("hello.txt");
    System.out.println(file.getAbsoluteFile());
    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()));
//E:\Java\code\JavaSE\senior_java\hello.txt
//hello.txt
//hello.txt
//null 		-- 	只有构造器中是绝对路径的才能看到父目录
//11 		-- 	文件中的字节长度
//Wed Sep 09 15:30:11 CST 2020	--	返回时间戳
}
对文件夹的操作
@Test
public void test3()
{
    File file = new File("E:\\BUPT\\java");
    String[] list = file.list();
    for(String str : list)
    {
        System.out.println(str);
    }
    File[] files = file.listFiles();
    for (File f : files)
    {
        System.out.println(f);
    }
//        day1.md
//        day2.md
//        ...
//        E:\BUPT\java\day1.md
//        E:\BUPT\java\day2.md
//        ...
}

重命名

boolean file1.ranameTo(file2)

注意:file1必须在硬盘中存在,file2必须在硬盘中不存在,否则操作失败,返回false

@Test
public void test4()
{
    File file1 = new File("hello.txt");
    File file2 = new File("hi.txt");
    boolean b = file2.renameTo(file1);
    System.out.println(b);
    // true if hello.txt exists and hi.txt not
}
判断相关信息
  • public boolean isDirectory():判断是否是目录
  • public boolean isFile():判断是否是文件
  • public boolean exists():判断是否存在
  • public boolean canRead():判断是否可读
  • public boolean canWrite():判断是否可写
创建、删除功能
  • public boolean createNewFile():创建新的文件,如果文件存在则不创建,返回false
  • public boolean mkdir():创建文件目录,如果目录存在则不创建,如果上层目录不存在也不创建
  • public boolean mkdirs():创建文件目录,如果上层文件不存在一并创建
  • public boolean delete():删除文件或文件夹。注意:Java删除不走回收站!

IO流原理及流的分类

IO是Input/Output的缩写,用于处理设备之间的数据传输。Java中数据的输入输出以流的方式进行。java.io包下提供了各种 流类和接口,并通过标准的方法输入或输出数据

流的分类

  • 操作数据单位不同分为:字节流(8bit),字符流(16bit)
  • 数据量的流向不同分为:输入流、输出流
  • 按流的角色的不同分为:节点流、处理流
抽象基类字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

在这里插入图片描述

深色是比较重要的。主要学习访问文件的四个流,具体的操作方法每个流都差不多,剩下的学习功能即可。

文件流

FileReader

首先注意的几点:

  • IO流这些物理上的流JVM无法自行关闭,必须手动关闭!
  • read()的理解:返回读入的一个字符,如果达到文件末尾返回-1
  • 异常的处理:如果使用throws,发现错误就会理解创建异常对象然后结束,此时有可能IO流对象还未被关闭,所以需要使用try-catch-finally来关闭IO流而非使用throws
  • 打开的文件一定要存在,不然会报错
public void test() throws IOException {
    FileReader fr = null;
    try {
        File file = new File("hello.txt");
        fr = new FileReader(file);

        int data;
        while((data = fr.read())!=-1)
        {
            System.out.print((char)data);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fr != null)
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

重载read()方法——一次读多个字符

public void test2() {
    FileReader fr = null;
    try {
        // 1. File类的初始化
        File file = new File("hello.txt");
        // 2. io流类的初始化
        fr = new FileReader(file);
        // 3. 读文件操作
        // 这里使用重载的read(char[] buf)
        int len;
        char[] cbuf = new char[5];
        while ((len = fr.read(cbuf)) != -1) {
//            System.out.println("错误的写法1");
//            for (int i = 0; i < cbuf.length; i++)
//                System.out.print(cbuf[i]);
//            // helloworld123ld
//            
//            System.out.println("\n错误的写法2:");
//            String str = new String(cbuf);
//            System.out.print(cbuf);
//            // helloworld123ld
//            
//            System.out.println("\n正确的写法1");
//            for (int i = 0; i < len; i++)
//                System.out.print(cbuf[i]);
//            // helloworld

            System.out.println("\n正确的写法2");
            String str2 = new String(cbuf, 0, len);
            System.out.print(str2);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 4. 关闭IO流
        if(fr != null)
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

FileWriter

注意:

  • 若文件不存在,则创建该文件
  • 若文件存在,会覆盖该文件
  • FileWriter(File file,boolean append),如果使用该构造器,append为false则覆盖,为true则添加
public void test3(){
    FileWriter fw = null;
    try {
        // 该文件不存在,则会创建文件
        File file = new File("hi.txt");
        fw = new FileWriter(file);

        fw.write("I hava a dream! ");
        fw.write("This is a Test");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileReader和FileWriter实现文件复制

注意:FileReader是字符流形式,不能用于图片、视频的复制,如果想实现后者的复制,必须换成FileOutputStream,FileWriter同理。

结论:对于文本文件(.txt.doc.c.java)用字符流处理,非文本文件用字节流(.jpg.mp4.mp3)处理

@Test
public void test5()
{
    FileReader fr = null;
    FileWriter fw = null;
    try {
        File srcfile = new File("hello.txt");
        File destfile = new File("hello2.txt");

        fr = new FileReader(srcfile);
        fw = new FileWriter(destfile);

        int len;
        char []cbuf = new char[5];
        while((len = fr.read(cbuf))!=-1)
        {
            String str = new String(cbuf,0,len);
            fw.write(str);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fr!=null)
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        if(fw !=null)
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

缓冲流(处理流的一种)

缓冲流是为了提高读写效率

注意:

  • 新建缓冲流的前提是新建了一个节点流
  • 关闭处理流时,只用关闭外层流,内层流自动关闭
  • 使用缓冲流的速度远大于节点流(原因:内部提供缓冲区,大小为8092,等到缓冲区填满了再flush出去)
@Test
public void test6() {
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        // 1.造文件
        File f1 = new File("UI1.png");
        File f2 = new File("UI2.png");

        // 2.造流
        // 2.1 造节点流
        FileInputStream fis = new FileInputStream(f1);
        FileOutputStream fos = new FileOutputStream(f2);
        // 2.2 造处理流
        bis = new BufferedInputStream(fis);
        bos = new BufferedOutputStream(fos);

        // 复制
        int len;
        byte[] bytes = new byte[10];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (bos != null) {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bis != null) {
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

转换流

分辨属于什么流看后缀,转换流属于字符流

  • InputStreamReader:将一个字节的输入流转换为字符的输入流
  • OutputStreamWriter:将一个字符的输出流转换为字节的输出流
  • 作用:提供字节流与字符流之间的转换
  • 解码:字节、字节数组 —>字符数组、字符串
  • 编码:字符数组、字符串 —>字节、字节数组

字符集

  • ASCII:美国标准信息交换码,用一个字节的7位可以表示

  • ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位可以表示

  • GB2312:中国的中文编码表,最多两个字节编码所有字符

  • GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节

  • Unicode:国际校准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码,所有的文字字符都用两个字节表示

  • UTF-8:变长的编码方式,可用1-4个字节来表示一个字符

对象流

序列化机制

允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其他程序获取了这种二进制流,就可以恢复成原来的Java对象。

对象的序列化

用于存储和读取基本数据类型数据或对象的处理流,可以把Java中的对象写入到数据源中也能还原回来。

  • ObjectInputStreamObjectOutputStream
  • 序列化:用ObjectInputStream类保存基本类型数据或对象的机制
  • 反序列化:用ObjectOutputStream类读取基本类型数据或对象的机制

static和transient修饰的成员变量不能被序列化

IO流的框架都是一样的,对象流也差不多

自定义类序列化的注意事项:

  • 注意进行序列化的对象所在的类必须要实现Serializable接口,尤其是自定义类
  • 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量private static final long serialVersionUID
  • 如果不显式设置这个ID也可,但是系统会隐式给你一个ID,当你修改了类中的变量之后,ID会改变,可能会造成先前序列化后的文件反序列化回来的结果与原来不一致。所以一般自己显示定义一个常量。
  • 自定义类的所有内部属性必须可序列化。(默认情况下,基本数据类型可序列化)
public class ObjectStreamTest {
    // 序列化
    @Test
    public void test2()
    {
        ObjectOutputStream oos = null;
        try {
            File file = new File("object.dat");
            FileOutputStream fos = new FileOutputStream(file);
            oos = new ObjectOutputStream(fos);
            oos.writeObject(new User(18,"Bill"));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(oos != null)
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }
    // 反序列化
    @Test
    public void test1()
    {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));
            Object obj = ois.readObject();
            User user = (User) obj;
            System.out.println(user);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null)
            {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
       System.out.println(user);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if(ois != null)
        {
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值