1.1 IO概述

回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了。那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据读出来继续使用呢?其实要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等 ROM)上。

当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作。

因此我们把这种输入和输出动作称为IO操作。

IO流-File,字节流,缓冲流 随笔 第1张

1.2 IO流流向分类

按照流向分输入流与输出流,每个IO流对象均要绑定一个IO资源

分类关系如下:

字节输入流 InputStream的抽象类

  FileInputStream 操作文件的字节输入流

字节输出流 OutputStream的抽象类

  FileOutputStream 操作文件的字节输出流

按照传输方式:分为字节流和字符流

    字符流  按照字符的方式读写 

    字节流  按照字节的方式读写

 

1.3 一切均为字节

 

在数据传输过程中,一切数据(文本、图像、声音等)最终存储的均为一个个字节,即二进制数字。所以数据传输过程中使用二进制数据可以完成任意数据的传递。

 

 

第1章 File

 

在我们操作系统中,数据都保存在文件中,而文件存放相应的文件夹中。那么Java中是如何描述这些的呢?

 

1.1 File类的出现

 

打开API,搜索File类。阅读其描述:File文件和目录路径名的抽象表示形式。即,Java中把文件或者目录(文件夹)都封装成File对象。也就是说如果我们要去操作硬盘上的文件,或者文件夹只要找到File这个类即可。那么我们就要研究研究File这个类中都有那些功能可以操作文件或者文件夹呢?

 

 

1.2 File类的构造方法

IO流-File,字节流,缓冲流 随笔 第2张

通过构造方法创建File对象,我们进行代码演示:

 

    public static void main(String[] args) {
        //方法1:
        String filePath = "G:\\FileTest\\file1.txt";
        File file = new File(filePath);
        System.out.println(file);
        // 方法2:将parent封装成file对象。
        File dir = new File("G:\\FileTest");
        File file2 = new File(dir, "hello.java");
        //方法3:
        File file3 = new File("G:\\FileTest", "hello.java");
    }

1.3 File类的方法

创建完了File对象之后,那么File类中都有如下常用方法

 

public static void main(String[] args) throws IOException {
        String dirPath = "g:\\TestFiles";
        //String dirPath = "g:\\TestFile";//注意java创建文件夹和文件名不要包含file,可能存在bug,创建不成功
        String filePath = "G:\\TestFiles\\file1.txt";
        File dir = new File("g:\\TestFiles");
        boolean b1=dir.mkdir();//创建一个空的新文件夹(前提是该文件不存在)
        File file = new File(filePath);
        boolean b2=file.createNewFile();//创建一个空的新文件(前提是该文件不存在)注意,要保证该路径下所有的文件夹都已经存在或者在此之前已经创建
        // 创建文件,如果文件不存在,创建 true 如果文件存在,则不创建 false。 如果路径错误,IOException。
        String absPath=file.getAbsolutePath();//获取文件全路径
        String path=file.getPath();//获取我们构造文件的时候的路径(也就是File构造方法里面我们传递的字符串)
        String name=file.getName();//获取文件名
        String parent=file.getParent();//获取父文件夹文件名
        boolean isfile=file.isFile();//判断是不是文件(如果文件不存在返回false)
        boolean isdir=file.isDirectory();//判断是不是文件夹(如果文件夹不存在返回false)
        boolean canread=file.canRead();//判断是否可读
        boolean canwrite=file.canWrite();//判断是否可写
        long lenth=file.length();//返回文件的长度
        boolean b3=file.exists();//判断文件是否存在
        boolean b4 = file.delete();//删除文件操作--删除成功返回true,文件不存在返回false-----注意:不去回收站。慎用------
        //删除目录时,如果目录中有内容,无法直接删除返回false。只有将目录中的内容都删除后,保证该目录为空。这时这个目录才可以删除。
        boolean b5 = dir.delete();
        System.out.println("b1="+b1);
        System.out.println(absPath);
        System.out.println(path);
        System.out.println(name);
        System.out.println(parent);
        System.out.println(isfile);
        System.out.println(isdir);
        System.out.println(canread);
        System.out.println(canwrite);
        System.out.println(lenth);
        System.out.println(b3);
        System.out.println(b4);
        System.out.println(b5);
//    1.1 listFiles()list()方法介绍
     File dir0=new File("g://files");
        File dir1=new File("g://files//dir1");
        File dir2=new File("g://files//dir2");
        File f1=new File("g://files//dir2//test1.txt");
        File f2=new File("g://files//dir2//test2.txt");
        File f3=new File("g://files//dir1//test3.txt");
        if(!dir1.exists()) {
            dir1.mkdirs();
        }
        if(!dir2.exists()) {
            dir2.mkdirs();
        }
        if(!f1.exists()) {
            f1.createNewFile();
        }
        if(!f2.exists()) {
            f2.createNewFile();
        }
        if(!f3.exists()) {
            f3.createNewFile();
        }
        String arg1[]=dir0.list();//获取的是目录下的当前的文件以及文件夹的名称。
        for(String s: arg1) {
            System.out.println(s);
        }
        File f[]=dir0.listFiles();//获取目录下当前文件以及文件对象,只要拿到了文件对象,那么就可以获取其中想要的信息
        for(File ff:f) {
            System.err.println(ff);
        }

    }

 

 

第2章 字节流

既然一切数据都是字节,那么字节流如何操作呢,那么接下来我们进行字节流的学习.

2.1 字节输出流OutputStream

OutputStream此抽象类是表示输出字节流的所有类的超类。操作的数据都是字节,定义了输出字节流的基本共性功能方法。

输出流中定义都是写write方法;

 

2.1.1 FileOutputStream

 

OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。

 

FileOutputStream,即文件输出流是用于将数据写入 File的输出流。

 

 IO流-File,字节流,缓冲流 随笔 第3张

构造方法:

IO流-File,字节流,缓冲流 随笔 第4张

代码演示:

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //需求:将数据写入到文件中。
        //创建存储数据的文件。
        File f1=new File("g://files//dir2//test1.txt");
        File f2=new File("g://files//dir2//test2.txt");
        File f3=new File("g://files//dir2//test3.txt");
        //创建一个用于操作文件的字节输出流对象。一创建就必须明确数据存储目的地。
        //输出流目的是文件,会自动创建。如果文件存在,则覆盖。
        FileOutputStream fs1=new FileOutputStream(f1);
        FileOutputStream fs2=new FileOutputStream(f2,true);//第二个参数true标识不是覆盖,而是续写
        FileOutputStream fs3=new FileOutputStream(f3);
        byte b[]="123我很开心".getBytes();
        //调用父类的write方法
        fs1.write(b);//将b全部写出
        fs2.write(b,2,4);//将b里面索引在2-4的内容写出(3我很)
        fs3.write(10);//这个方法有待研究
        //刷新此输出流并强制写出所有缓冲的输出字节
        fs1.flush();
        //关闭流资源
        fs1.close();
        
        fs2.flush();
        fs2.close();
        fs3.flush();
        fs3.close();
    }

2.2.1 FileInputStream

InputStream有很多子类,其中子类FileInputStream可用来读取文件内容。

FileInputStream 从文件系统中的某个文件中获得输入字节。

IO流-File,字节流,缓冲流 随笔 第5张

构造方法:

 IO流-File,字节流,缓冲流 随笔 第6张

2.2.2 FileInputStream类读取数据read方法(只读纯英文,有空介绍一下读中文问题)

在读取文件中的数据时,调用read方法,实现从文件中读取数据

IO流-File,字节流,缓冲流 随笔 第7张

代码演示:

public static void main(String[] args) throws Exception {
        File f1=new File("g://files//dir2//test1.txt");
        FileInputStream fis1=new FileInputStream(f1);
        //读取数据。使用 read();一次读一个字节。
        int n;
        while((n=fis1.read())!=-1) {
            System.out.println((char)n);
        }
        fis1.close();
    }

2.2.3 读取数据read(byte[])方法

在读取文件中的数据时,调用read方法,每次只能读取一个,太麻烦了,于是我们可以定义数组作为临时的存储容器,这时可以调用重载的read方法,一次可以读取多个字符。

 

public static void main(String[] args) throws Exception {
        File f1=new File("g://files//dir2//test1.txt");
        FileInputStream fis1=new FileInputStream(f1);
        /*
         * 演示第二个读取方法, read(byte[]);
         */
        int n=0;
        byte b[]=new byte[1024];//长度可以定义成1024的整数倍。
        while((n=fis1.read(b))!=-1) {
            System.out.println(new String(b,0,n));
        }
        fis1.close();
    }

2.3.1 复制文件

原理;读取一个已有的数据,并将这些读到的数据写入到另一个文件中。

 

public class CopyFileTest {
    public static void main(String[] args) throws IOException {
        //1,明确源和目的。
        File srcFile = new File("c:\\YesDir\test.JPG");
        File destFile = new File("copyTest.JPG");
        
        //2,明确字节流 输入流和源相关联,输出流和目的关联。
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        
        //3, 使用输入流的读取方法读取字节,并将字节写入到目的中。
        int ch = 0;
        while((ch=fis.read())!=-1){
            fos.write(ch);
        }
        //4,关闭资源。
        fos.close();
        fis.close();
    }
}

上述代码输入流和输出流之间是通过ch这个变量进行数据交换的。

上述复制文件有个问题,每次都从源文件读取一个,然后在写到指定文件,接着再读取一个字符,然后再写一个,一直这样下去。效率极低。

2.3.2临时数组方式复制文件

上述代码复制文件效率太低了,并且频繁的从文件读数据,和写数据,能不能一次多把文件中多个数据都读进内容中,然后在一次写出去,这样的速度一定会比前面代码速度快。

public class CopyFileByBufferTest {
    public static void main(String[] args) throws IOException {
        File srcFile = new File("c:\\YesDir\test.JPG");
        File destFile = new File("copyTest.JPG");
        // 明确字节流 输入流和源相关联,输出流和目的关联。
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        //定义一个缓冲区。
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);// 将数组中的指定长度的数据写入到输出流中。
        }
        // 关闭资源。
        fos.close();
        fis.close();
    }
}

第3章 缓冲流

在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么,我想提高速度,怎么办?

Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度

缓冲流,根据流的分类分为字节缓冲流与字符缓冲流。

3.1 字节缓冲流

字节缓冲流根据流的方向,共有2

写入数据到流中,字节缓冲输出流 BufferedOutputStream

读取流中的数据,字节缓冲输入流 BufferedInputStream

它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度

3.1.1字节缓冲输出流BufferedOutputStream

通过字节缓冲流,进行文件的读写操作 写数据到文件的操作  

l 构造方法

public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 

public class BufferedOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        
        //写数据到文件的方法
        write();
    }

    /*
     * 写数据到文件的方法
     * 1,创建流
     * 2,写数据
     * 3,关闭流
     */
    private static void write() throws IOException {
        //创建基本的字节输出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt");
        //使用高效的流,把基本的流进行封装,实现速度的提升
        BufferedOutputStream out = new BufferedOutputStream(fileOut);
        //2,写数据
        out.write("hello".getBytes());
        //3,关闭流
        out.close();
    }
}

3.1.2 字节缓冲输入流 BufferedInputStream

刚刚我们学习了输出流实现了向文件中写数据的操作,那么,现在我们完成读取文件中数据的操作

l 构造方法

public BufferedInputStream(InputStream in)

 

/*
     * 从文件中读取数据
     * 1,创建缓冲流对象
     * 2,读数据,打印
     * 3,关闭
     */
    private static void read() throws IOException {
        //1,创建缓冲流对象
        FileInputStream fileIn = new FileInputStream("abc.txt");
        //把基本的流包装成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn);
        //2,读数据
        int ch = -1;
        while ( (ch = in.read()) != -1 ) {
            //打印
            System.out.print((char)ch);
        }
        //3,关闭
        in.close();
    }

3.3.3  复制单级文件夹

/* 
 * 数据源:e:\\demo
 * 目的地:e:\\test
 * 
 * 分析:
 *         A:封装目录
 *         B:获取该目录下的所有文本的File数组
 *         C:遍历该File数组,得到每一个File对象
 *         D:把该File进行复制
 */
public class CopyFolderDemo {
    public static void main(String[] args) throws IOException {
        // 封装目录
        File srcFolder = new File("e:\\demo");
        // 封装目的地
        File destFolder = new File("e:\\test");
        // 如果目的地文件夹不存在,就创建
        if (!destFolder.exists()) {
            destFolder.mkdir();
        }

        // 获取该目录下的所有文本的File数组
        File[] fileArray = srcFolder.listFiles();

        // 遍历该File数组,得到每一个File对象
        for (File file : fileArray) {
            // System.out.println(file);
            // 数据源:e:\\demo\\e.mp3
            // 目的地:e:\\test\\e.mp3
            String name = file.getName(); // e.mp3
            File newFile = new File(destFolder, name); // e:\\test\\e.mp3

            copyFile(file, newFile);
        }
    }

    private static void copyFile(File file, File newFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                file));
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(newFile));

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }

        bos.close();
        bis.close();
    }
}

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄