IO流

    通过IO可以完成硬盘文件的读和写

    往内存中去,叫输入(input),或者叫读

    从内存中出来,叫输出(output),或者叫写。

    流的分类:

    字节流:一次读取一个字节,等同于一次读取八个二进制位。比如读取英文字母,一个字母一个字节,一个中文在Java中理论上占两个字节,这个指的是在JVM虚拟机中一个中文字符占两个字节。但在数据存储层面,一个中文字符是按照UTF-8的规定,以3个字节的方式保存在文件中,但是当中文字符被读到JVM内存中,该字符会被转为UTF-16,并以2个字节的方式保存在JVM内存中。

    java.io.InputStream 字节输入流
    java.io.OutputStream 字节输出流

    字符流:一次读取一个字符,这种流是为了方便读取普通文本文件而存在的。

    java.io.Reader 字符输入流

    java.io.Writer 字符输出流
    每个字符在计算机语言中都有一个ASCII值对应,通过ASCII值建立起字符与字节的联系。

    字符流读取数据和字节流读取数据:

    相同点:在Java中的操作步骤相似,以及所调用的API相同

    不同点:效率不同,字符流效率更高,但字节流可以读取任意文件(视频,音频,图片),字符流只能读取普通文本(普通文本不是单指txt文件,指只包含文本的文件,比如java文件)。

    所有的都实现了java.io.Closeable接口,都是可关闭的,都有close()方法

    所有的输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法。从内存中把数据写到硬盘中是通过管道进行的,管道会刷新,所以输出流都可刷新。
    ps:存在一个类:OutputStreamWriter(此类属于字符流),是字符流通向字节流的桥梁:可以使用charset将要写入的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

    一、文件专属流:

    java.io.FileIntputStream

    java.io.FileOutputStream

    java.io.FileReader

    java.io.FileWriter

    java.io.FileReader、java.io.FileWriter与java.io.FileIntputStream、java.io.FileOutputStream的使用方法相同,字符流只能读取普通文本。

    1、java.io.FileIntputStream

    创建对象时其参数可以是File对象。
    读取方法为read(),read 如果是空参方法,返回的是ASCII值,且一次一个字节,如果是有参且传递的是字节数组时,返回的是读取的字节的个数。
    创建字节数组进行读取时,是将对应字符的ASCII值传入数组,然后通过创建字符串对象,将数组传入字符串对象来转换为字符串。读取时会进行覆盖。

    举个例子:
    数据为abcdefg,七个字节,用长度为4的字节数组读取,那么第一次读取出来的数据是abcd,第二次读取时还剩3个字母没读,所以第二次读出的数据是efg,这是因为efg将abc覆盖了,如果将读取长度写死为4,那个读出的是efgd。
    image.png

    代码如下:

    1. /**
    2. * FileIntputStream 文件专属流,字节输入流
    3. */
    4. public class IOTest02 {
    5. public static void main(String[] args) {
    6. FileInputStream fileInputStream = null;
    7. try {
    8. //创建流对象
    9. fileInputStream = new FileInputStream("E:\\Temp\\test.txt");
    10. //创建一个字节数组
    11. //将ASCII值转换为字符时就是通过字节数组
    12. byte[] bytes = new byte[4];
    13. //传入字节数组,读取时会按照字节数组的长度来读取字节
    14. //read 如果是空参方法,返回的是ASCII值,如果是有参且传递的是字节数组时,返回的是读取的字节的个数
    15. int read = fileInputStream.read(bytes);
    16. //创建字符串对象,并且传入需要转换的字节数组,会将字节数组的ASCII值转换为对应的字符串
    17. String s = new String(bytes,0,4);
    18. System.out.println(s);
    19. //此时再读,就是读取剩下的字节
    20. read = fileInputStream.read(bytes);
    21. //剩下3个,此时read值为3
    22. System.out.println(new String(bytes,0,read));
    23. } catch (Exception e) {
    24. e.printStackTrace();
    25. }finally {
    26. try {
    27. fileInputStream.close();
    28. } catch (IOException e) {
    29. e.printStackTrace();
    30. }
    31. }
    32. }
    33. }

    此时第二次输出为efg
    Java学习十九——io流(一) - 图2
    将第二次输出字节长度写死为4时:

    1. //此时再读,就是读取剩下的字节
    2. read = fileInputStream.read(bytes);
    3. System.out.println(new String(bytes,0,4));

    此时第二次输出为efgd
    Java学习十九——io流(一) - 图3

    FileIntputStream的available()方法 返回的是所读取文件剩余的字节个数

    可以通过调用这个方法作为字节数组的长度,这样就不用写while循环了。且转换时直接传入数组,不用设定从哪一位开始传,传多长字节。(不适用大文件)

    1. byte[] bytes = new byte[fileInputStream.available()];
    2. System.out.println(new String(bytes));
    3. //传入字节数组,读取时会按照字节数组的长度来读取字节
    4. /*read 如果是空参方法,返回的是ASCII值,如果是有参且传递的是字节数组时,返回的是读取的字节的个数*/
    5. int read = fileInputStream.read(bytes);
    6. System.out.println(new String(bytes));

    2、java.io.FileOutputStream
    输出流得有刷新(flush)

    1. package com.jy.io;
    2. import java.io.FileInputStream;
    3. import java.io.FileNotFoundException;
    4. import java.io.FileOutputStream;
    5. import java.io.IOException;
    6. /**
    7. * FileOuttputStream 文件专属流,字节输出流
    8. */
    9. public class IOTest03 {
    10. public static void main(String[] args) {
    11. FileOutputStream fileOutputStream = null;
    12. try {
    13. //创建输出流对象
    14. fileOutputStream = new FileOutputStream("E:\\Temp\\test02.txt");
    15. //abcd对应的ASCII值
    16. byte[] bytes = {97,98,99,100};
    17. fileOutputStream.write(bytes);
    18. /**
    19. * 将字符串转换为字节数组进行输出
    20. */
    21. //定义一个字符串
    22. String str = "你好,柿子!";
    23. //将字符串转换为字节数组
    24. byte[] bytes1 = str.getBytes();
    25. fileOutputStream.write(bytes);
    26. //刷新
    27. fileOutputStream.flush();
    28. } catch (Exception e) {
    29. e.printStackTrace();
    30. }finally {
    31. if(fileOutputStream != null){
    32. try {
    33. fileOutputStream.close();
    34. } catch (IOException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }
    39. }
    40. }

    输出流提供了两种构造,
    第一种,只需要传文件路径,输出时会覆盖之前的数据。

    1. fileOutputStream = new FileOutputStream("E:\\Temp\\test02.txt");

    第二种,追加,加上true,这时输出时会接着原有数据的后面追加。

    1. fileOutputStream = new FileOutputStream("E:\\Temp\\test02.txt",true);

    案例:copy文件或者视频

    1. /**
    2. * 通过输入流和输出流完成视频copy
    3. */
    4. public class IOTest06 {
    5. public static void main(String[] args) {
    6. FileInputStream fileInputStream = null;
    7. FileOutputStream fileOutputStream = null;
    8. try {
    9. //copy视频
    10. fileInputStream = new FileInputStream("E:\\Temp\\test.mp4");
    11. fileOutputStream = new FileOutputStream("E:\\Temp\\copy.mp4");
    12. //copy文件
    13. /*fileInputStream = new FileInputStream("io02.txt");
    14. fileOutputStream = new FileOutputStream("io03.txt",true);*/
    15. byte[] bytes = new byte[1024*1024];//1MB
    16. //读取文件
    17. int read = 0;
    18. while ((read = fileInputStream.read(bytes)) != -1){
    19. //将字节数组转换成字符串
    20. //String s = new String(bytes, 0, read);
    21. fileOutputStream.write(bytes,0,read);
    22. }
    23. //刷新数据流
    24. fileOutputStream.flush();
    25. } catch (FileNotFoundException e) {
    26. e.printStackTrace();
    27. } catch (IOException e) {
    28. e.printStackTrace();
    29. }finally {
    30. if(fileInputStream != null){
    31. try {
    32. fileInputStream.close();
    33. } catch (IOException e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. if(fileOutputStream != null){
    38. try {
    39. fileOutputStream.close();
    40. } catch (IOException e) {
    41. e.printStackTrace();
    42. }
    43. }
    44. }
    45. }
    46. }

    同理:FileReader和FileWriter的用法与上面相似,除了字节数组换成字符数组,无变化

    1. try {
    2. FileReader fileReader = new FileReader("io01.txt");
    3. char[] chars = new char[4];
    4. int read = 0;
    5. while ((read = fileReader.read(chars)) != -1){
    6. System.out.println(new String(chars,0,read));
    7. }
    8. }
    1. fileWriter.write("\n")//换行符