一.IO流简介

  1. 流是一个抽象概念,Java程序和外部设备(可以是硬盘上的文件,也可以是网络设备)之间的输入输出操作是基于流的。

    流就好比水管中的水流,具有流入和流出,类比数据的输入和输出。

    Java中流屏蔽了实际IO设备中处理数据的细节,主要用来处理设备之间的数据传输。

  2. IO流的分类

    根据数据的流向可以分为:输入流和输出流

    根据数据的类型可以分为:字节流和字符流

    Java中将所有流类型都放在了java.io包中,用于实现输入和输出功能,相关类关系如下图

二.字节流

  1. 一切皆为字节

    Java中的字节流 处理的基本单位是单个字节,一切的文件数据(文本,图片,视频等)在存储时,都是以二进制的形式保存的,都是一个字节一个字节的,传输时候也一样,所以字节流可以传输任意文件数据,所以在操作流的时候应该明确,无论使用什么流对象,其底层传输始终是二进制数据。

  2. 字节输出流(OutputStream)

    public abstract class OutputStream是字节输出流的所有类的超类,是一个抽象类,所有的字节输出流都是继承自OutputStream。

    它定义了一些共用的方法:

    • void close():关闭此输出流并释放与此流有关的所有系统资源
    • void flush():刷新此输出流并强制写出所有缓冲的输出字节。
    • void write(byte[] b):将 b.length 个字节从指定的 byte 数组写入此输出流。
    • void write(byte[] b, int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
    • abstract void write(int b):将指定的字节写入此输出流。

    OutputStream有很多子类,这里主要学习FileOutputStream,FileOutputStream是文件输出流,用于将数据写到文件。

    构造方法是:

    • FileOutputStream(File file):创建一个向指定File对象表示的文件中写入数据的文件输出流。

    • FileOutputStream(File file, boolean append):创建一个向指定File对象表示的文件中写入数据的文件输出流,其中参数append代表是否追加写入文件

    • FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。

    • FileOutputStream(String name, boolean append):创建一个向具有指定name的文件中写入数据的输出文件流,其中参数append代表是否追加写入文件

      注意:

      当创建一个流对象时,需要传入一个文件路径,在该路径下,如果没有这个文件,则会创建该文件,如果有这个文件,将会清空这个文件的数据再写入(带append参数,且append为true的则不会清空,因为它代表着追加内容)

    示例:

    import java.io.FileOutputStream;
    import java.io.IOException; public class TestFileOutputStream {
    public static void main(String[] args) throws IOException{
    // 1. 创建FileOutputStream对象
    FileOutputStream fos = new FileOutputStream("File\\a.txt"); // 写入一个字节 97 就是字符 'a'
    fos.write(97); // 写入字节数组
    byte[] bytes = "你好".getBytes();
    fos.write(bytes); // 写入字节数组,指定长度
    byte[] b = "abcdef".getBytes();
    fos.write(b, 2, 3); // 从第二位开始,写3个,就是c,d,e fos.close(); }
    }

    运行结果:

    生成文件a.txt,内容为:a你好cde

    注意:

    write调用时候是不会写换行的。如果需要换行,需要自己写入。

    不同系统的换行不同:

    Windows是\r\n

    Unix是\n

  3. 字节输入流(InputStream)

    public abstract class InputStream是字节输入流的所有类的超累,是一个抽象类,他定义了一些共用方法:

    • void close():关闭此输入流并释放与该流关联的所有系统资源。
    • abstract int read():从输入流中读取数据的下一个字节。
    • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中,返回值为每次读取到的有效字节个数。

    InputStream有很多子类,这里主要学习FileInputStream,FileInputStream是文件输入流,用于从文件中读取字节。

    构造方法是:

    • FileInputStream(File file):过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
    • FileInputStream(String name):通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

    注意:

    当创建一个输入流对象时,必须传入一个文件路径,在改路径下,如果没有该文件的话,会报FileNotFoundException

    示例:文件b.txt内容为:abcdefg

    使用int read()读取:

    import java.io.FileInputStream;
    import java.io.IOException; public class TestFileInputStream {
    public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("File\\b.txt"); // 读取一个字节
    // System.out.println(fis.read()); // 97
    // System.out.println(fis.read()); // 98
    // System.out.println(fis.read()); // 99
    // System.out.println(fis.read()); // 100
    // System.out.println(fis.read()); // 101
    // System.out.println(fis.read()); // 102
    // System.out.println(fis.read()); // 103
    // System.out.println(fis.read()); // -1 // 使用循环读
    int r;
    while ((r = fis.read()) != -1) {
    System.out.print((char)r);
    } // 输出 abcdefg fis.close();
    }
    }

    说明:

    1. 示例使用每次读取一个字节的方式从文件中读取数据,其中要注意虽然每次读取了一个自己,但是会被自动提升为int类型,所以打印出来的是97,98,99,100,101,102,103,这些是字符对应的ASCII码,当使用强制转换为char之后,就正常输出abcdefg了。
    2. 当读取到文件末尾时候,读出来的是-1

    使用int read(byte[] b)读取:

    import java.io.FileInputStream;
    import java.io.IOException; public class TestFileInputStream {
    public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("File\\b.txt"); // 读取到数组
    byte[] b = new byte[3];
    int len; while ((len = fis.read(b)) != -1) {
    System.out.print(new String(b) + " ");
    } fis.close();
    }
    }

    说明:

    1. 程序输出的结果为:abc def gef
    2. 这种输出结果是错误的,正确应该是 abc def g,因为在第三次读取时候,文件中只读取了一个字节g,然后存在了数组的第一位,因为第二次时候数组内容为def,所以第三次时候,数组的内容为gef,只改变了第一位
    3. 要修正上面的问题,要使用len,获取有效的字节。

    修正代码:

    import java.io.FileInputStream;
    import java.io.IOException; public class TestFileInputStream {
    public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("File\\b.txt"); // 读取到数组
    byte[] b = new byte[3];
    int len; while ((len = fis.read(b)) != -1) {
    System.out.print(new String(b, 0, len) + " " );
    } fis.close();
    }
    }

三.字符流

​ 当使用字节流读取文本本间时,可能会存在一个小问题,就是遇到中文字符时候,可能不会显示完整的字符,因为一个中文字符可能占用多个字符存储,所以Java中提供了字符流类,以字符为单位读写数据。

  1. 字符输出流(Writer)

    public abstract class Writer是用于写出字符流的所有类的超类,是一个抽象类,它定义了字节输出流的基本共性能方法:

    • void write(int c):写入单个字符。
    • void write(char[] cbuf):写入字符数组。
    • abstract void write(char[] cbuf, int off, int len):写入字符数组的某一部分。
    • void write(String str): 写入字符串。
    • void write(String str, int off, int len):写入字符串的某一部分。
    • void flush():刷新该流的缓冲。
    • void close():关闭此流,但要先刷新它。

    FileWriter类是写字符到文件的类,构造时使用系统默认的字符编码和默认字节缓冲区。

    构造方法:

    • FileWriter(File file):根据给定的 File 对象构造一个 FileWriter 对象。
    • FileWriter(File file, boolean append):根据给定的 File 对象构造一个 FileWriter 对象。其中append参数代表是否追加。
    • FileWriter(String fileName):根据给定的文件名构造一个 FileWriter 对象。
    • FileWriter(String fileName, boolean append):根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

    基本写数据示例:

    import java.io.FileWriter;
    import java.io.IOException; public class TestFileWriter {
    public static void main(String[] args) throws IOException{
    FileWriter fw = new FileWriter("File\\c.txt"); fw.write(97); // 写第一个字符
    fw.write('b'); // 写第二个字符
    fw.write('c'); // 写第三个字符 fw.close();
    }
    }

    注意:

    1. 如果没有调用close方法,写入的数据只是保存到了缓冲区,并没有写到文件中,这一点和FileOutputStream不一样,或者写完调用flush()刷新缓冲区。
    2. 最后如果调用了close(),可以不调用flush()刷新,因为close()会先刷新缓冲,再关闭流。
    3. 即使使用了flush()刷新了缓冲,写出了数据,但最后还是要调用close()方法来释放资源。

    其他方法写数据示例:用法和FileOutputStream类似

    import java.io.FileWriter;
    import java.io.IOException; public class TestFileWriter {
    public static void main(String[] args) throws IOException{
    FileWriter fw = new FileWriter("File\\c.txt"); // 写字符数组
    char[] chars = "我是中国人".toCharArray();
    fw.write(chars); // 从索引1开始,写2个字节
    fw.write(chars, 1, 2); // 写字符串
    String str = "你好吗"; fw.write(str); fw.write(str, 1, 1); fw.close();
    }
    }

    注意:

    字符流只能操作文本文件,不能操作图片,视频等非文本文件(因为是二进制存储的,要用字节流)

Java IO---字节流和字符流的更多相关文章

  1. JAVA IO 字节流与字符流

    文章出自:听云博客 题主将以三个章节的篇幅来讲解JAVA IO的内容 . 第一节JAVA IO包的框架体系和源码分析,第二节,序列化反序列化和IO的设计模块,第三节异步IO. 本文是第一节.     ...

  2. Java IO 字节流与字符流 (三)

    概述 IO流用来处理设备之间的数据传输 Java对数据的操作时通过流的方式 Java用于操作流的对象都在IO包中 流按操作的数据分为:字节流和字符流 流按流向不同分为:输入流和输出流 IO流常用基类 ...

  3. Java IO 字节流与字符流 (二)

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...

  4. Java IO 字节流与字符流 (五)

    Java的IO流分为字符流(Reader,Writer)和字节流(InputStream,OutputStream),字节流顾名思义字节流就是将文件的内容读取到字节数组,然后再输出到另一个文件中.而字 ...

  5. java中字节流与字符流的区别

    字节流 在I/O类库中,java.io.InputStream和java.io.OutputStream分别表示字节输入流和字节输出流,它们都是抽象类,不能实例化,数据流中的最小单位是字节,所以叫做字 ...

  6. Java中字节流和字符流的比较(转)

    字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢? 实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操 ...

  7. java中字节流和字符流的区别

    流分类: 1.Java的字节流   InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先.2.Java的字符流  Reader是所有读取字符串输入流的祖先,而 ...

  8. java IO(三):字符流

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  9. Java中字节流和字符流复制文件

    字节流和字符流复制文件的过程: 1.建立两个流对象 绑定数据源和目的地 2.遍历出需复制的文件写入复制过后的新文件中(只不过是遍历的时候是区分字节和字符的) 3.访问结束后关闭资源 字节流复制文件: ...

  10. 14、IO (字节流、字符流)

    输入和输出 * A:输入和输出 * a: 参照物 * 到底是输入还是输出,都是以Java程序为参照 * b: Output * 把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作 ...

随机推荐

  1. BareTail(日志查看工具)

    官网:http://www.baremetalsoft.com/baretail/index.php 在看log文件时,当日志有新增时,会自动滚动到最新的那一行,对于查看实时日志有作用.

  2. opencv 程序

    IplImage结构中的一个元素:struct _IplROI *roi; //图像感兴趣区域,当该值非空时,只对该区域进行处理 .   ROI :Region of Interest,表示感兴趣的区 ...

  3. JDK1.8 LocalDate 使用方式;LocalDate 封装Util,LocalDate工具类(四)

    未完待续 ........ 前言:       加班了好几天,终于结束上一个坑的项目了,项目交接人员全部离职,代码一行注释没有,无人问津的情况下,完成了项目,所以好的规范真的很重要. 继续日期改写 一 ...

  4. python yield实现协程(生产者-消费者)

    def customer(): r="" while True: n=yield r#,接收生产者的消息,并向消费者发送r print("customer receive ...

  5. ESA2GJK1DH1K基础篇: 测试APP使用SmartConfig绑定Wi-Fi 设备并控制设备

    前言 实现功能概要 STM32控制WI-Fi模块以AT指令TCP透传方式连接MQTT服务器, 实现MQTT通信控制. 测试准备工作(详细下载步骤请参考 硬件使用说明 ) 一,下载单片机程序 二,安装A ...

  6. Codeforces Round 563 (Div. 2) 题解

    自己开了场镜像玩. 前三题大水题.D有点意思.E完全不会.F被题意杀了……然而还是不会. 不过看过(且看懂)了官方题解,所以这里是六题题解齐全的. A 水题.给原序列排序,如果此时合法则直接输出,否则 ...

  7. 浅谈Asp.Net中的几种传值方式

    一.使用Querystring Querystring是一种非常简单的传值方式,其缺点就是会把要传送的值显示在浏览器的地址栏中,并且在此方法中不能够传递对象.如果你想传递一个安全性不是那么太重要或者是 ...

  8. DJI Terra+EasyEarth让数据获取与应用无缝衔接

    大数据时代对地理信息数据的获取与应用提出了更高的要求: ⏩低成本.全要素.高效获取 ⏩数据采集.处理到应用无缝衔接 DJI Terra大疆智图 DJI Terra大疆智图是一款提供自主航线规划.飞行航 ...

  9. 某邀请赛misc key家用完整版

    目录 题目下载 提示 解题过程 1.提取RGB值 2.找到key 3.循环异或,得到flag 反思 题目下载 题目名:key 提示 提取钥匙中特殊颜色的RGB循环异或KEY值 解题过程 1.提取RGB ...

  10. C# IE浏览器操作类

    using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropSe ...