Java SE 学习笔记(十四)—— IO流(2)

news2025/1/12 6:50:43

目录

  • 1 字节流
    • 1.1 字节流写数据
      • 1.1.1 创建字节输出流对象
      • 1.1.2 字节流写数据
    • 1.2 字节流读数据
      • 1.2.1 创建字节输入流对象
      • 1.2.2 字节流读数据
    • 1.3 字节流复制文件
    • 1.4 流的刷新与关闭
    • 1.5 资源释放方式
      • 1.5.1 try-catch-finally
      • 1.5.2 try-with-resource
  • 2 字符流
    • 2.1 字符流概述
    • 2.2 字符流写数据
    • 2.3 字符流读数据

1 字节流

1.1 字节流写数据

1.1.1 创建字节输出流对象


  • 字节流抽象基类
    • InputStream:这个抽象类是表示字节输入流的所有类的超类
    • OutputStream:这个抽象类是表示字节输出流的所有类的超类
    • 子类名特点:子类名称都是以其父类名作为子类名的后缀
  • 字节输出流
    • FileOutputStream(String name):创建文件输出流以指定的名称写入文件
  • 使用字节输出流写数据的步骤
    • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
    • 调用字节输出流对象的写数据方法
    • 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)

在这里插入图片描述

示例代码:

public static void main(String[] args) throws IOException {
	//1.创建字节输出流的对象
	FileOutputStream fos = new FileOutputStream("D:\\a.txt");
	//FileOutputStream fos = new FileOutputStream(new File("D:\\a.txt"));

注意:

  • 如果文件不存在,会帮我们自动创建出来.
  • 如果文件存在,会把文件清空.

1.1.2 字节流写数据


在这里插入图片描述

示例代码:

public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("bytestream\\a.txt");
  /*fos.write(97);
    fos.write(98);
    fos.write(99);*/
    
    /* byte[] bys = {97,98,99};
    fos.write(bys);*/

    byte [] bys = {97,98,99,100,101,102,103};
    fos.write(bys,1,2); //98,99即写入bc
    
    fos.close();
}

那么,现在有两个小问题

  • 字节流写数据如何实现换行?
    • windows:\r\n
    • linux:\n
    • mac:\r
    • getBytes()是字符串的一个方法,可以将字符串转换为字节
  • 字节流写数据如何实现追加写入?
    • public FileOutputStream(String name,boolean append)
    • 创建文件输出流对象以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头

示例代码:

public static void main(String[] args) throws IOException {
	//第二个参数就是续写开关,如果没有传递,默认就是false,
	//表示不打开续写功能,那么创建对象的这行代码会清空文件.

	//如果第二个参数为true,表示打开续写功能
	//那么创建对象的这行代码不会清空文件.
	FileOutputStream fos = new FileOutputStream("bytestream\\a.txt",true);

	fos.write(97);
	//加一个换行
	fos.write("\r\n".getBytes());
	fos.write(98);
	//加一个换行
	fos.write("\r\n".getBytes());
	fos.write(99);
	//加一个换行
	fos.write("\r\n".getBytes());
	fos.write(100);
	//加一个换行
	fos.write("\r\n".getBytes());
	fos.write(101);
	//加一个换行
	fos.write("\r\n".getBytes());

	fos.close();
}

1.2 字节流读数据

1.2.1 创建字节输入流对象


字节输入流

  • FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名

在这里插入图片描述

1.2.2 字节流读数据


在这里插入图片描述

字节输入流读取数据的步骤:

  • 创建字节输入流对象
  • 调用字节输入流对象的读数据方法
  • 释放资源

1. 一次读一个字节数据

public static void main(String[] args) throws IOException {
	//如果文件存在,那么就不会报错.
	//如果文件不存在,那么就直接报错.
	FileInputStream fis = new FileInputStream("bytestream\\a.txt");

	int read = fis.read();
	//一次读取一个字节,返回值就是本次读到的那个字节数据.
	//也就是字符在码表中对应的那个数字.
	//如果我们想要看到的是字符数据,那么一定要强转成char

	System.out.println(read); // 97
	System.out.println((char)read); //a

	//释放资源
	fis.close();
}

改进:使用循环

public static void main(String[] args) throws IOException {
	FileInputStream fis = new FileInputStream("bytestream\\a.txt");
	//文件中多个字节我怎么办?
	/*while(true){
		int i1 = fis.read(); 内容读取结束读取到空格时返回-1
		System.out.println(i1); 
	}*/ 

	int b;
	while ((b = fis.read())!=-1){
		System.out.println((char) b);
	}
	fis.close();
}

每个读取一个字节存在什么问题呢?

  • 性能较慢
  • 读取中文字符输出无法避免乱码问题

2. 一次读一个字节数组

一次读一个字节数组的方法:

  • public int read(byte[] b):从输入流读取最多b.length个字节的数据
  • 返回的是读入缓冲区的总字节数,也就是实际的读取字节个数

注意:

  • hello.txt文件内容为:ab3abccd
  • io为当前模块名
public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("io/src/hello.txt");
    byte[] bytes = new byte[3];

    int len1 = fis.read(bytes);
    System.out.println("读取了" + len1 + "字节"); // 读取了3字节
    String s1 = new String(bytes);
    System.out.println(s1); // ab3

    int len2 = fis.read(bytes);
    System.out.println("读取了" + len2 + "字节"); // 读取了3字节
    String s2 = new String(bytes);
    System.out.println(s2); // abc

    int len3 = fis.read(bytes);
    System.out.println("读取了" + len3 + "字节"); // 读取了2字节
//        String s3 = new String(bytes);
//        System.out.println(s3); // cdc
//        注意:上一次读取的是abc,这一次由于只读两个,所以只会覆盖前两个字符
    
    // 读多少倒出多少
    String s3 = new String(bytes, 0, 2);
    System.out.println(s3); // cd
}

每次读取一个字节数组存在什么问题?

  • 读取的性能得到了提升
  • 读取中文字符输出无法避免乱码问题。

3. 一次读完全部字节

(1)定义一个与文件一样大的字节数组byte[] bytes=new byte[(int) f.length()],一次性读完文件的全部字节,这样直接把文件数组全部读取到一个字节数组里可以避免乱码,但是如果文件过大,字节数组可能会引起内存溢出。

(2)官方为字节输入流 InputStream 提供了如下 API 可以直接把文件的全部数据读取到一个字节数组中

在这里插入图片描述

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        File f = new File("io/src/hello.txt");
        FileInputStream fis = new FileInputStream(f);

        // 方法一
//        byte[] bytes = new byte[(int) f.length()];
//        int len = fis.read(bytes);
//        System.out.println("读取了" + len + "字节"); // 读取了8字节
//        System.out.println("文件的大小:" + f.length()+"字节"); // 文件的大小:8字节
//        System.out.println(new String(bytes)); // ab3abccd
        // 方法二
        byte[] bytes1 = fis.readAllBytes();
        System.out.println(new String(bytes1)); // ab3abccd
    }
}

1.3 字节流复制文件


  1. 小文件复制

C:\it\a.jpg的文件复制到模块 bytestream 下

public static void main(String[] args) throws IOException {
	//创建了字节输入流,准备读数据.
	FileInputStream fis = new FileInputStream("C:\\test\\a.jpg");
	//创建了字节输出流,准备写数据.
	FileOutputStream fos = new FileOutputStream("bytestream\\a.jpg");

	int b;
	while((b = fis.read())!=-1){
		fos.write(b);
	}

	fis.close();
	fos.close();
}
  1. 大文件复制

对于大文件的复制问题,字节流通过创建字节数组,可以一次读写多个数据

public static void main(String[] args) throws IOException {
	FileInputStream fis = new FileInputStream("C:\\test\\a.avi");
	FileOutputStream fos = new FileOutputStream("bytestream\\a.avi");

	byte [] bytes = new byte[1024];// 该字节数组的大小是1024字节
	int len;//本次读到的有效字节个数 --- 这次读了几个字节

	while((len = fis.read(bytes))!=-1){  // 循环读取
		fos.write(bytes,0,len);//0索引开始,读取len个字节
	}

	fis.close();
	fos.close();
}

字节流适合做一切文件数据的拷贝吗?

  • 任何文件的底层都是字节,拷贝是一字不漏的转移字节,只要前后文件格式,编码一致就没有任何问题。

1.4 流的刷新与关闭


以下两种方法能够让写出去的数据成功生效

在这里插入图片描述

1.5 资源释放方式

1.5.1 try-catch-finally


有如下代码:

try {
    FileOutputStream fos = new FileOutputStream("a.txt");
    fos.write(97);
    fos.close();
}catch (IOException e){
    e.printStackTrace();
}

我们如何操作才能让close方法一定执行呢?

异常处理的标准格式:

try{
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}finally{
	执行所有清除操作; // 在异常处理时提供finally块来执行所有的清除操作,比如IO流的释放资源,被finally控制的语句一定会执行,除非JVM退出
}

加异常处理后的代码如下:

public static void main(String[] args) {
	FileOutputStream fos = null;
	try {
		//System.out.println(2/0);
		fos = new FileOutputStream("D:\\a.txt");
		//FileOutputStream fos = new FileOutputStream("D:\\a.txt");
		//此时fos是局部变量,在finally里无法执行fos.close();
		fos.write(97);
	}catch(IOException e){
	   e.printStackTrace();
	}finally {
		//finally语句里面的代码,一定会被执行.
		if(fos != null){//如果fos为null就不会和上述路径的文件产生关系,就不用关闭文件
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

finally 虽然可以用于释放资源,但是释放资源的代码过于繁琐

1.5.2 try-with-resource


在这里插入图片描述

JDK 7 以及 JDK 9 的 ()只能 放置资源对象,用完会自动关闭,自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)

  • 什么是资源呢?
    • 资源都是实现了 Closeable/AutoCloseable 接口的类对象

在这里插入图片描述

2 字符流

2.1 字符流概述


既然字节流可以操作所有文件,为什么要学习字符流?

  • 如果利用字节流,把文本文件中的中文,读取到内存中,有可能出现乱码
  • 如果利用字节流,把中文写到文本文件中,也有可能出现乱码

为什么字节流读取文本文件,可能会出现乱码?

  • 因为字节流一次读一个字节,而不管GBK还是UTF-8一个中文都是多个字节,用字节流每次只能读其中的一部分,所以会出现乱码的问题

由于字节流操作中文不是特别的方便,所以Java就提供字符流(字符流 = 字节流 + 编码表)。字符流更适合操作中文,最小单位就是按照单个字符读写的。

2.2 字符流写数据


Writer: 用于写入字符流的抽象父类
FileWriter: 用于写入字符流的常用子类

构造方法:

在这里插入图片描述

成员方法:

在这里插入图片描述

public static void main(String[] args) throws IOException {
    //创建字符输出流的对象
    //FileWriter fw = new FileWriter(new File("charstream\\a.txt"));
    FileWriter fw = new FileWriter("charstream\\a.txt");


    //写一个字符
    fw.write(97);
    fw.write(98);
    fw.write(99);


    //写出一个字符数组
    char [] chars1 = {97,98,99,100,101};
    fw.write(chars1);


    //写出字符数组的一部分
    char [] chars2 = {97,98,99,100,101};
    fw.write(chars2,0,3);


    //写一个字符串
    String line1 = "黑马程序员abc";
    fw.write(line1);


    //写一个字符串的一部分
    String line2 = "黑马程序员abc";
    fw.write(line2, 0, 2);

    //释放资源
    fw.close();
}

注意:

  • 在创建字符输出流对象时,如果文件存在就清空,如果文件不存在就创建,但是要保证父级路径存在
  • 写数据时,写出int类型的整数,实际写出的是整数在码表上对应的字母,写出字符串数据,是把字符串本身原样输出

2.3 字符流读数据


Reader: 用于读取字符流的抽象父类
FileReader: 用于读取字符流的常用子类

构造方法

在这里插入图片描述
成员方法

在这里插入图片描述

public static void main(String[] args) throws IOException {
    //创建字符输入流的对象
    // FileReader fr = new FileReader(new File("charstream\\a.txt"));
    FileReader fr = new FileReader("charstream\\a.txt");

    //读取数据
    
    //一次读取一个字符
/*        int ch;
    while((ch = fr.read()) != -1){
        System.out.println((char) ch);
    }*/


    //一次读取多个字符。
    //创建一个数组
    char [] chars = new char[1024];
    int len;
    //read方法还是读取,但是是一次读取多个字符
    //他把读到的字符都存入到chars数组。
    //返回值:表示本次读到了多少个字符。
    while((len = fr.read(chars))!=-1){
        System.out.println(new String(chars,0,len));
    }

    //释放资源
    fr.close();
}

小结:

  • 字节流适合做一切文件的拷贝
  • 字符流适合做文本文件的操作(读写)
    • 想要把文本文件中的数据读到内存中,使用字符输入流
    • 想要把内存中的数据写到文本文件中,使用字符输出流

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

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

相关文章

Spring中Bean的作用域

目录 一、什么是Bean的作用域 二、Scope注解 三、Bean的6种作用域 3.1 singleton单例模式 3.2 prototype 原型模式 3.3 request 3.4 session 3.5 application 3.6 websocket 一、什么是Bean的作用域 在之前学习的过程中,我们把作用域定义为:限定程序中变…

关于数字化转型的know how

关于定义——到底什么是“数字化转型”? 关于价值——数字化转型对企业到底有多重要? 关于框架——企业数字化转型的框架必备要素有哪些? 关于执行——企业数字化转型到底怎么做? 一、什么是数字化转型? 现在各种…

Flink将数据写入MySQL(JDBC)

一、写在前面 在实际的生产环境中&#xff0c;我们经常会把Flink处理的数据写入MySQL、Doris等数据库中&#xff0c;下面以MySQL为例&#xff0c;使用JDBC的方式将Flink的数据实时数据写入MySQL。 二、代码示例 2.1 版本说明 <flink.version>1.14.6</flink.version…

2000-2021年上市公司内部薪酬差距数据(原始数据+计算代码Stata do文档+计算结果)

2000-2021年上市公司内部薪酬差距数据&#xff08;原始数据计算代码Stata do文档计算结果&#xff09; 1、时间&#xff1a;2000-2021年 2、来源&#xff1a;上市公司年报 3、指标&#xff1a; 原始数据指标&#xff1a;code、year、证券代码、应付职工薪酬、员工人数、支付…

美国IP代理如何获取?适用于哪些场景?

美国代理IP可以是静态&#xff08;不会改变&#xff09;或动态&#xff08;周期性更改&#xff09;&#xff0c;并且可以由专业的代理服务提供商提供。不同的代理IP服务提供商可能提供不同类型的代理&#xff0c;包括数据中心代理、住宅代理和移动代理&#xff0c;以满足不同用…

RT-Thread 7. RT-Thread Studio ENV修改MCU型号

1. 修改MCU型号 2.在ENV界面输入 scons -c scons --dist3. dist下为更新后完整源代码 4.导入RT-Thread Studio 发现GD32F330已经生效了。 5. 自己编写startup_gd32f3x0.S&#xff0c;准确性待验证 ;/* ; * Copyright (c) 2006-2021, RT-Thread Development Team ; * ; * SPD…

Vue组件样式设置,解决样式冲突问题

如果我们在不同的组件内&#xff0c;使用相同的类名&#xff0c;就会发生样式的冲突&#xff0c;使用后引入的组件中的样式&#xff1a; 一、scoped属性 在一个组件的style标签上添加scoped属性&#xff0c;该组件的所有样式都是该组件独有的&#xff0c;即使其他组件中有相同…

详解傅立叶变换,看这一文足矣!

从听到傅立叶变换这个名词后到现在已经四年了&#xff0c;这次终于对傅立叶变换有了一个基本的初步了解。记录一下&#xff0c;这个傅立叶变换也同时记录了我本科到研究生的四年&#xff0c;一路以来跌跌撞撞&#xff0c;没想到最后还是入了图像的坑 数字图像处理——傅立叶变换…

freeRTOS内部机制——创建任务的内部细节

创建任务的两个核心&#xff1a;栈和任务结构体 函数运行过程中的局部变量保存在哪里&#xff1f;他自己的栈中 任务被切换过后&#xff0c;在切换的瞬间&#xff0c;哪些寄存器的值保存在哪里&#xff1f;保存在任务结构体中 在任务创建函数中&#xff0c;会malloc动态分配…

【Javascript】函数隐藏参数ar

function test(a,b,c){console.log(abc);}test(1,2,3);这里的形参有三个分别是a&#xff0c;b&#xff0c;c分别对应实参1&#xff0c;2&#xff0c;3 假如在调用函数的时候多传入几个实参会怎么样&#xff1f; function test(a,b,c){console.log(arguments);console.log(a…

吃瓜教程3|决策树

ID3算法 假定当前样本集合D中第k类样本所占比例为pk&#xff0c;则样本集合D的信息熵定义为 信息增益 C4.5算法 ID3算法存在一个问题&#xff0c;就是偏向于取值数目较多的属性&#xff0c;因此C4.5算法使用了“增益率”&#xff08;gain ratio&#xff09;来选择划分属性 CA…

第四章 文件管理 六、文件的基本操作

目录 一、创建文件(create系统调用) 1、进行Create系统调用时&#xff0c;需要提供的几个主要参数: 2、操作系统在处理Create系统调用时&#xff0c;主要做了两件事: 二、删除文件(delete系统调用) 1、进行Delete系统调用时&#xff0c;需要提供的几个主要参数: 2、操作系…

【20年VIO梳理】

19-20年VIO 梳理 1. 开源代码介绍&#xff1a; DSM2. FMD Stereo SLAM&#xff1a;融合MVG和直接方法&#xff0c;实现准确&#xff0c;快速的双目SLAM3. 基于VINS-Mono开发的SPVIS4. 改进&#xff1a;一种基于光流的动态环境移动机器人定位方案5. PVIO:基于先验平面约束的高效…

第四章 文件管理 五、文件存储空间管理

目录 一、逻辑结构和物理结构的比较 二、空闲表法 1、磁盘中的空闲块表 2、例子 3、如何回收空闲区间 ①回收区的前后都没有相邻空闲区; ②回收区的前后都是空闲区; ③回收区前面是空闲区; ④回收区后面是空闲区; 三、空闲链表法 1、分类 2、空闲盘块链 &#xff…

【顺序栈的表示和实现,顺序栈的初始化,是否为空,清空顺序栈,销毁顺序栈,】

文章目录 一、栈和队列的定义和特点1.1顺序栈的表示和实现1.2顺序栈的基本操作1.2.1顺序栈的初始化1.2.2判断顺序栈是否为空1.2.3清空顺序栈1.2.4销毁顺序栈1.2.5顺序栈的入栈 一、栈和队列的定义和特点 栈和队列是限定插入和删除只能在表的“端点”进行的线性表。 栈是先进后…

【Linux】安装与配置虚拟机及虚拟机服务器坏境配置与连接---超详细教学

一&#xff0c;操作系统介绍 1.1.什么是操作系统 操作系统&#xff08;Operating System&#xff0c;简称OS&#xff09;是一种系统软件&#xff0c;它是计算机硬件和应用软件之间的桥梁。它管理计算机的硬件和软件资源&#xff0c;为应用程序提供接口和服务&#xff0c;并协…

VS搭建32位和64位汇编开发环境

VS搭建32位和64位汇编开发环境 1 VS2017软件安装2 创建汇编工程3 配置X86汇编环境&#xff08;32位&#xff09;4 配置X64汇编环境&#xff08;64位&#xff09;5 调试技巧 本文属于《 X86架构指令基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 VS2017软件安装 安装过…

根据键名解析特定属性的值相关API

mycdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/of.h>struct device_node *node; //解析得到的设备树节点对象指针 struct property *pr; //属性结构体指针 int len; u32 a; u32 b[2]; const char *str; u8 c[6]; static i…

MFI芯片I2C地址转换(写读转7位传入API接口)

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)&#xff1f;可加我微信hezkz17, 本群提供音频技术答疑服务 MFI芯片I2C地址转换(写读转7位传入API接口&#xff09; #define MFI_I2C_CHIP_ADDR 0x10// 芯片写/读 0x20/0x21(写/读) 七位地址 0x10 //zk 使用读地址…

jdbc 对事务的支持

MySQL中默认开启事务自动提交功能&#xff0c;即 每个SQL语句都会自动开启一个事务并提交&#xff0c;如果没有显式地使用COMMIT或者ROLLBACK语句&#xff0c;则所有的修改都将被保存到数据库中。这种情况下&#xff0c;如果某个操作出现错误&#xff0c;就无法回滚事务&#x…