Java IO学习笔记(二):字节流与字符流

首先我们要知道流的概念

程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

字节流与字符流

javaIO流写入中文乱码 java io 字符流_javaIO流写入中文乱码

以上这四个都是抽象类

文件操作流程:

  1. 使用File类打开一个文件
  2. 通过字节流或字符流的子类,指定输出的位置
  3. 进行读/写操作
  4. 关闭输入/输出

注意:IO操作属于资源操作,一定要记得关闭。

字节流

字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream

字节输出流:OutputStream(向文件写入内容)

OutputStream是整个IO包中字节输出流的最大父类,定义如下:

public abstract class OutputStream extends Object implements Closeable,Flushable

有上面的定义可以看出:

  1. 此类是一个抽象类,必须通过子类实例化对象才能使用
  2. 使用FileOutputStream类。通过向上转型之后,可以为OutputStream实例化
  3. Closeable表示可以关闭的操作
  4. Flushable:表示刷新,清空内存中的数据

FileOutputStream类的构造方法如下:

javaIO流写入中文乱码 java io 字符流_学习_02

写数据:

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        OutputStream out = new FileOutputStream(f);//如果文件不存在会自动创建
        String str = "Hello World";
        byte[] b = str.getBytes();
        out.write(b);//因为是字节流,所以要转化成字节数组进行输出
        out.close();//最后一定要关闭
    }

最后在E盘生成一个内容属Hello World的 txt 文件。

也可以一个字节一个字节进行输出,如下:

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        OutputStream out = new FileOutputStream(f);//如果文件不存在会自动创建
        String str = "Hello World";
        byte[] b = str.getBytes();
        for (int i = 0; i < b.length; i++) {
            out.write(b[i]);
        }
        out.close();//最后一定要关闭
    }

以上输出只会进行覆盖,如果要追加的话,需要FileOutputStream类的另一个构造方法:

public FileOutputStream(File file,boolean append)throws FileNotFoundException

在构造方法中,如果将append的值设置为true,则表示在文件的末尾追加内容。

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        OutputStream out = new FileOutputStream(f, true);//如果文件不存在会自动创建
        String str = "\r\n 追加Hello World";
        byte[] b = str.getBytes();
        for (int i = 0; i < b.length; i++) {
            out.write(b[i]);
        }
        out.close();//最后一定要关闭
    }

文件内容变为:

javaIO流写入中文乱码 java io 字符流_开发语言_03


文件中换行为:\r\n

字节输入流:InputStream(从文件中把内容读取进来)

InputStream类的定义:

public abstract class InputStream extends Object implements Closeable

InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,就用FileInputStream来实现。

FileInputStream类的构造方法:

public FileInputStream(File file)throws FileNotFoundException

读文件

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        InputStream in = new FileInputStream(f);
        byte[] b = new byte[(int) f.length()];//根据文件的大小来定义字节数组的大小
        int len = in.read(b);
        in.close();
        System.out.println(new String(b, 0, len));
    }

控制台打印结果:

javaIO流写入中文乱码 java io 字符流_java_04


换种方式,一个字节一个字节读入:

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        InputStream in = new FileInputStream(f);
        byte[] b = new byte[(int) f.length()];//根据文件的大小来定义字节数组的大小
        for (int i = 0; i < b.length; i++) {
            b[i] = (byte) in.read();
        }
        in.close();
        System.out.println(new String(b));
    }

控制台打印结果:

javaIO流写入中文乱码 java io 字符流_开发语言_05


以上情况只适合知道输入文件的大小,不知道的话用如下方法:

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        InputStream in = new FileInputStream(f);
        byte[] b = new byte[1024];
        int temp = 0;
        int len = 0;
        while ((temp = in.read()) != -1) {//-1为文件读完的标志
            b[len] = (byte) temp;
            len++;
        }
        in.close();
        System.out.println(new String(b, 0, len));
    }

字符流

一个字符等于两个字节,java提供了Reader、Writer两个专门操作字符流的类。

字符输出流:Writer(向文件写入内容)

Writer本身是一个字符流的输出类,定义如下:

public abstract class Writer extends Object implements Appendable,Closeable,Flushable

此类本身也是一个抽象类,如果要使用此类,则肯定要使用其子类.如果是向文件中写入内容,所以应该使用FileWriter的子类。

FileWriter类的构造方法定义如下:

public FileWriter(File file)throws IOException

字符流的操作比字节流操作好在一点,就是可以直接输出字符串,不用再像之前那样进行转换操作。

写数据

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        Writer out = new FileWriter(f);
        String str = "Hello World进行测试";
        out.write(str);
        out.close();
    }

在默认情况下再次输出会覆盖,追加的方法也是在构造函数上加上追加标记

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        Writer out = new FileWriter(f,true);
        String str = "\r\nHello World进行测vdfvb试";
        out.write(str);
        out.close();
    }

字符输入流:Reader(从文件读取内容)

Reader是使用字符的方式从文件中取出数据,Reader类的定义如下:

public abstract class Reader extends Objects implements Readable,Closeable

Reader本身也是抽象类,如果现在要从文件中读取内容,则可以直接使用FileReader子类。

FileReader的构造方法定义如下:

public FileReader(File file)throws FileNotFoundException

以字符数组的形式读取出数据:

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        Reader input = new FileReader(f);
        char[] c = new char[1024];
        int len = input.read(c);
        input.close();
        System.out.println(new String(c, 0, len));
    }

也可以用循环方式,判断是否读到底:

public static void main(String[] args) throws IOException {
        File f = new File("E:" + File.separator + "IO.txt");
        Reader input = new FileReader(f);
        char[] c = new char[1024];
        int temp = 0;
        int len = 0;
        while ((temp = input.read()) != -1) {
            c[len] = (char) temp;
            len++;
        }
        input.close();
        System.out.println(new String(c, 0, len));
    }

拓展:通过字节缓冲流实现文件拷贝

/**
   * 通过字节缓冲流实现文件的拷贝
   *
   * @param sourcePath 源文件路径
   * @param targetPath 目标文件路径
   */
  public static void copyFileByBuffered(String sourcePath, String targetPath){
    //源文件路径
    File source = new File(sourcePath);
    //目标文件路径
    File target = new File(targetPath);

    //如果源文件不存在则不能拷贝
    if (!source.exists()) {
      return;
    }
    //如果目标文件目录不存在则创建
    if (!target.getParentFile().exists()) {
      target.getParentFile().mkdirs();
    }

    InputStream in = null;
    OutputStream out = null;
    try {
      //字节缓冲输入流和字节缓冲输出流
      in = new BufferedInputStream(new FileInputStream(source));
      out = new BufferedOutputStream(new FileOutputStream(target));

      byte[] b = new byte[1024];
      int temp = 0;
      //每次读取一个1024的字节数组
      while((temp = in.read(b)) != -1){
        //输出到文件
        out.write(b,0,temp);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      //关闭流
      try {
        if (in != null) {
          in.close();
        }
        if (out != null) {
          out.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

连接拓展:java IO学习笔记(一)File类