06IO流

IO

概述

对于任何程序设计语言而言,输入输出( I/O )系统都是比较复杂的而且是比较核心的。程序运行需要数据,数据的获取往往需要跟外部系统进行通信,外部系统可能是文件、数据库、其他程序、网络、IO设备等等。我们可以发现,外部系统比较复杂多变,那么我们有必要通过某种手段进行抽象、屏蔽外部的差异。我们希望通过某种技术实现对所有外部系统的输入输出操作, java.io 包为我们提供了相关的API,这就是我们这章所要学习的技术。

数据源

data source , 提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网
络连接、IO设备。

数据源就像水箱,流就像水管中流着的水流,程序就是我们最终的用户。 流是一个抽象、动态的概念,是一连串连续动态的数据集合。

流的概念

Stream:名词,水流,趋势。动词:流出,流动

数据源就像水箱,流就像水管中流着的水流,程序就是我们最终的用户。 流是一个抽象、动态的概念,是一连串连续动态的数据集合。

image-20230704134155465

IO流的种类

IO流很庞大,从不同角度进行分类,常见大分类字符流和字节流。

处理的数据单元

按处理数据单位分为:字节流和字符流。 处理数据是音频、视频、doc、文本等一切为字节流 , 仅能处理文本的为字符流 。 字节流和字符流的用法几乎完全一致,区别在于它们所操作的数据单元不同,字节流(8位)、字符流(16 位),字节流主要由 InputStreamOutputStream 作为基类,字符流主要由ReaderWriter 作为基类。

  • 字节流:按照字节读取数据(InputStream、OutputStream)
  • 字符流:按照字符读取数据(Reader、Writer)

流向分类

输入流和输出流。 从节点到 java 内存 叫输入流, 从 java 内存到节点 叫输出流。Java 的输入流主要由 InputStream 和 Reader 作为基类,输出流主要由 OutputStream 和 Writer 作为基类。 (一切以程序为中心)

  • 输入流:数据源到程序(InputStream、Reader读进来)
  • 输出流:程序到目的地(OutPutStream、Writer写出去)

功能分类

节点流处理流直接从/向一个特定的I/0设备(磁盘、网络等)读写数据的流称为节点流,也常被称为低级流。 处理流则对于一个已存在的节点流进行连接或封装,常被称为高级流(装饰器设计模式)。处理流为增强、提升性能的,本身不具备直接操作节点的能力。如扩音器,就是放大声音的。 节点流处于io操作的第一线,所有操作必须通过他们进行;处理流可以对其他流 进行处理(提高效率或操作灵活性)。

  • 节点流:可以直接从数据源或目的地读写数据。
  • 处理流:不直接连接到数据源或目的地,是处理流的流。通过对其他流的处理提高程序的性能。

体系图

image-20230704135533957

FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用
FileWriter。

image-20230704135644554

使用流抽象的概念,屏蔽了实际的 I/O设备中处理数据的细节。

IO操作步骤

在进行任何操作之前,首先要明确目的(读还是写),找准源头(读取),找准目的地(写出)。

  1. 建立联系 :这一步骤是为了获取流,如果此时是文件,则需要将文件抽象到内存形成对象。后期也可以是其他的数据源
  2. 选择流:从读写、数据单元和功能方面考虑。输入|输出,字节|字符,结点流|处理流。
  3. 执行操作:该读就读,该写就写。考虑是一次性完成还行需要循环。
  4. 释放资源:程序中打开的文件 IO 资源不属于内存中的资源,垃圾回收无法回收,需要显示关闭。

字符集和编码格式

字符集

字符
计算机科学和信息科学中字符(character,或译为字元)是一个信息单位,通常来说就是一个字母、一个汉字、一个数字、一个标点符号。另外,还存在着一些控制字符,通常是不可打印的(不可见的,或称为是功能性的),有特定用途,以及emoji(绘文字)之类特殊的符号。

字符集
字符集(character set)指的是指定若干字符组成的一个集合,通常这个集合具有一定的规模和合理性,比如囊括一个国家或地区日常使用的文字字符、数字、标点符号和控制字符等。不同的国家和地区由于历史和文化的原因,使用不同的语言文字,因此存在各种不同的字符集。

字符编码
字符编码(character encoding)是把字符集中的字符映射为指定集合中某一对象(例如数字系统中表示为某个特定的二进制数),以便文本在计算机中存储和在通信网络传递。

乱码
有字符的编码,就有相应的解码,解码出错就会导致乱码问题。乱码指的是由于使用不同的字符集或字符编码方式,导致显示的部分或全部字符无法被正常的阅读,如常见的文本、网页、邮件乱码。

编码格式

计算机中存储信息的最小单元是一个字节(byte)即 8 个 bit,所以能表示的字符范围是 0~255 个。人类要表示的符号太多,无法用一个字节来完全表示。

ASCII 码

学过计算机的人都知道 ASCII 码,总共有 128 个,用一个字节的低 7 位表示,0~31 是控制字符如换行回车删除等;32~126 是打印字符,可以通过键盘输入并且能够显示出来。

ISO-8859-1

128 个字符显然是不够用的,于是 ISO 组织在 ASCII 码基础上又制定了一些列标准用来扩展 ASCII 编码,它们是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所有应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。

GB2312

它的全称是《信息交换用汉字编码字符集 基本集》,它是双字节编码,总的编码范围是 A1-F7,其中从A1-A9 是符号区,总共包含 682 个符号,从 B0-F7 是汉字区,包含 6763 个汉字。

GBK

全称叫《汉字内码扩展规范》,是国家技术监督局为 windows95 所制定的新的汉字内码规范,它的出现是为了扩展 GB2312,加入更多的汉字,它的编码范围是 8140~FEFE(去掉 XX7F)总共有 23940 个码位,它能表示 21003 个汉字,它的编码是和 GB2312 兼容的,也就是说用 GB2312 编码的汉字可以用 GBK 来解码,并且不会有乱码。

GB18030

全称是《信息交换用汉字编码字符集》,是我国的强制标准,它可能是单字节、双字节或者四字节编码,它的编码与 GB2312 编码兼容,这个虽然是国家标准,但是实际应用系统中使用的并不广泛。

BIG5

繁体中文编码方式。

UTF-16

说到 UTF 必须要提到 Unicode(Universal Code 统一码),ISO 试图想创建一个全新的超语言字典,世界上所有的语言都可以通过这本字典来相互翻译。可想而知这个字典是多么的复杂,关于 Unicode 的详细规范可以参考相应文档。Unicode 是 Java 和 XML 的基础,下面详细介绍 Unicode 在计算机中的存储形式。

UTF-16 具体定义了 Unicode 字符在计算机中存取方法。UTF-16 用两个字节来表示 Unicode 转化格式,这个是定长的表示方法,不论什么字符都可以用两个字节表示,两个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表示字符非常方便,每两个字节表示一个字符,这个在字符串操作时就大大简化了操作,这也是 Java 以 UTF-16 作为内存的字符存储格式的一个很重要的原因。

UTF-8

UTF-16 统一采用两个字节表示一个字符,虽然在表示上非常简单方便,但是也有其缺点,有很大一部分字符用一个字节就 可以表示的现在要两个字节表示,存储空间放大了一倍,在现在的网络带宽还非常有限的今天,这样会增大网络传输的流量,而且也没必要。而 UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以是由 1~6 个字节组成。

字符集和字符编码的关系
字符集是书写系统字母与符号的集合,而字符编码则是将字符映射为一特定的字节或字节序列,是一种规则。通常特定的字符集采用特定的编码方式(即一种字符集对应一种字符编码,但Unicode不是,它采用现代的模型),因此基本上可以将两者视为同义词。

基本输入流

用来读取的,将其他地方的数据读取到Java内存的流称为输入流。可以是字节也可以是字符,字节流和字符流的操作方式几乎完全一样,只是操作的数据单元不同而已 。字节流可以操作所有文件,字符流仅操作纯文本。

抽象类:InputStreamReader

InputStreamReader是所有输入流的基类,它们是两个抽象类,是所有输入流的模版,其中定义的方法在所有输入流中都可以使用。

在InputStream种常用如下几个方法:

Modifier and Type Method and Description
void close() 关闭此输入流并释放与流相关联的任何系统资源。
abstract int read() 从输入流读取数据的下一个字节。
int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区 b
int read(byte[] b, int off, int len) 从输入流读取最多 len 字节的数据到一个字节数组。

在Reader中常用如下几个方法

Modifier and Type Method and Description
abstract void close()关闭流并释放与之相关联的任何系统资源。
int read() 读一个字符
int read(char[] cbuf) 将字符读入数组。
abstract int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。

对比InputStream和Reader 所提供的方法,可以看出这两个基类的功能基本相似。在读取文件时返回结果为 -1 时表明到了输入流的结束点。 InputStream 和 Reade 都是抽象的,不能直接创建它们的实例,可以使用它们的子类。

文件节点类: FileInputStream 和 FileReader

FileInputStream 和 FileReader,它们都是节点流,直接和指定文件关联。 操作方式基本一致。而且都使用父类中的方法即可。

单个字节读取
public class TestFileIO {
   
    public static void main(String[] args) {
   
        //创建file对象,建立联系
        File file = new File("D:\\test.txt");
        //选择流
        FileInputStream fileInputStream = null;
        try {
   
            fileInputStream = new FileInputStream(file);
            //计算实际读取的字节数
            long length = file.length();
            System.out.println(length);
            //循环读取
            long num = 0;
            while(num<length){
   
                char</
  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值