【java 安全】 IO流

前言

IO是指 Input/Output,即输入和输出。以内存为中心:

  • Input指从外部读入数据到内存,例如把文件从磁盘读取到内存,从网络读取数据到内存等等。
  • Output指把数据从内存输出到外部,例如把数据从内存写入到文件,把数据从内存输出到网络等等。

为什么要把数据读到内存才能处理这些数据?因为代码是在内存中运行的,数据也必须读到内存,最终的表示方式无非是 byte[ ]数组,字符串等,都必须存放在内存里。

从 Java 代码来看,输入实际上就是从外部,例如,硬盘上的某个文件,把内容读到内存,并且以 Java 提供的某种数据类型表示,例如,byte[]String,这样,后续代码才能处理这些数据。

因为内存有“易失性”的特点,所以必须把处理后的数据以某种方式输出,例如,写入到文件。Output 实际上就是把 Java 表示的数据格式,例如,byte[]String等输出到某个地方。

IO 流是一种顺序读写数据的模式,它的特点是单向流动。数据类似自来水一样在水管中流动,所以我们把它称为 IO 流。

在Java中,InputStream代表输入字节流,OuputStream代表输出字节流,这是最基本的两种IO流。

FIle对象的一些操作

创建文件常用的三种方式

主要是根据它的 public 构造方法,File的public构造方法共有4种
还有一种public File(URI uri)用的比较少就没说

根据路径创建一个File对象

方法:new File(String Pathname)

package IOStream;import java.io.File;
import java.io.IOException;public class newFile01 {public static void main(String[] args) {//文件路径:xpw/src/IOStream/newFile01.javaFile file = new File("src/IOStream/1.txt");//pathname:"/1.txt" --> 盘符根目录//pathname:"1.txt"  --> 项目根目录try {file.createNewFile();} catch (IOException e) {throw new RuntimeException(e);}}
}
根据父目录路径,在子路径下生成文件

方法:new File(String parent, String child)

package IOStream;import java.io.File;
import java.io.IOException;public class newFile03 {public static void main(String[] args) {File file = new File("src/IOStream","3.txt");try {file.createNewFile();} catch (IOException e) {throw new RuntimeException(e);}}
}
根据父目录 File 对象,在子路径创建一个文件

方法:new File(File parent, String child)

package IOStream;import java.io.File;
import java.io.IOException;public class newFile02 {public static void main(String[] args) {File parent = new File("src/IOStream");File file = new File(parent,"2.txt");try {file.createNewFile();} catch (IOException e) {throw new RuntimeException(e);}}
}

获取文件信息

通过file对象的一些方法进行获取

package IOStream;import java.io.File;public class gerFileInfo {public static void main(String[] args) {File file = new File("src/IOStream/3.txt");System.out.println("文件名称为:" + file.getName());System.out.println("文件的绝对路径为:" + file.getAbsolutePath());System.out.println("文件的父级目录为:" + file.getParent());System.out.println("文件的大小(字节)为:" + file.length());System.out.println("这是不是一个文件:" + file.isFile());System.out.println("这是不是一个目录:" + file.isDirectory());}
}

在这里插入图片描述

目录与文件操作

文件删除

使用 file.delete(文件)

package IOStream;import java.io.File;public class delFIle {public static void main(String[] args) {File file = new File("src/IOStream/3.txt");boolean delete = file.delete();System.out.println(delete?"Deleted Successfully":"Failed to Delete Successfully");}
}
目录删除

使用 file.delete(目录),前提是目录为空

package IOStream;import java.io.File;public class delDictory {public static void main(String[] args) {File file = new File("src/IOStream/test");boolean delete = file.delete();System.out.println(delete?"success":"fail");}
}
创建单级目录

使用file.mkdir()

package IOStream;import java.io.File;public class createDictory {public static void main(String[] args) {File file = new File("src/IOStream/dictory");boolean mkdir = file.mkdir();System.out.println(mkdir?"success":"fail");}
}
创建多级目录

使用 file.mkdirs()

package IOStream;import java.io.File;public class createDictorys {public static void main(String[] args) {File file = new File("src/IOStream/Dictorys/test/123");boolean mkdirs = file.mkdirs();System.out.println(mkdirs?"success":"fail");}
}

IO流分类

按照操作数据单位不同分为:字节流和字符流

  • 字节流(8bit,适用于二进制文件)
  • 字符流(按字符,因编码不同而异,适用于文本文件)

数据流流向:输入流(读取数据)和输出流(写入数据)。

流的角色:节点流(直接操作数据源)和处理流/包装流(对节点流进行包装,提供额外功能)。

类型特点抽象基类
字节流处理二进制数据,单位 8bitInputStream OutputStream
字符流处理文本数据,单位依赖字符编码Reader Writer
节点流直接操作数据源FileInputStream
处理流/包装流封装节点流,提供增强功能BufferedInputStream

InputStream

InputStream就是Java标准库提供的最基本的输入流。它位于java.io这个包里, java.io包提供了所有同步IO的功能

注意:InputStream不是一个接口,而是一个抽象类,是所有输入流的超类

它里面最重要的方法就是int read()

public abstract int read() throws IOException;

这个方法会读取输入流的下一个字节,并返回该字节表示的int值(0~255)。如果已读到末尾,返回-1表示不能继续读取了。

FileInputStream() 实现类

FileInputStreamInputStream的一个子类。顾名思义,FileInputStream就是从文件流中读取数据。

通过FileInputStream()来读取一个文件

package IOStream;import java.io.FileInputStream;
import java.io.IOException;public class inputStream {public static void main(String[] args) {FileInputStream fileinputstream = null;int read=0;try {fileinputstream = new FileInputStream("src/IOStream/1.txt");while((read=fileinputstream.read())!=-1){System.out.print((char)read);//不换行
//                System.out.println((char)read);//换行}} catch (IOException e) {e.printStackTrace();}finally {try {fileinputstream.close();} catch (IOException e) {e.printStackTrace();}}}}

应用程序在运行的过程中,如果打开了一个文件进行读写,完成后要及时地关闭,以便让操作系统把资源释放掉,否则,应用程序占用的资源会越来越多,不但白白占用内存,还会影响其他应用程序的运行。InputStreamOutputStream都是通过close()方法来关闭流。关闭流就会释放对应的底层资源。

InputStreamOutputStream都实现了AutoCloseable的接口,会自动加上finally语句并调用close()方法

所以可以通过这种方式去写:try(resource){}
try(fileinputstream = new FileInputStream("src/IOStream/1.txt")){ }

缓冲

在读取流的时候,一次读取一个字节比较低效,利用缓冲一次读取多个字节到缓冲区会比较高效

InputStream提供了两个重载方法来支持读取多个字节

  • int read(byte[] b):读取若干字节并填充到byte[]数组,返回读取的字节数
  • int read(byte[] b, int off, int len):指定byte[]数组的偏移量和最大填充数

需要先定义一个byte[]数组作为缓冲区,read()方法会尽可能多地读取字节到缓冲区, 但不会超过缓冲区的大小。read()方法的返回值不再是字节的int值,而是返回实际读取了多少个字节。如果返回-1,表示没有更多的数据了。

package IOStream;import java.io.FileInputStream;
import java.io.IOException;public class inputStream02 {public static void main(String[] args) {FileInputStream inputStream = null;//设置缓冲区,大小为 8 字节byte[] cache = new byte[8];int datalen = 0;try (FileInputStream fileInputStream = new FileInputStream("src/IOStream/1.txt")) {while((datalen = fileInputStream.read(cache))!=-1){System.out.println("read "+datalen+" bytes");// 会将整个cache数组转化为字符串,会存在上一次循环留下来的数据System.out.println(new String(cache));// 只将实际读取到的 datalen 长度的字节从 cache 数组中转换为字符串System.out.println(new String(cache,0,datalen));}} catch (IOException e) {throw new RuntimeException(e);}}
}

在这里插入图片描述

ByteArrayInputStream实现类

ByteArrayInputStream() 允许你将一个字节数组(**byte[]**)当作一个输入流来读取

相当于把内存中的字节数组当成了一个文件或其他数据源,可以使用InputStream 的各种方法来处理它

许多库和方法都接受 InputStream 作为参数,如果你有字节数组,通过 ByteArrayInputStream() 就可以方便地与这些API集成。

ByteArrayInputStream()通常有两种构造方法:

  1. **ByteArrayInputStream(byte[] b)**
    • 接收一个完整的字节数组作为数据源。
    • 流的读取将从数组的第一个字节开始,到数组的最后一个字节结束。
  1. **ByteArrayInputStream(byte[] b, int offset, int length)**
    • 接收一个字节数组 。
    • offset:指定从数组的哪个索引位置开始读取。
    • length:指定从 offset 位置开始,总共读取多少个字节。
    • 这允许你只读取字节数组的一部分
package IOStream;import java.io.ByteArrayInputStream;
import java.io.IOException;public class inputStream03 {public static void main(String[] args) {byte[] data = "xpw123xpw".getBytes();//读取整个byte数组int datalen = 0;try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) {System.out.println("读取所有数据:");while((datalen = byteArrayInputStream.read()) != -1){System.out.print((char)datalen);}} catch (IOException e) {throw new RuntimeException(e);}//读取byte数组的一部分try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data,3,3)) {System.out.println("\n读取部分数据:");while((datalen = byteArrayInputStream.read()) != -1){System.out.print((char)datalen);}} catch (IOException e) {throw new RuntimeException(e);}//结合缓冲区读取byte[] cache = new byte[8];try(ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)){System.out.println("\n通过缓冲区读取: ");while((datalen = byteArrayInputStream.read(cache)) != -1){System.out.println(new String(cache,0,datalen));}} catch (IOException e) {throw new RuntimeException(e);}}
}

在这里插入图片描述

OutputStream

OutputStream是Java标准库提供的最基本的输出流

InputStream类似,OutputStream也是抽象类,它是所有输出流的超类。这个抽象类定义的一个重要的方法就是void write(int b)

public abstract void write(int b) throws IOException;

当然这个实现也比较简单,就是一个字节一个字节的写进去

OutputStream还提供了一个重要的方法就是flush(),它的目的是将缓冲区的内容真正输出到目的地

为什么要有flush()
因为向磁盘、网络写入数据的时候,出于效率的考虑,操作系统并不是输出一个字节就立刻写入到文件或者发送到网络,而是把输出的字节先放到内存的一个缓冲区里(本质上就是一个byte[]数组),等到缓冲区写满了,再一次性写入文件或者网络。对于很多IO设备来说,一次写一个字节和一次写1000个字节,花费的时间几乎是完全一样的,所以OutputStream有个flush()方法,能强制把缓冲区内容输出。

不过大多时候我们不需要调用这个flush()方法,因为如果缓冲区写满了,OutputStream会自动调用它,并且在调用close()方法关闭OutputStream之前,也会自动调用flush()

FileOutputStream实现类

FileOutputStream从文件获取输出流,是OutputStream常用的一个实现类

write(int b)

一个字节一个字节的写入

package IOStream;import java.io.FileOutputStream;
import java.io.IOException;public class writeStream {public static void main(String[] args) {try (FileOutputStream outputStream = new FileOutputStream("src/IOStream/1.txt")) {outputStream.write(72);outputStream.write(73);outputStream.write(74);outputStream.write(75);} catch (IOException e) {throw new RuntimeException(e);}}
}
write(byte b[])

整个字节数组写入

package IOStream;import java.io.FileOutputStream;
import java.io.IOException;public class writeStream02 {public static void main(String[] args) {byte[] data= "112233".getBytes();try (FileOutputStream outputStream = new FileOutputStream("src/IOStream/2.txt")) {outputStream.write(data);} catch (IOException e) {throw new RuntimeException(e);}}
}

追加写入

public FileOutputStream(String name, boolean append) throws FileNotFoundException
public FileOutputStream(File file, boolean append) throws FileNotFoundException

主要在于构造函数多添加一个参数

package IOStream;import java.io.FileOutputStream;
import java.io.IOException;public class writeStream03 {public static void main(String[] args) {byte[] data= "xpw".getBytes();try (FileOutputStream outputStream = new FileOutputStream("src/IOStream/2.txt", true)) {outputStream.write(data);} catch (IOException e) {throw new RuntimeException(e);}}
}

同样,OutputStream也有一个子类ByteArrayOutputStream,在内存中模拟一个OutputStream流, 实际上是把一个byte[]数组在内存中变成一个OutputStream

byte[] data;
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {output.write("Hello ".getBytes("UTF-8"));output.write("world!".getBytes("UTF-8"));data = output.toByteArray();
}
System.out.println(new String(data, "UTF-8"));

Reader

Reader是Java的IO库提供的另一个输入流接口。和InputStream的区别是,InputStream是一个字节流,即以byte为单位读取,而Reader是一个字符流,即以char为单位读取, 是所有字符输入流的超类

InputStreamReader
字节流,以byte为单位字符流,以char为单位
读取字节(-1,0~255):int read()读取字符(-1,0~65535)int read()
读到字节数组:int read(byte[] b)读到字符数组:int read(char[] c)

FileReader

FileReaderReader的一个子类

read()

这个方法读取字符流的下一个字符,并返回字符表示的**int**,范围是0~65535。如果已读到末尾,返回-1

package IOStream;import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;public class fileReader {public static void main(String[] args) {try {Reader reader = new FileReader("src/IOStream/1.txt");for (;;){int n = reader.read();if(n==-1)break;System.out.print((char)n);}} catch (IOException e) {throw new RuntimeException(e);}}
}

有时候可能会出现一些乱码问题,要避免乱码问题,我们需要在创建FileReader时指定编码:

Reader reader = new FileReader("src/IOStream/1.txt", StandardCharsets.UTF_8);
read(char[] c)

一次性读取若干字符并填充到char[]数组

它返回实际读入的字符个数,最大不超过char[]数组的长度。返回-1表示流结束

需要先设置一个缓冲区

package IOStream;import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;public class fileReader02 {public static void main(String[] args) {try (Reader reader = new FileReader("src/IOStream/2.txt", StandardCharsets.UTF_8)) {char[] cache = new char[8];int n;while ((n = reader.read(cache)) != -1) {System.out.println("read " + n + " chars.");System.out.println(new String(cache, 0, n));}} catch (IOException e) {throw new RuntimeException(e);}}
}

在这里插入图片描述

CharArrayReader

CharArrayReader可以在内存中模拟一个Reader,它的作用实际上是把一个char[]数组变成一个Reader,这和ByteArrayInputStream非常类似:

try (Reader reader = new CharArrayReader("Hello".toCharArray())) { }

StringReader

StringReader可以直接把String作为数据源,它和CharArrayReader几乎一样

try (Reader reader = new StringReader("Hello")) { }

Writer

Reader是带编码转换器的InputStream,它把byte转换为char,而Writer就是带编码转换器的OutputStream,它把char转换为byte并输出。

WriterOutputStream的区别如下:

OutputStreamWriter
字节流,以byte为单位字符流,以char为单位
写入字节(0~255):void write(int b)写入字符(0~65535):void write(int c)
写入字节数组:void write(byte[] b)写入字符数组:void write(char[] c)
无对应方法写入字符串:void write(String s)

FileWriter

FileWriter就是向文件中写入字符流的Writer。它的使用方法和FileReader类似

package IOStream;import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;public class fileWriter {public static void main(String[] args) {try (Writer writer = new FileWriter("src/IOStream/2.txt", StandardCharsets.UTF_8)) {//写入单个字符writer.write("h");writer.write(65);//写入字符数组writer.write("hello".toCharArray());//写入字符串writer.write("hello");} catch (IOException e) {throw new RuntimeException(e);}}
}

CharArrayWriter

CharArrayWriter可以在内存中创建一个Writer,它的作用实际上是构造一个缓冲区,可以写入char,最后得到写入的char[]数组,这和ByteArrayOutputStream非常类似

try (CharArrayWriter writer = new CharArrayWriter()) {writer.write(65);writer.write(66);writer.write(67);char[] data = writer.toCharArray(); // { 'A', 'B', 'C' }
}

StringWriter

StringWriter也是一个基于内存的Writer,它和CharArrayWriter类似。实际上,StringWriter在内部维护了一个StringBuffer,并对外提供了Writer接口。

参考文章

https://drun1baby.top/2022/05/30/Java-IO%E6%B5%81
https://liaoxuefeng.com/books/java/io/index.html

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

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

相关文章

音视频同步技术初剖析:原理、实现与FFmpeg分析

音视频同步的基本原理 音视频同步主要依靠以下几个关键点:时间戳机制: 在封装格式(如MP4)中,音频帧和视频帧都带有时间戳(PTS, Presentation Time Stamp)这些时间戳表示该帧应该在什么时间被呈现同步策略: 音频为主时钟&#xff1…

掌控网页的魔法之书:JavaScript DOM的奇幻之旅

掌控网页的魔法之书:JavaScript DOM的奇幻之旅 在网页开发的世界里,JavaScript就像一位魔法师,而DOM(文档对象模型)则是它的魔法之书。没有DOM,JavaScript就像失去了咒语的巫师,无法操控网页的元…

【C语言】深入理解柔性数组:特点、使用与优势分析

C语言学习 柔性数组 友情链接:C语言专栏 文章目录C语言学习前言:柔性数组一、柔性数组的特点二、柔性数组的使用三、柔性数组的优势总结附录上文链接专栏前言: 在有结构体和动态内存分配的知识后,今天咱们来说说柔性数组吧&…

RV126平台NFS网络启动终极复盘报告

1. 初始目标与环境目标: 将RV1126开发板的启动方式,由从eMMC内部存储挂载根文件系统(rootfs),切换为通过网络挂载位于NFS服务器上的根文件系统。动机: 提升开发调试效率,实现代码修改后仅需重启即可验证,免…

一台显示器上如何快速切换两台电脑主机?

我注意到很多人会遇到一个常见的情况:他们有两台电脑,一台旧的用来处理基本的办公任务,另一台新的用来玩游戏。新手通常会用 DP端口连接第一台电脑的显示器,用 HDMI 连接第二台电脑。当他们想在两台电脑之间切换时,经常…

抗辐照与国产替代:ASM1042在卫星光纤放大器(EDFA)中的应用探索

摘要:本文以国科安芯推出的ASM1042芯片为例,通过分析ASM1042的抗辐照性能、高速数据传输能力、可靠性以及国产化优势,结合EDFA系统的需求特点,深入探讨了其在商业卫星光纤放大器(EDFA)项目中的应用潜力。AS…

鸿蒙ArkUI:声明式开发,高效构建全场景体验

目录 导言:开启鸿蒙应用开发的新范式 ArkUI框架概览 - 鸿蒙UI的灵魂 深入核心 - 声明式UI开发范式 命令式 vs 声明式:范式革命 ArkUI如何实现声明式? 创建内置组件 创建自定义组件 自定义组件的基本结构 ArkUI框架的核心特性与优势 …

数据查找 二叉查找树

查找一般分为有序查找和无序查找,这边在讲有序查找例二分查找二分查找就是在有序数组中,通过mid(lowhigh)/2来判定中间值,将中间值与待查找的值进行比较,如果待查找的值大于中间值,那么就将范围缩小,查找右…

几款开源的安全监控与防御工具分享

安全监控与防御工具概述 在现代网络安全架构中,合理选择和部署一系列的安全监控、检测、响应工具至关重要。下面我们将介绍一些常见的安全工具,包括 Elkeid、Wazuh、Caldera、ELK、Snort、Suricata、OpenHFW、OSSEC、GScan 和 Sysom,并详细介绍它们的下载链接、用处、使用方…

Elasticsearch:ES|QL 改进的时间线

作者:来自 Elastic Toms Mura 让我们回顾一下 ES|QL 的历史和它的改进。 更多阅读,Elasticsearch:ES|QL 查询展示。 Elasticsearch 配备了众多新功能,帮助你为自己的用例构建最佳搜索方案。查看我们的示例笔记本了解更多内容&…

Linux | Bash 子字符串提取

注:本文为 “ Bash 子字符串提取” 相关合辑。 英文引文,机翻未校。 如有内容异常,请看原文。 How to Extract Bash Substring? [5 methods] 如何提取 Bash 子字符串?[5 种方法] 2024-04-28 00:00:00 In Bash, a substring is…

Vue2 前端开发 - vue-quill-editor 富文本编辑器(编辑器基础案例、编辑器配置参数解读、编辑器事件)

一、vue-quill-editor 1、vue-quill-editor 概述vue-quill-editor 是一个基于 Quill 富文本编辑器的 Vue 组件vue-quill-editor 在 Vue 2 项目中可以很方便地集成与使用2、vue-quill-editor 安装 执行如下指令,安装 vue-quill-editor npm install vue-quill-editor …

断网情况下,网线直连 Windows 笔记本 和Ubuntu 服务器

在断网情况下,通过网线直连 Windows 笔记本 和 Ubuntu 服务器,并使用 VSCode 访问服务器及 Docker 容器 的步骤如下:1. 物理连接(网线直连) 1.1 使用网线连接 用 网线(Cat5e 或更高) 连接 Windo…

消息队列总结

为什么需要消息队列? 随着互联网快速发展,业务规模不断扩张,技术架构从单体演进到微服务,服务间调用复杂、流量激增。为了解耦服务、合理利用资源、缓冲流量高峰,「消息队列」应运而生,常用于异步处理、服务…

C#引用转换核心原理:类型视角切换

🔍 C#引用转换核心原理:类型视角切换 引用类型由内存指针和类型标记组成(如图1)。引用转换不改变内存地址,仅改变编译器识别对象的“视角”: B myVar1 new B(); // 实际B类型对象 A myVar2 (A)myV…

重要发布丨MaxKB V2正式发布,助力用户快速构建企业级智能体

2025年7月18日,MaxKB V2版本正式发布。MaxKB是一个强大易用的企业级智能体平台,致力于解决企业AI落地所面临的技术门槛高、部署成本高、迭代周期长等问题,让企业用户落地AI更简单。 秉承“开箱即用,伴随成长”的设计理念&#xff…

大语言模型任务分解与汇总:从认知瓶颈到系统化解决方案

一、缘起:为什么大模型需要"分而治之" 1.1 从一个真实场景说起 设想这样一个场景:你要求GPT-4帮你完成一份包含市场调研、竞品分析、财务预测和战略规划的商业计划书。即使是最先进的大模型,面对这样的复杂任务也会"力不从心&…

Spring核心注解@RequestMapping详解

RequestMapping 是 Spring Framework 中一个核心注解,用于在 Spring MVC(或 Spring WebFlux)中将 HTTP 请求映射到特定的处理器(Controller 中的方法)或处理器类。它告诉 Spring 框架:当一个匹配特定条件的…

OSPF路由协议的协商过程

OSPF的知识点非常多,协议过程也是一个不大不小的知识点,今天就简单的说一下,OSPF是如何进行协商的。OSPF(Open Shortest Path First)协议是一种用于路由选择的动态链路状态协议,是大型网络普遍使用的动态路…

MySql:索引,结构

文章目录注意事项结构注意事项 主键字段在建表时,会自动创建主键索引添加唯一约束时,数据库实际上会添加唯一索引。 解释: 增:创建: create [unique] index 索引名 on 表名 (字段名……);-- 举例 :给tb…