- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
上一篇文章中,我们介绍了Java IO流中的4个基类:InputStream、OutputStream、Reader、Writer,那么这一篇中,我们将以四个基类所衍生出来,应对不同场景的数据流进行学习.
我们上面说了java.io包中有40多个类,都从InputStream、OutputStream、Reader、Writer这4个类中衍生而来,我们以操作对象的维度进行如下的区分:
文件流也就是直接操作文件的流,可以细分为字节流(FileInputStream 和 FileOuputStream)和字符流(FileReader 和 FileWriter),我们在上面的已经说了很多了,这里就再赘述啦.
所谓数组流就是将内存中有限的数据进行读写操作的流,适应于数据量小,无需利用文件存储,提升程序效率.
我们以ByteArrayInputStream(字节数组输入流)为例:
public class TestService{
public static void main(String[] args) {
try {
ByteArrayInputStream bi = new ByteArrayInputStream("JavaBuild".getBytes());
int content;
while ((content = bi.read()) != -1) {
System.out.print((char) content);
}
// 关闭输入流,释放资源
bi.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
字节数组输出流(ByteArrayOutputStream)亦是如此,它们不需要创建临时文件,直接在内存中就可以完成对字节数组的压缩,加密,读写以及序列化.
管道(Pipe)作为一种在计算机内通讯的媒介,无论是在操作系统(Unix/Linux)层面还是JVM层面都至关重要,我们今天提到的通道流就是在JVM层面,同一个进程中不同线程之间数据交互的载体.
我们以PipedOutputStream和PipedInputStream为例,通过PipedOutputStream将一串字符写入到内存中,再通过PipedInputStream读取输出到控制台,整个过程并没有临时文件的事情,数据仅在两个线程之间流转.
public class TestService{
public static void main(String[] args) throws IOException {
// 创建一个 PipedOutputStream 对象和一个 PipedInputStream 对象
final PipedOutputStream pipedOutputStream = new PipedOutputStream();
final PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
// 创建一个线程,向 PipedOutputStream 中写入数据
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
// 将字符串 "沉默王二" 转换为字节数组,并写入到 PipedOutputStream 中
pipedOutputStream.write("My name is JavaBuild".getBytes());
// 关闭 PipedOutputStream,释放资源
pipedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
// 创建一个线程,从 PipedInputStream 中读取数据并输出到控制台
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
// 定义一个字节数组用于存储读取到的数据
byte[] flush = new byte[1024];
// 定义一个变量用于存储每次读取到的字节数
int len = 0;
// 循环读取字节数组中的数据,并输出到控制台
while (-1 != (len = pipedInputStream.read(flush))) {
// 将读取到的字节转换为对应的字符串,并输出到控制台
System.out.println(new String(flush, 0, len));
}
// 关闭 PipedInputStream,释放资源
pipedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
// 启动线程1和线程2
thread1.start();
thread2.start();
}
}
我们知道在Java中分为基本数据类型和引用类型,我们在做数据的读取与写入时,自然也会涉及到这种情况,比如我们将txt文件中的数字型数据以int类型读取到程序中,这时Java为我们提供了DataInputStream/DataOutputStream类。它们的常用方法为:
具体使用也相对比较简单:
DataInputStream dis = new DataInputStream(new FileInputStream("input.txt"));
// 创建一个 DataOutputStream 对象,用于将数据写入到文件中
DataOutputStream das = new DataOutputStream(new FileOutputStream("output.txt"));
// 读取四个字节,将其转换为 int 类型
int i = dis.readInt();
// 将一个 int 类型的数据写入到文件中
das.writeInt(1000);
对于数据的处理,CPU速度快于内存,内存又远快于硬盘,在大数据量情况下,频繁的通过IO向磁盘读写数据会带来严重的性能问题,为此Java中提供了一个缓冲流的概念,简单来说就是在内存中设置一个缓冲区,只有缓冲区中存储的数据到达一定量后才会触发一次IO,这样大大提升了程序的读写性能,常用的缓冲流有:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter.
通过BufferedInputStream的底层源码我们可以看到,其内部维护了一个buf[]数据,默认大小为8192字节,我么也可以通过构造函数进行缓存大小设置.
public
class BufferedInputStream extends FilterInputStream {
// 内部缓冲区数组
protected volatile byte buf[];
// 缓冲区的默认大小
private static int DEFAULT_BUFFER_SIZE = 8192;
// 使用默认的缓冲区大小
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
// 自定义缓冲区大小
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
}
至于说缓冲流到底能不能实现性能的提升,我们实践出真知,对于程序员来说所有的理论都不及上手写一写来得有效!这其实也涉及到一个经常被问的面试问题:java中的缓冲流真的性能很好吗?
刚好,我们手头有一本《Java性能权威指南》的PDF版,大小为66MB,我们通过普通的文件流和缓冲流进行文件的读取和复制,看一下耗时对比.
public class TestService{
public static void main(String[] args) throws IOException {
TestService testService = new TestService();
testService.copyPdfWithPublic();
testService.copyPdfWithBuffer();
}
/*通过普通文件流进行pdf文件的读取和拷贝*/
public void copyPdfWithPublic(){
// 记录开始时间
long start = System.currentTimeMillis();
try (FileInputStream fis = new FileInputStream("E:\\Java性能权威指南.pdf");
FileOutputStream fos = new FileOutputStream("E:\\Java性能权威指南Public.pdf")) {
int content;
while ((content = fis.read()) != -1) {
fos.write(content);
}
//使用数组充当缓存时,两者性能差距不大
/*int len;
byte[] bytes = new byte[4 * 1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}*/
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("使用普通文件流复制PDF文件总耗时:" + (end - start) + " 毫秒");
}
/*通过缓冲字节流进行pdf文件的读取和拷贝*/
public void copyPdfWithBuffer(){
// 记录开始时间
long start = System.currentTimeMillis();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Java性能权威指南.pdf"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\Java性能权威指南Buffer.pdf"))) {
int content;
while ((content = bis.read()) != -1) {
bos.write(content);
}
/*int len;
byte[] bytes = new byte[4 * 1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}*/
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("使用缓冲字节流复制PDF文件总耗时:" + (end - start) + " 毫秒");
}
}
输出:
使用普通文件流复制PDF文件总耗时:221611 毫秒
使用缓冲字节流复制PDF文件总耗时:228 毫秒
然后,我们将注释掉的代码放开,也就是我们采用一个缓存数组,先将数组存储起来后,两者之间的性能差距就没那么明显了.
使用普通文件流复制PDF文件总耗时:106 毫秒
使用缓冲字节流复制PDF文件总耗时:80 毫秒
在这种情况下,我们可以看到,甚至于普通的文件流的耗时是小于缓冲流的,所以对于这种情况来说,缓冲流未必一定性能最好.
对于System.out.println("Hello World");这句代码我想大家并不陌生吧,我们刚学习Java的第一堂课,老师们都会让我们输出一个Hello World,System.out 实际是用于获取一个 PrintStream 对象,print方法实际调用的是 PrintStream 对象的 write 方法.
public class PrintStream extends FilterOutputStream
implements Appendable, Closeable {
}
public class PrintWriter extends Writer {
}
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥! 。
如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入! 。
最后此篇关于面试官:Java中缓冲流真的性能很好吗?我看未必的文章就讲到这里了,如果你想了解更多关于面试官:Java中缓冲流真的性能很好吗?我看未必的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试在两个表之间进行空间连接: 表 1:397265 个特征(在 geom 字段上有 gist 索引) 表 2:73 个特征(在 geom 字段上有 gist 索引) 表 1 和表 2 具有相同
我正在尝试在两个表之间进行空间连接: 表 1:397265 个特征(在 geom 字段上有 gist 索引) 表 2:73 个特征(在 geom 字段上有 gist 索引) 表 1 和表 2 具有相同
枚举类型的值是该类型的静态变量。 据我所知,变量是由引用变量引用的,但没有新的运算符来实例化枚举对象。但这就像初始化数组一样吗? 这是对还是错? 最佳答案 是的,枚举类型的文字是 public sta
我阅读了有关关闭 zsh 自动更正以完成命令的所有提示。但是,它们并没有完全发挥作用。我试过 DISABLE_CORRECTION="true", unsetopt correct, unsetopt
我知道这个问题是 answered before ,但给出的答案并不是完整的故事: 我进入了 Firefox 的 Options->Content 并删除了除德语/德国之外的所有语言,navigato
我知道用汇编语言编写任何内容或将汇编语言添加到任何程序都会损害其可移植性。但是,有多糟糕呢?我的意思是,现在基本上所有 PC 都是 x86 或 x64,对吧?那么,如果我将汇编嵌入到 C 程序中,为什
我正计划构建一个 Web 服务客户端,它始终检查数据库中的某些记录,并根据数据库内容的结果在每个时刻及时执行某些决策。 所以我在想,我怎样才能让客户端一直运行呢? 我唯一想到的就是无限循环。像这样的东
我无法获取小部件的实际背景颜色。在我的特殊情况下,我在使用 QTabWidget 中的小部件时遇到了问题。 这是在 Windows7 上。所以经典小部件有一些灰色背景,而选项卡中的小部件通常用白色背景
请不要将我指向How to wrap preference title?因为它不适用于(正如我评论的那样)您使用 @strings/ 的情况对 strings.xml 文件的引用。 如果你使用 and
情况如下: 已知hdfs是仅附加的(本身没有更新)。 配置单元将数据写入其位于hdfs中的仓库。 可以在配置单元中执行更新 这意味着写入了新数据,旧数据应该以某种方式标记为已弃用,然后在某个时间将其清
在javascript中删除cookies的方法是将过期日期设置为过去。现在这实际上并没有删除 cookie,至少在 Firefox 中是这样。这只是意味着 cookie 将在浏览器关闭时被删除。 这
我需要终止一个卡住的线程,我将 IsBackground 设置为 true 但它仍然存在。线程的属性: ThreadState = AbortRequested IsBackground = true
在逻辑中,以及在 *ahem* 正确设计的编程语言中,将 boolean 值与 true 进行比较总是多余的,即 a == True 应该简单地替换为 a 。 (类似地, a == False 由 n
我一直在努力寻找一个好的定义,并理解线程到底是什么。 看来我一定错过了一些明显的东西,但是每次我读到什么是线程时,它几乎是一个循环定义,la“线程是一个执行线程”或“一种划分运行任务的方法” ”。呃呃
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
是否可以在 MAC 上以真正的全屏模式运行 IntelliJ Idea? 没有工具栏、侧边栏、按钮,只有代码。 如果可以,请告诉我。 最佳答案 您可以通过禁用以下项目在 View 菜单中执行此操作:
考虑以下代码: case class Vector3(var x: Float, var y: Float, var z: Float) { def add(v: Vector3): Unit =
我试图确认这个说法是否属实: 模型包括: 持久层:本质上是 DAO + 表示表的类 + DTO 服务层:DAOS + 一些逻辑的组合 您能否也引用/支持您的回答?我相信我在Spring Framewo
给定代码: #include struct X {}; struct Y1: virtual X {}; struct Y2: virtual X {}; struct Y3: virtual X
从这个其他QUESTION他们谈论 Bjarne Stroustrup 是如何说的,就像比 int 窄的整数数据类型(例如 short)被提升为 int,float 被提升为 double。但是,与i
我是一名优秀的程序员,十分优秀!