Java基础(八)——IO流1_字节流、字符流-编程思维

一、概述

1、介绍

  I/O是 Input/Output 的缩写,IO流用来处理设备之间的数据传输,如读/写文件,网络通讯等。Java对数据的操作是通过流的方式进行。java.io 包下提供了各种"流"类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
  输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

 

2、分类

  按操作数据单位不同分为: 字节流 (8 bit),字符流 (16 bit)。
  按数据流的流向不同分为: 输入流,输出流。
  按流的角色的不同分为: 节点流(文件流),处理流。

  节点流(文件流):直接作用在文件上,从数据源或目的地读写数据。
  处理流:不直接作用在文件上,不直接连接到数据源或目的地,而是"连接"在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

  节点流:

  处理流:

3、IO流体系

  四个顶层的抽象基类。

  由这四个类派生出来的子类名称都是以其父类作为子类名的后缀。例:InputStream的子类FileInputStream,Reader的子类FileReader。
  IO流的体系如下:重点掌握高亮部分。

  【访问文件】是节点流(文件流),其他(除了抽象基类)都是处理流。

二、字符流

1、FileReader(输入)

  用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在FileInputStream上构造一个InputStream。
  read():一次读一个字符,指针会指向下一个字符。读到末尾返回-1。
  代码示例:读文件

 1 // 文件:F:\\hello.txt
 2 // 内容:helloworld123中国人1
 3 public class Main {
 4     public static void main(String[] args) {
 5         try (FileReader fr = new FileReader(new File("F:\\hello.txt"));) {
 6             int data;
 7             while ((data = fr.read()) != -1) {
 8                 System.out.print((char) data);
 9             }
10         } catch (Exception e) {
11         }
12     }
13 }
14 
15 // 结果
16 helloworld123中国人的

  read(char[] buff):一次读 buff.length 个字符,返回读取的个数。读到末尾返回-1。
  代码示例:错误的写法

 1 // 文件:F:\\hello.txt
 2 // 内容:helloworld123中国人1
 3 public class Main {
 4     public static void main(String[] args) {
 5         try (FileReader fr = new FileReader(new File("F:\\hello.txt"));) {
 6             char[] buff = new char[5];
 7             int len;
 8 
 9             while ((len = fr.read(buff)) != -1) {
10                 // 方式一:
11                 for (char c : buff) {
12                     System.out.print(c);
13                 }
14 
15                 // 方式二:
16                 // String str = new String(buff);
17                 // System.out.print(str);
18             }
19         } catch (Exception e) {
20         }
21     }
22 }
23 
24 // 结果.方式一 和 方式二都是
25 helloworld123中国人13中国

  代码示例:正确的写法

 1 // 文件:F:\\hello.txt
 2 // 内容:helloworld123中国人1
 3 public class Main {
 4     public static void main(String[] args) {
 5         try (FileReader fr = new FileReader(new File("F:\\hello.txt"));) {
 6             char[] buff = new char[5];
 7             int len;
 8 
 9             while ((len = fr.read(buff)) != -1) {
10                 // 方式一:
11                 for (int i = 0; i < len; i++) {
12                     System.out.print(buff[i]);
13                 }
14 
15                 // 方式二:从 buff 的下标 0 开始取字符,取 len 个
16                 // String str = new String(buff, 0, len);
17                 // System.out.print(str);
18             }
19         } catch (Exception e) {
20         }
21     }
22 }
23 
24 // 结果
25 helloworld123中国人1

  深刻理解 read(char[] buff) 方法:一次读进 buff.length 个字符,打印。读取下次的时候,上次读取的字符其实还在字符数组中,所以最后"人1"只覆盖了上一次的前两个字符,使得最后字符数组里是"人 1 3 中 国"。

2、FileWriter(输出)

  构造方法必须明确被操作的文件,若指定目录下不存在,会被创建;若存在,会被覆盖。相关API如下:

  new FileWriter(String fileName):在指定目录下创建
  new FileWirter(String fileName, boolean append):是否为追加数据
  void write(String int):重载,将字符串写入到流中
  void write(char[] buff):写入字符数组
  void wirte(char[] buff, int off, int len):写入字符数组的某一部分
  void flush():刷新流,流可以继续使用
  void close():先刷新流,关闭流,流不可以继续使用

  注:通过write()写入换行用 \r\n,对应的字节为 13 10

  代码示例:写文件

 1 public class Main {
 2     public static void main(String[] args) {
 3         // 默认不追加,覆盖原有的文件内容
 4         try (FileWriter fw = new FileWriter(new File("F:\\hello.txt"));) {
 5 
 6             // 表示在原有文件内容的基础上追加
 7             // FileWriter fw = new FileWriter(new File("F:\\hello.txt"), true);
 8             fw.write("我有a dream!\n");
 9             fw.write("you need to have a dream!");
10 
11             // fw.flush();
12         } catch (Exception e) {
13         }
14     }
15 }

3、复制文件

  代码示例:字符流复制文本文件

 1 public class Main {
 2     public static void main(String[] args) {
 3         try (FileReader fr = new FileReader(new File("F:\\hello.txt"));
 4              FileWriter fw = new FileWriter(new File("F:\\hello_copy.txt"));) {
 5 
 6             char[] buff = new char[5];
 7             int len;
 8 
 9             // 一次读出len个字符到buff.
10             while ((len = fr.read(buff)) != -1) {
11                 fw.write(buff, 0, len);
12                 fw.flush();
13             }
14         } catch (Exception e) {
15         }
16     }
17 }

  注:不能使用字符流来处理图片,视频等字节数据。

三、字节流

1、FileInputStream(输入)

  基本用法和字符流一样。
  代码示例:读文件,可能出现乱码。

 1 // 文件:F:\\hello.txt
 2 // 内容:helloworld123中国人1
 3 public class Main {
 4     public static void main(String[] args) {
 5         try (FileInputStream fis = new FileInputStream(new File("F:\\hello.txt"));) {
 6             // fis.available():返回文件字节数
 7             byte[] buffer = new byte[5];
 8             int len;
 9 
10             // 按字节来读取
11             while ((len = fis.read(buffer)) != -1) {
12                 String str = new String(buffer, 0, len);
13                 System.out.print(str);
14             }
15         } catch (Exception e) {
16 
17         }
18     }
19 }
20 
21 // 结果,有乱码.原因就是一个汉字占两字节,被分割了.
22 helloworld123��国���1

2、FileOutputStream(输出)

  基本用法和字符流一样,不同于在写入时不需要flush()。

  void write(int b):一次写入一个字节
  void write(byte[] b):写入一个字节数组
  void write(byte[] b, int off, int len):写入一个字节数组,off开始,len字节数

  代码示例:写文件

 1 public class Main {
 2     public static void main(String[] args) {
 3         try (FileOutputStream fos = new FileOutputStream(new File("F:\\hello.txt"));) {
 4 
 5             fos.write("我有a dream!\n".getBytes());
 6             fos.write("you need to have a dream!".getBytes());
 7 
 8         } catch (Exception e) {
 9         }
10     }
11 }
12 
13 // 结果,有乱码.
14 鎴戞湁a dream!
15 you need to have a dream!

  总结:因为一个汉字占两个字节。所以,
  字符流,适用于读写文本文件。不适用于字节流,容易出现乱码。
  字节流,适用于读写二进制文件,比如图片,音频,视频等。

3、复制文件

  代码示例:用字节流处理非文本文件(图片,视频等)。字节流复制图片。

 1 // 文件:F:\\hello.PNG
 2 public class Main {
 3     public static void main(String[] args) {
 4         try (FileInputStream fis = new FileInputStream(new File("F:\\hello.PNG"));
 5              FileOutputStream fos = new FileOutputStream(new File("F:\\hello_1.PNG"));) {
 6 
 7             byte[] buffer = new byte[5];
 8             int len;
 9 
10             // 一次性读一个 len 个字节到buffer. len <= buffer
11             while ((len = fis.read(buffer)) != -1) {
12                 fos.write(buffer, 0, len);
13             }
14         } catch (Exception e) {
15         }
16     }
17 }
18 
19 // 此代码用于复制 3.64G 的文件花费 56.574s

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://www.cnblogs.com/originator/p/15736289.html

javax.validation @Valid注解实现参数校验-编程思维

  在 RESTful 的接口服务中,存在各种各样的请求参数。在跳入业务处理环节之前,通常会有一个基础的数据验证的机制,待验证通过,结果无误后,请求参数才会传递到正式的业务处理中。 maven 依赖引入   Spring Boot项目中,Validation校验需要引入的两个包: <dependency

Java 压缩成zip文件-编程思维

综述 在《 把多个文件打包压缩成tar.gz文件并解压的Java实现》中介绍了如何把文件压缩车gz文件,这里介绍如何把文件压缩成zip文件。支持如下方式的压缩: 压缩单个文件 压缩文件夹下的所有文件 源码 话不多说,直接上源代码: /** * 压缩指定文件夹中的所有文件,生成指定名称的zip压缩包

面试造火箭系列,栽在了cglib和jdk动态代理-编程思维

“喂,你好,我是XX巴巴公司的技术面试官,请问你是张小帅吗”。声音是从电话那头传来的 “是的,你好”。小帅暗喜,大厂终于找上我了。 “下面我们来进行一下电话面试吧,请先自我介绍一下吧” “balabalabla...”小帅把之前的经历大概描述了一下 “嗯,经历很丰富呀,接下来咱们来聊聊技术吧,请问cglib和jdk动态

Java基础(八)——IO流2_缓冲流、转换流-编程思维

一、缓冲流 1、介绍   缓冲流:不能直接作用在文件上,需要包一层,它是一种处理流。用于提高文件的读写效率。它在流的基础上对流的功能进行了增强。提高读写速度的原因:内部提供了一个缓冲区。缺省使用 8192 个字节(8Kb)的缓冲区 。  源码示例:BufferedInputStream 1 public class

Java开发工程师最新面试题库系列——Web部分(附答案)-编程思维

WEB 如果你有更好的想法请在评论区留下您的答案,一起交流讨论 http和https有什么区别? 答:http是超文本传输协议,默认端口是80。https是安全的默认端口是443;http是明文传输,存在安全隐患,Https在Http的基础上增加了SSL/TLS协议,需要依靠整数来验证服务器身份,并且对服务器与客户端