IO流(3)- 转换流与打印流

news2024/11/19 19:21:36

目录

1. 为什么要用到转换流?

2. 字符输入转换流(重点掌握)

3. 字符转换输出流(理解即可)

4. 认识打印流

5. 打印流的作用

6. PrintStream(字节打印流)如何使用?

7. PrintStream 内部没有缓冲区

 8. PrintWriter(字符打印流)如何使用?

9. PrintStream和PrintWriter的区别?

10. 打印流与常用的 System.out.println() 有什么关系?


1. 为什么要用到转换流?

我们都知道,字符集编码的格式多种多样,有UTF-8,UTF-16,GBK等等很多种,那么在读取的时候也会有差异,例如我们的IDEA编码格式为UTF-8,当我们去读取一个编码格式为GBK的文件时,即便是采用字节流全部读取出来,也会读取到一堆乱码。

如下所示,我在项目目录下创建一个名为 test02.txt 的文件,随便填写一些内容,将该文件的编码格式改为GBK。

然后我们去另一个编码为UTF-8 的类中编写一个 main 函数,读取该文件中的内容,代码如下所示

public static void main(String[] args) {
        try (
                // 创建 IO流 管道,得到原始字节流对象 is
                Reader r = new FileReader("user-service/test02.txt");

                // 这里我们可以多做一步,将is 对象加工成缓冲流对象提高读写效率
                BufferedReader br = new BufferedReader(r);
        ){

            // 定义一个字符串接收读取到的文件内容
            String line;

            // 将读取到每一行文件内容赋值给字符串 line,这里其实是在底层新建字符串
            while ( (line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 运行上述方法,可以得到如下结果

在控制台,我们可以看到文件中的内容虽然被读取出来,却含有一部分乱码,原因就是因为我们读取的文件编码格式为 GBK,而我们 编写的main 方法编码格式为 UTF-8,编码格式不匹配,就会出现乱码问题。

这还仅仅只是向内存中读数据(即输入流编码格式的问题),如果从内存向硬盘写数据,想要编写的文件编码格式也不一样,该怎么办呢?有没有什么办法可以解决这个问题呢?这就需要用到我们的转换流。

2. 字符输入转换流(重点掌握)

字符转换输出流,在我们开发时还是较为常用的,因为我们在编码时,可能会遇到各种各样类型的文件,需要读入到内存进行处理,这个时候我们就需要使用字符输入转换流进行编码修改。

如图所示,字符输出转换流有两个构造器,我们常用的是第二个圈起来的,他的参数列表中第二个参数可以传入一个String 类型的编码字符串,这里就是要写我们所读取文件的编码格式。

再回到刚才的那个问题,我们使用字符转换输入流来试一下看看是否能够解决乱码问题,我已经写好了代码如下

public static void main(String[] args) {
        try (
                // 创建 IO流 管道,得到原始字节流对象 is
                InputStream is = new FileInputStream("user-service/test02.txt");

                // 将is 字节流转换成字符输入流对象
                InputStreamReader isr = new InputStreamReader(is, "GBK");

                // 这里我们可以多做一步,将isr 对象加工成缓冲流对象提高读写效率
                BufferedReader br = new BufferedReader(isr);
        ){

            // 定义一个字符串接收读取到的文件内容
            String line;

            // 将读取到每一行文件内容赋值给字符串 line,这里其实是在底层新建字符串
            while ( (line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行此方法,我们到控制台查看输出结果

 此时可以看到,刚才的乱码问题已经得到了解决。

这里需要提醒一点,在JDK11以后,这种方法就已经用的不多了。因为在JDK11以后,FileReader中又新增了一种构造器,可以额外添加一个字符集编码参数,所以FileReader也可以用作转换流了,但这是在JDK11以后,用JDK8的还要使用 InputStreamReader 转换流。

3. 字符转换输出流(理解即可)

字符转换输出流相比于字符转换输入流,用的就没有那么多了,所以理解即可,但能熟练掌握最好。

刚才我们也他提到了,字符输入转换流可以控制改变写入到内存中的文件编码格式,那么字符转换输出流也是同样的道理,可有控制我们输出数据的编码格式。

如下图中即为字符转换输出流的构造器,我们常用的同样也是第二个可以传递编码格式参数的构造方法。

下面我简单做个小案例,将刚才 字符转换输入流中的test02.txt 文件中的内容复制一份,但编码格式仍然采用 GBK的形式

public static void main(String[] args) {
        try (
                // 创建 IO 输入流管道,得到原始字节流对象 is
                InputStream is = new FileInputStream("user-service/test02.txt");

                // 将is 字节流转换 成 字符转换输入流对象
                InputStreamReader isr = new InputStreamReader(is, "GBK");

                // 这里我们可以多做一步,将isr 对象加工成缓冲流对象提高 读的效率
                BufferedReader br = new BufferedReader(isr);

                // 创建 IO 输入流管道,得到原始字节流对象 os
                OutputStream os = new FileOutputStream("user-service/test03.txt");

                // 将os 字节流转换成字符转换输出流对象
                OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");

                // 这里我们可以多做一步,将osw 对象加工成缓冲流对象提高 写的效率
                BufferedWriter bw = new BufferedWriter(osw);

        ){

            // 定义一个字符串接收读取到的文件内容
            String line;

            // 将读取到每一行文件内容赋值给字符串 line,这里其实是在底层新建字符串
            while ( (line = br.readLine()) != null){
                osw.write(line,0,line.length());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行上述代码,我们都可以在项目木块中找到已经被新建出来的test03.txt文件

这里需要提醒一点,在JDK11以后,这种方法就已经用的不多了。因为在JDK11以后,FileWriter中又新增了一种构造器,可以额外添加一个字符集编码参数,所以FileWriter也可以用作转换流了,但这是在JDK11以后,用JDK8的还要使用 OutputStreamWriter 转换流。

4. 认识打印流

如下图所示,打印流一共有两个,一个是PrintStream,一个是PrintWriter,分别是OutputStream与Writer的子类。

5. 打印流的作用

打印流的作用其实很简单,我们知道,我们使用字节流在打印数据时,如果输出数字97,那么它实际打印的并不是97,而是97对应的ASCLL码表中的字母,就是a;

如果我们真的只是想打印数字97,就可以使用打印流,它可以实现我们写什么它就打印什么的功能。

打印流分为字节打印流与字符打印流两种;

此外,打印流是不操作数据源的,只能操作目的地。

6. PrintStream(字节打印流)如何使用?

下图即为PrintStream提供的构造器,字节打印流默认自动刷新

 这里还有PrintStream常用的两个方法

PrintStream的使用非常简单,我们只需要直接创建它的对象即可,如下代码所示

public static void main(String[] args) {
        try (
                PrintStream ps = new PrintStream("user-service/test04.txt");
        ){
            ps.print(97);
            ps.print("abcdefg");
            ps.println("中国万岁");
            ps.println(88.888);
            ps.println(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行此方法,程序会自动创建名为 test04.txt 的文件,可以看到,这里可以添加诸多内容,证书,字符串,浮点数,布尔类型都可以加入,我们打开文件查看如下,可以看到添加成功

7. PrintStream 内部没有缓冲区

PrintStream 字节流底层没有缓冲区,开不开自动刷新都一样。

 8. PrintWriter(字符打印流)如何使用?

其实从使用上来讲,PrintStream与PrintWriter没有什么本质的区别,它们的功能都是为了打印数据,但PrintWriter毕竟是字符输出流,所以它可以打印字符串,这里用法就不再作演示了,几乎和PrintStream一摸一样。

但有一点,字符打印流自动刷新需要开启,不是默认开启的。

9. PrintStream和PrintWriter的区别?

(1)从功能上来讲,PrintStream和PrintWriter都是一样的,都是使用方便,性能高效,这也是它们的核心功能。

(2)PrintStream继承字节输出流OutputStream,因此支持写字节数据的方法。

(3)PrintWriter继承字符输出流Writer,因此支持写字符数据。

10. 打印流与常用的 System.out.println() 有什么关系?

我们知道,System.out.println() 是我们在编写代码时常常用到的一个打印语句,那么它与打印流有没有什么内在联系呢?

这里是有的哦!

其实 System 是我们Java中的一个类,我们打开它的源码看一下

往下翻阅,可以看到两个静态变量,err 和 out,其中 out 是我们最常用的,他就是 System.out.println 中的那个out

静态变量的调用方式也是 类名.静态变量;

System.out 就是获取了一个打印流的对象,这个流的对象时不需要我们自己去创建的,而是虚拟机在启动时自动帮我们创建的,而且这个打印流对象默认指向了控制台,而不是文件。

我们可以使用 PrintStream 创建一个对象接收这个对象,来试一下

从IDEA 的提示中就可以看到,接收的这个对象可以调用 PrintStream 的方法,我们随便打印一个字符串123,运行此方法,就会得到如下图所示结果,可以发现,此对象的默认指向就是我们的控制台。

其实这个流有一个专门的名称,叫做系统中的标准输出流。而且不能把它关闭,因为你一旦关闭,就无法继续在控制台打印内容了,如下所示,各位一看就懂了

因此要记住,System.out 是一个打印流对象,默认指向我们的控制台输出,而且不要关闭!​​​​​​​

未完待续......

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/830706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go -- 测试 and 项目实战

没有后端基础,学起来真是费劲,所以打算速刷一下,代码跟着敲一遍,有个印象,大项目肯定也做不了了,先把该学的学了,有空就跟点单体项目,还有该看的书.... 目录 🍌单元测试…

【LeetCode】【数据结构】单链表OJ常见题型(二)

👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言: 【LeetCode】面试题02.04. 分割链表 【Lee…

Unity实现物体上下漂浮旋转效果

效果展示 代码(直接挂载在物体上就可以了) using System.Collections; using System.Collections.Generic; using UnityEngine;public class FloatingObject : MonoBehaviour {public float amplitude 0.5f; // 上下移动的幅度public float frequency …

C# OpenCvSharp 去水印 图像修复

效果 项目 VS2010.net4.0OpenCvSharp3 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System…

简单了解一下vue-router是什么

要学习vue-router就要先知道这里的路由是什么&#xff1f;为什么我们不能像原来一样直接用<a></a>标签编写链接哪&#xff1f;vue-router如何使用&#xff1f;常见路由操作有哪些&#xff1f;等等这些问题&#xff0c;就是本篇要探讨的主要问题。 vue-router是什么…

【二叉树进阶】二叉树的前中后序遍历(非递归迭代实现)

文章目录 1. 二叉树的前序遍历1.1 思路分析1.2 AC代码 2. 二叉树的中序遍历2.1 思路分析2.2 AC代码 3. 二叉树的后序遍历3.1 思路13.2 思路1AC3.3 思路23.4 思路2AC 1. 二叉树的前序遍历 题目链接: link 不用递归&#xff0c;用迭代算法如何实现对二叉树的前序遍历&#xff1f…

linux作业

1.简述静态网页和动态网页的区别 (1).程序是否在服务器端运行&#xff0c;是重要标志。 (2).编程技术不同。静态网页和动态网页主要根据网页制作的语言来区分。 (3).被搜索引擎收录情况不同。 (4).用户访问速度不同。 (5).制作和后期维护工作量不同。 2. 简述 Webl.0 和 …

嵌入式pc技术的特点有哪些?

嵌入式PC技术是将计算机硬件和软件嵌入到各种设备中的一种技术&#xff0c;它具有低功耗、高效率、小型化、易于集成等优点&#xff0c;广泛应用于工业自动化、医疗设备、电力、通信、家用电器、物联网等领域&#xff0c;成为新时代工业生产和社会生活必不可少的技术之一。 嵌入…

Python基本数据类型之散列类型详解

前言&#xff1a; python的基本数据类型可以分为三类&#xff1a;数值类型、序列类型、散列类型&#xff0c;本文主要介绍散列类型。 一、散列类型 散列类型&#xff1a;内部元素无序&#xff0c;不能通过下标取值 1&#xff09;字典&#xff08;dict&#xff09;&#xff…

SAP 特殊采购类型52简介

特殊采购类型52简介-52 直接生产/收集订单可以在物料主数据中进行设置或者在BOM中进行设置, 所谓“直接生产”,是相对于一般的“间接生产”模式而言的。在我们通常采用的计划模式下面,所有在BOM结构里面的半成品,都是在库存中作为一个整体, 可以用在任意的一个成品物料,或…

STM32 NOR_FLASH 学习

NOR FLASH FLASH是常用的&#xff0c;用于存储数据的半导体器件&#xff0c;它具有容量大&#xff0c;可重复擦写、按“扇区/块”擦除、掉电后数据可继续保存的特性。 NOR FLASH的单位是MB&#xff0c;EEPROM的单位是KB。 NM25Q128&#xff0c;是NOR FLASH的一种&#xff0c…

正则匹配img标签里面src

正则&#xff1a; (?<src\s*\s*\")\S(?\"{1})匹配效果&#xff1a;

SAP F4下拉值报错:【内部错误:表格格式】

报错截图如下&#xff1a; 解决办法&#xff1a; 事务码&#xff1a;SU3 在【参数】页签维护如下值&#xff1a; SET/GET参数标识参数值简短描述F4METHODNoActiveXActiveX/NoActiveX 维护好以上信息之后&#xff0c;就可以正常显示下拉值了

OpenHarmony ArkUI 如何调用相机

​ ArkUI调用相机和调用相册其实是一个思路&#xff0c;只用修改一个地方。 我们继续来说相机调用&#xff0c;ArkUI没办法自己获取相机&#xff0c;所以得依靠一下ohos.multimedia.camera 相机开发指导 介绍 本指导主要展示了调用相机的调用过程&#xff0c;以及调用相机的…

【Elasticsearch】学好Elasticsearch系列-Query DSL

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 先看后赞&#xff0c;养成习惯。 点赞收藏&#xff0c;人生辉煌。 文章目录 查询上下文相关度评分&#xff1a;_score源数据&#xff1a;_source数据源过滤器全文检索match&#xff1a;匹配包含某个term的子句…

整个个人博客?想找纯html代码模板?来个手机版带菜单的首页模板“参考参考”

以前做毕业设计的时候老想找一些不掺杂后端代码的前端模板。 可是下载下来&#xff0c;不是php就是python后台的。看又看不懂&#xff0c;想换语言就必须先把里面的后台代码拿掉。 就很像买了个精装的二手房&#xff0c;白白多花了砸墙钱。 就比如&#xff0c;想做个带菜单的…

【go-zero】docker镜像直接部署API与RPC服务 如何实现注册发现?docker network 实现 go-zero 注册发现

一、场景&问题 使用docker直接部署go-zero微服务会发现API无法找到RPC服务 1、API无法发现RPC服务 用docker直接部署 我们会发现API无法注册发现RPC服务 原因是我们缺少了docker的network网桥 2、系统内查看 RPC服务运行正常API服务启动,通过docker logs 查看日志还是未…

数据库相关知识点

体系结构图&#xff1a; 体系介绍&#xff1a; Client Connectors 接入方。支持很多协议(JDBC、ODBC、.NET、PHP、Python、PERL、C 等) Management Serveices & Utilities 系统管理和控制工具&#xff0c;mysqldump、 mysql复制集群、分区管理等 Connection Pool 连接池…

【css】css位置布局position

position 属性规定应用于元素的定位方法的类型。元素其实是通过使用top、bottom、left 和 right 属性来定位的。但是&#xff0c;需要首先设置了 position 属性&#xff0c;否则这些属性将不起作用。根据不同的 position 值&#xff0c;它们的设置特点不同。 其有五个不同的位…

【禅道】禅道数据迁移,源码安装的禅道18.2迁移至docker安装的禅道18.2

docker安装禅道开源版18.2 sudo docker run --name chandao \ -p 9080:80 \ -p 3306:3306 \ --networkzentaonet \ -v /opt/docker/zentao/zentaopms:/www/zentaopms \ -v /opt/docker/zentao/mysql:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD数据库密码\ -d easysoft/zentao:1…