Java学习笔记

IO流(操作文件内容): 字节流

2017-02-11  本文已影响721人  奋斗的老王

IO简单概述

  File对象可以表示存在的文件或文件夹,也可以表示不存在的。我们想要得到文件的内容怎么办? 
  File只是操作文件,文件的内容如何处理就需要使用io流技术了
  例如在D盘下有一个名称为a.txt的文本文件. 想要通过Java程序读出来文件中的内容, 需要使用IO流技术. 同样想要将程序中的数据,保存到硬盘的文件中,也需要IO流技术

IO解决问题 : 解决设备与设备之间的数据传输问题(硬盘 -> 内存 内存 -> 硬盘)

public class IODemo {
    public static void main(String[] args) throws FileNotFoundException, IOException {
        writFileTest();
        readFileTest();
    }

    private static void writFileTest() throws FileNotFoundException,
            IOException {
        // 创建文件对象
        File file = new File("c:\\a.txt");
        // 创建文件输出流
        FileOutputStream fos = new FileOutputStream(file);
        fos.write('g');
        fos.write('z');
        fos.write('i');
        fos.write('t');
        fos.write('c');
        fos.write('a');
        fos.write('s');
        fos.write('t');
        fos.close();
    }

    private static void readFileTest() throws FileNotFoundException,
            IOException {
        // 创建文件对象
        File file = new File("c:\\a.txt");
        // 创建文件输入流
        FileInputStream fis = new FileInputStream(file);
        // 有对多长,就读多少字节。
        for (int i = 0; i < file.length(); i++) {
            System.out.print((char) fis.read());
        }
        fis.close();
               // 当完成流的读写时,应该通过调用close方法来关闭它,
               // 这个方法会释放掉十分有限的操作系统资源.
               // 如果一个应用程序打开了过多的流而没有关闭它们,那么系统资源将被耗尽
    }
}

字节流

输入字节流
// 根据read方法返回值的特性,如果独到文件的末尾返回-1,如果不为-1就继续向下读
private static void showContent(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        int len = fis.read();
        while (len != -1) {
            System.out.print((char)len);
            len = fis.read();

        }
        // 使用完关闭流
        fis.close();
    }
// 使用字节数组存储读到的数据
    private static void showContent2(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[5];
        int len = fis.read(byt);
        for (int i = 0; i < byt.length; i++) {
            System.out.print((char) byt[i]);
        }

        // 使用完关闭流
        fis.close();
    }
/**
     * 把数组的一部分当做流的容器来使用
     * read(byte[] b,int off,int len)
     */
    private static void showContent3(String path) throws IOException {
        // 打开流
        FileInputStream fis = new FileInputStream(path);

        // 通过流读取内容
        byte[] byt = new byte[1024];
        // 从什么地方开始存读到的数据
        int start = 5;
        
        // 希望最多读多少个(如果是流的末尾,流中没有足够数据)
        int maxLen = 6;

        // 实际存放了多少个
        int len = fis.read(byt, start, maxLen);

        for (int i = start; i < start + maxLen; i++) {
            System.out.print((char) byt[i]);
        }

        // 使用完关闭流
        fis.close();
    }
/**
     * 使用字节数组当缓冲
     * */
    private static void showContent5(String path) throws IOException {
        FileInputStream fis = new FileInputStream(path);
        byte[] byt = new byte[1024];
        int len = fis.read(byt);
        System.out.println(len);
        String buffer = new String(byt, 0, len);
        System.out.print(buffer);
    }

注意:如何将字节数组转成字符串? 可以通过创建字符串对象即可。
发现:一旦数据超过1024个字节,数组就存储不下。如何将文件的剩余内容读完?我们可以通过通过循环保证文件读取完

    /**
     * 使用字节数组当缓冲
     * */
    private static void showContent7(String path) throws IOException {
        FileInputStream fis = new FileInputStream(path);
        byte[] byt = new byte[1024];
        int len = 0;
        while ((len = fis.read(byt)) != -1) {
            System.out.println(new String(byt, 0, len));
        }
    }
输出字节流
public class IoTest2 {
    public static void main(String[] args) throws IOException {
        String path = "c:\\a.txt";
        writeTxtFile(path);
    }

    private static void writeTxtFile(String path) throws IOException {
        // 1:打开文件输出流,流的目的地是指定的文件
        FileOutputStream fos = new FileOutputStream(path);

        // 2:通过流向文件写数据
        fos.write('j');
        fos.write('a');
        fos.write('v');
        fos.write('a');
        // 3:用完流后关闭流
        fos.close();

    }
}
public class IoTest2 {
    public static void main(String[] args) throws IOException {
        String path = "c:\\a.txt";
        writeTxtFile(path);
    }

    private static void writeTxtFile(String path) throws IOException {
        // 1:打开文件输出流,流的目的地是指定的文件
        FileOutputStream fos = new FileOutputStream(path);

        // 2:通过流向文件写数据
        byte[] byt = "java".getBytes();
        fos.write(byt);
        // 3:用完流后关闭流
        fos.close();
    }
}
  仔细查看a.txt文本文件发现上述程序每运行一次,老的内容就会被覆盖掉。     
  那么如何不覆盖已有信息,能够往a.txt里追加信息呢
  查看API文档, 发现FileOutputStream类中的构造方法中有一个构造可以实现追加的功能 FileOutputStream(File file, boolean append) 第二个参数append为 true,则将字节写入文件末尾处,而不是写入文件开始处
private static void writeTxtFile(String path) throws IOException {
        // 1:打开文件输出流,流的目的地是指定的文件
        FileOutputStream fos = new FileOutputStream(path,true);

        // 2:通过流向文件写数据
        byte[] byt = "java".getBytes();
        fos.write(byt);
        // 3:用完流后关闭流
        fos.close();
    }
字节流文件拷贝
public class IoTest3 {
    public static void main(String[] args) throws IOException {
        String path = "c:\\b.txt";
        String content = "hello java";

        writeFile(path, content);

        readFile(path);
    }

    public static void writeFile(String path, String content)
            throws IOException {
        // 打开文件输出流
        FileOutputStream fos = new FileOutputStream(path);
        byte[] buffer = content.getBytes();
        // 向文件中写入内容
        fos.write(buffer);
        // 关闭流
        fos.close();

    }

    public static void readFile(String path) throws IOException {
        FileInputStream fis = new FileInputStream(path);
        byte[] byt = new byte[1024];
        int len = 0;
        while ((len = fis.read(byt)) != -1) {
            System.out.println(new String(byt, 0, len));
        }
        // 关闭流
        fos.close();

    }
}

什么是文件拷贝?很显然,先开一个输入流,将文件加载到流中,再开一个输出流,将流中数据写到文件中。就实现了文件的拷贝

public class IoTest3 {

    public static void main(String[] args) throws IOException {

        String srcPath = "c:\\a.txt";
        String destPath = "d:\\a.txt";
        copyFile(srcPath, destPath);
    }

    public static void copyFile(String srcPath, String destPath)
            throws IOException {
        // 打开输入流,输出流
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);

        // 读取和写入信息
        int len = 0;
        while ((len = fis.read()) != -1) {
            fos.write(len);
        }

        // 关闭流
        fis.close();
        fos.close();
    }
}
`` 拷贝音频, 视频文件 ``
public class IoTest3 {

    public static void main(String[] args) throws IOException {

        String srcPath = "c:\\秋.jpg";
        String destPath = "d:\\秋.jpg";
        copyFile(srcPath, destPath);
    }

    public static void copyFile(String srcPath, String destPath)
            throws IOException {
        // 打开输入流,输出流
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);

        // 读取和写入信息
        int len = 0;
        while ((len = fis.read()) != -1) {
            fos.write(len);
        }

        // 关闭流
        fis.close();
        fos.close();
    }
}
  1. 使用字节数组作为缓冲区
public static void copyFile2(String srcPath, String destPath)
            throws IOException {
        // 打开输入流,输出流
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);

        // 读取和写入信息
        int len = 0;

        // 使用字节数组,当做缓冲区
        byte[] byt = new byte[1024];
        while ((len = fis.read(byt)) != -1) {
            fos.write(byt);
        }

        // 关闭流
        fis.close();
        fos.close();
    }
- 问题: 使用缓冲(字节数组)拷贝数据, 为什么拷贝后的文件大于源文件?
- 测试该方法, 打开文件发现拷贝后的文件和拷贝前的源文件不同, 拷贝后的文件要比源文件多一些内容问题就在于我们使用的容器, 这个容器我们是重复使用的, 新的数据会覆盖掉老的数据, 显然最后一次读文件的时候,容器并没有装满, 出现了新老数据并存的情况. 所以最后一次把容器中数据写入到文件中就出现了问题
- 如何避免?使用 `` FileOutputStream 的write(byte[] b, int off, int len) `` : b 是容器,off是从数组的什么位置开始,len是获取的个数,容器用了多少就写出多少
public static void copyFile2(String srcPath, String destPath)
            throws IOException {
        // 打开输入流,输出流
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);

        // 读取和写入信息
        int len = 0;

        // 使用字节数组,当做缓冲区
        byte[] byt = new byte[1024];
        while ((len = fis.read(byt)) != -1) {
            fos.write(byt, 0, len);
        }

        // 关闭流
        fis.close();
        fos.close();
    }
- 使用缓冲拷贝视频,可以根据拷贝的需求调整数组的大小,一般是1024的整数倍。发现使用缓冲后效率大大提高
字节流的异常处理

当我们读和写打开流, 关闭流的时候都会出现异常, 异常出现后, 后面的代码就不会执行. 假设打开和关闭流出现了异常, 那么close方法就不会再执行

public class IoTest4 {
    public static void main(String[] args) throws IOException,
            InterruptedException {
        String path = "c:\\b.txt";
        readFile(path);
    }

    private static void readFile(String path) throws IOException,
            InterruptedException {
        FileInputStream fis = new FileInputStream(path);
        byte[] byt = new byte[1024];
        int len = fis.read(byt);
        System.out.println(new String(byt, 0, len));
        // 让程序睡眠,无法执行到close方法。
        Thread.sleep(1000 * 10);
        fis.close();
    }
}
在执行该程序的同时我们尝试去删除b.txt文件。如果在该程序没有睡醒的话,我们是无法删除b.txt 文件的
因为b.txt还被该程序占用着,这是很严重的问题,所以一定要关闭流。
目前我们是抛出处理,一旦出现了异常,close就没有执行,也就没有释放资源
那么为了保证close的执行该如何处理呢? 那么就需要使用try{} catch(){}finally{}语句
try中放入可能出现异常的语句,catch是捕获异常对象,fianlly是一定要执行的代码
public class IoTest4 {
    public static void main(String[] args) throws IOException,
            InterruptedException {
        String path = "c:\\b.txt";
        readFile(path);
    }

    private static void readFile(String path) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(path);
            byte[] byt = new byte[1024];
            int len = fis.read(byt);
            System.out.println(new String(byt, 0, len));
        } catch (IOException e) {
            // 抛出运行时异常
            throw new RuntimeException(e);
        } finally {
            // 把close方法放入finally中保证一定会执行
            // 先判断是否空指针
            if (fis != null) {
                try {
                    fis.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
public static void copyFile(String srcPath, String destPath) {

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(srcPath);
            fos = new FileOutputStream(destPath);

            byte[] byt = new byte[1024 * 1024];
            int len = 0;
            while ((len = fis.read(byt)) != -1) {

                fos.write(byt, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

        }

    }
public static void copyFile(String srcPath, String destPath) {

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(srcPath);
            fos = new FileOutputStream(destPath);

            byte[] byt = new byte[1024 * 1024];
            int len = 0;
            while ((len = fis.read(byt)) != -1) {

                fos.write(byt, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {

            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

            }
        }

    }
字节缓冲流
public class IoTest5 {
    public static void main(String[] args) throws IOException {
        String srcPath = "c:\\a.mp3";
        String destPath = "d:\\copy.mp3";
        copyFile(srcPath, destPath);
    }

    public static void copyFile(String srcPath, String destPath)
            throws IOException {
        // 打开输入流,输出流
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);

        // 使用缓冲流
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        // 读取和写入信息
        int len = 0;

        while ((len = bis.read()) != -1) {
            bos.write(len);
        }

        // 关闭流
        bis.close();
        bos.close();    
}
}

什么情况使用字节流 : 读取到数据不需要经过编码或者解码的情况情况下这时候使用字节流(比如 : 图片数据)

上一篇 下一篇

猜你喜欢

热点阅读