IO流你了解多少
IO流你了解多少
🏠个人主页:shark-Gao
🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉
🎉目前状况:23届毕业生,目前在某公司实习👏👏
❤️欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘
🖥️个人小站 :个人博客,欢迎大家访问
CSDN发布的文章同样会在个人小站折腾后记 个人博客进行同步,欢迎大家指点!!!
1 初始IO
IO,即in和out,也就是输入和输出,指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。
Java 中是通过流处理IO 的,那么什么是流?
流(Stream),是一个抽象的概念,是指一连串的数据(字符或字节),是以先进先出的方式发送信息的通道。
当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。
一般来说关于流的特性有下面几点:
- 先进先出:最先写入输出流的数据最先被输入流读取到。
- 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(
RandomAccessFile除外) - 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。
1.1 为什么要学习IO流
- 通过变量,数组,或者集合存储数据
- 都是不能永久化存储 , 因为数据都是存储在内存中
- 只要代码运行结束,所有数据都会丢失
- 使用IO流
- 1,将数据写到文件中,实现数据永久化存储
- 2,把文件中的数据读取到内存中(Java程序)
1.2 什么是IO流
- I 表示intput ,是数据从硬盘进内存的过程,称之为读。
- O 表示output ,是数据从内存到硬盘的过程。称之为写
- IO的数据传输,可以看做是一种数据的流动,按照流动的方向,以内存为参照物,进行读写操作
- 简单来说:内存在读,内存在写
1.3 IO流的分类
- 按照流向区分
- 输入流 : 用来读取数据
- 输出流 : 用来写入数据
- 按照类型区分
- 字节流
- 字符流
- 注意 :
- 字节流可以操作任意文件
- 字符流只能操作纯文本文件
- 用windows记事本打开能读的懂,那么这样的文件就是纯文本文件。
1、输入流与输出流
输入与输出是相对于应用程序而言的,比如文件读写,读取文件是输入流,写文件是输出流,这点很容易搞反。

2、字节流与字符流
字节流和字符流的用法几乎完成全一样,区别在于字节流和字符流所操作的数据单元不同,字节流操作的单元是数据单元是8位的字节,字符流操作的是数据单元为16位的字符。
为什么要有字符流?

Java中字符是采用Unicode标准,Unicode 编码中,一个英文字母或一个中文汉字为两个字节。
而在UTF-8编码中,一个中文字符是3个字节。例如下面图中,“云深不知处”5个中文对应的是15个字节:-28-70-111-26-73-79-28-72-115-25-97-91-27-92-124

那么问题来了,如果使用字节流处理中文,如果一次读写一个字符对应的字节数就不会有问题,一旦将一个字符对应的字节分裂开来,就会出现乱码了。为了更方便地处理中文这些字符,Java就推出了字符流。
字节流和字符流的其他区别:
字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。用一句话说就是:字节流可以处理一切文件,而字符流只能处理纯文本文件。
字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。而字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了。
3、节点流和处理流
节点流:直接操作数据读写的流类,比如FileInputStream
处理流:对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能,例如BufferedInputStream(缓冲字节流)
处理流和节点流应用了Java的装饰者设计模式。
下图就很形象地描绘了节点流和处理流,处理流是对节点流的封装,最终的数据处理还是由节点流完成的。
在诸多处理流中,有一个非常重要,那就是缓冲流。
我们知道,程序与磁盘的交互相对于内存运算是很慢的,容易成为程序的性能瓶颈。减少程序与磁盘的交互,是提升程序效率一种有效手段。缓冲流,就应用这种思路:普通流每次读写一个字节,而缓冲流在内存中设置一个缓存区,缓冲区先存储足够的待操作数据后,再与内存或磁盘进行交互。这样,在总数据量不变的情况下,通过提高每次交互的数据量,减少了交互次数。
2 字节流输出流
InputStream类有很多的实现子类,下面列举了一些比较常用的:

2.1 字节输出流入门
-
FileOutputStream类 :
OutputStream有很多子类,我们从最简单的一个子类开始。java.io.FileOutputStream类是文件输出流,用于将数据写出到文件
-
字节输出流
OutputStream主要方法:- write(byte[] b) :将 b.length 个字节从指定 byte 数组写入此文件输出流中。
- write(byte[] b, int off, int len) :将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
- write(int b) :将指定字节写入此文件输出流。
- close() :关闭此输入流并释放与该流关联的所有系统资源。
public class FileOutputStreamConstructor throws IOException {public static void main(String[] args) {// 使用File对象创建流对象File file = new File("a.txt");FileOutputStream fos = new FileOutputStream(file);// 使用文件名称创建流对象FileOutputStream fos = new FileOutputStream("b.txt");} } -
字节输出流写数据快速入门
- 创建字节输出流对象。
- 写数据
- 释放资源
package com.itheima.outputstream_demo;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;/*字节输出流写数据快速入门 :1 创建字节输出流对象。2 写数据3 释放资源*/ public class OutputStreamDemo1 {public static void main(String[] args) throws IOException {// 创建字节输出流对象// 如果指定的文件不存在 , 会自动创建文件// 如果文件存在 , 会把文件中的内容清空FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");// 写数据// 写到文件中就是以字节形式存在的// 只是文件帮我们把字节翻译成了对应的字符 , 方便查看fos.write(97);fos.write(98);fos.write(99);// 释放资源// while(true){}// 断开流与文件中间的关系fos.close();} }
2.2 字节输出流写数据的方法
-
字节流写数据的方法
- 1 void write(int b) 一次写一个字节数据
- 2 void write(byte[] b) 一次写一个字节数组数据
- 3 void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据
package com.itheima.outputstream_demo;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;/*字节流写数据的3种方式1 void write(int b) 一次写一个字节数据2 void write(byte[] b) 一次写一个字节数组数据3 void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据*/ public class OutputStreamDemo2 {public static void main(String[] args) throws IOException {// 创建字节输出流对象FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");// 写数据 // 1 void write(int b) 一次写一个字节数据fos.write(97);fos.write(98);fos.write(99);// 2 void write(byte[] b) 一次写一个字节数组数据byte[] bys = {65, 66, 67, 68, 69};fos.write(bys);// 3 void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据fos.write(bys, 0, 3);// 释放资源fos.close();} }
2.3 写数据的换行和追加写入
package com.itheima.outputstream_demo;import java.io.FileOutputStream;
import java.io.IOException;/*字节流写数据的换行和追加写入1 字节流写数据如何实现换行呢?写完数据后,加换行符windows : \r\nlinux : \nmac : \r2 字节流写数据如何实现追加写入呢?通过构造方法 : public FileOutputStream(String name,boolean append)创建文件输出流以指定的名称写入文件。如果第二个参数为true ,不会清空文件里面的内容*/
public class OutputStreamDemo3 {public static void main(String[] args) throws IOException {// 创建字节输出流对象FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");// void write(int b) 一次写一个字节数据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.close();}
}
package com.itheima.outputstream_demo;import java.io.FileOutputStream;
import java.io.IOException;/*字节流写数据的换行和追加写入1 字节流写数据如何实现换行呢?写完数据后,加换行符windows : \r\nlinux : \nmac : \r2 字节流写数据如何实现追加写入呢?通过构造方法 : public FileOutputStream(String name,boolean append)创建文件输出流以指定的名称写入文件。如果第二个参数为true ,不会清空文件里面的内容*/
public class OutputStreamDemo3 {public static void main(String[] args) throws IOException {// 创建字节输出流对象// 追加写数据// 通过构造方法 : public FileOutputStream(String name,boolean append) : 追加写数据FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt" , true);// void write(int b) 一次写一个字节数据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.close();}// 写完数据换行操作private static void method1() throws IOException {// 创建字节输出流对象FileOutputStream fos = new FileOutputStream("day11_demo\\a.txt");// void write(int b) 一次写一个字节数据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.close();}
}
3 字节输入流
3.1 字节输入流介绍
-
字节输入流类
- InputStream类 : 字节输入流最顶层的类 , 抽象类
— FileInputStream类 : FileInputStream extends InputStream
- InputStream类 : 字节输入流最顶层的类 , 抽象类
-
字节输入流
InputStream主要方法:- read() :从此输入流中读取一个数据字节。
- read(byte[] b) :从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
- read(byte[] b, int off, int len) :从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
- close():关闭此输入流并释放与该流关联的所有系统资源。
-
步骤
- 创建输入流对象
- 读数据
- 释放资源
-
package com.itheima.inputstream_demo;import java.io.FileInputStream; import java.io.IOException;/*字节输入流写数据快速入门 : 一次读一个字节第一部分 : 字节输入流类InputStream类 : 字节输入流最顶层的类 , 抽象类--- FileInputStream类 : FileInputStream extends InputStream第二部分 : 构造方法public FileInputStream(File file) : 从file类型的路径中读取数据public FileInputStream(String name) : 从字符串路径中读取数据第三部分 : 字节输入流步骤1 创建输入流对象2 读数据3 释放资源*/ public class FileInputStreamDemo1 {public static void main(String[] args) throws IOException {// 创建字节输入流对象// 读取的文件必须存在 , 不存在则报错FileInputStream fis = new FileInputStream("day11_demo\\a.txt");// 读数据 , 从文件中读到一个字节// 返回的是一个int类型的字节// 如果想看字符, 需要强转int by = fis.read();System.out.println((char) by);// 释放资源fis.close();} }
3.2 字节输入流读多个字节
package com.itheima.inputstream_demo;import java.io.FileInputStream;
import java.io.IOException;/*字节输入流写数据快速入门 : 读多个字节第一部分 : 字节输入流类InputStream类 : 字节输入流最顶层的类 , 抽象类--- FileInputStream类 : FileInputStream extends InputStream第二部分 : 构造方法public FileInputStream(File file) : 从file类型的路径中读取数据public FileInputStream(String name) : 从字符串路径中读取数据第三部分 : 字节输入流步骤1 创建输入流对象2 读数据3 释放资源*/
public class FileInputStreamDemo2 {public static void main(String[] args) throws IOException {// 创建字节输入流对象// 读取的文件必须存在 , 不存在则报错FileInputStream fis = new FileInputStream("day11_demo\\a.txt");// 读数据 , 从文件中读到一个字节// 返回的是一个int类型的字节// 如果想看字符, 需要强转
// int by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);
//
// by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);
// by = fis.read();
// System.out.println(by);// 循环改进int by;// 记录每次读到的字节while ((by = fis.read()) != -1) {System.out.print((char) by);}// 释放资源fis.close();}
}
3.3 图片的拷贝
package com.itheima.inputstream_demo;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;/*需求 : 把 "图片路径\xxx.jpg" 复制到当前模块下分析:复制文件,其实就把文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)数据源:xxx.jpg --- 读数据 --- FileInputStream目的地:模块名称\copy.jpg --- 写数据 --- FileOutputStream*/
public class FileInputStreamDemo2 {public static void main(String[] args) throws IOException {// 创建字节输入流对象FileInputStream fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");// 创建字节输出流FileOutputStream fos = new FileOutputStream("day11_demo\\copy.jpg");// 一次读写一个字节int by;while ((by = fis.read()) != -1) {fos.write(by);}// 释放资源fis.close();fos.close();}
}
3.4 异常的捕获处理
-
JDK7版本之前处理方式 : 手动释放资源
package com.itheima.inputstream_demo;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;/*需求 : 对上一个赋值图片的代码进行使用捕获方式处理*/ public class FileInputStreamDemo4 {public static void main(String[] args) {FileInputStream fis = null ;FileOutputStream fos = null;try {// 创建字节输入流对象fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");// 创建字节输出流fos = new FileOutputStream("day11_demo\\copy.jpg");// 一次读写一个字节int by;while ((by = fis.read()) != -1) {fos.write(by);}} catch (IOException e) {e.printStackTrace();} finally {// 释放资源if(fis != null){try {fis.close();} catch (IOException e) {e.printStackTrace();}}// 释放资源if(fos != null){try {fos.close();} catch (IOException e) {e.printStackTrace();}}}} } -
JDK7版本优化处理方式 : 自动释放资源
-
JDK7优化后可以使用 try-with-resource 语句 , 该语句确保了每个资源在语句结束时自动关闭。
简单理解 : 使用此语句,会自动释放资源 , 不需要自己在写finally代码块了 -
格式 :
格式 : try (创建流对象语句1 ; 创建流对象语句2 ...) {// 读写数据} catch (IOException e) {处理异常的代码...}举例 :try ( FileInputStream fis1 = new FileInputStream("day11_demo\\a.txt") ; FileInputStream fis2 = new FileInputStream("day11_demo\\b.txt") ) {// 读写数据} catch (IOException e) {处理异常的代码...}
-
-
代码实践
package com.itheima.inputstream_demo;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;/*JDK7版本优化处理方式需求 : 对上一个赋值图片的代码进行使用捕获方式处理*/ public class FileInputStreamDemo5 {public static void main(String[] args) {try (// 创建字节输入流对象FileInputStream fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");// 创建字节输出流FileOutputStream fos = new FileOutputStream("day11_demo\\copy.jpg")) {// 一次读写一个字节int by;while ((by = fis.read()) != -1) {fos.write(by);}// 释放资源 , 发现已经灰色 , 提示多余的代码 , 所以使用 try-with-resource 方式会自动关流// fis.close();// fos.close();} catch (IOException e) {e.printStackTrace();}} }
3.4 字节输入流一次读一个字节数组
-
FileInputStream类 :
- public int read(byte[] b) : 从输入流读取最多b.length个字节的数据, 返回的是真实读到的数据个数
package com.itheima.inputstream_demo;import javax.sound.midi.Soundbank; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException;/*FileInputStream类 :public int read(byte[] b):1 从输入流读取最多b.length个字节的数据2 返回的是真实读到的数据个数*/ public class FileInputStreamDemo6 {public static void main(String[] args) throws IOException {// 创建字节输入流对象FileInputStream fis = new FileInputStream("day11_demo\\a.txt");// public int read(byte[] b): // 1 从输入流读取最多b.length个字节的数据 // 2 返回的是真实读到的数据个数byte[] bys = new byte[3];// int len = fis.read(bys); // System.out.println(len);// 3 // System.out.println(new String(bys));// abc // // len = fis.read(bys); // System.out.println(len);// 2 // System.out.println(new String(bys));// efcSystem.out.println("==========代码改进===============");// int len = fis.read(bys); // System.out.println(len);// 3 // System.out.println(new String(bys, 0, len));// abc // // len = fis.read(bys); // System.out.println(len);// 2 // System.out.println(new String(bys, 0, len));// efSystem.out.println("==========代码改进===============");int len;while ((len = fis.read(bys)) != -1) {System.out.print(new String(bys , 0 , len));}fis.close();} } -
对复制图片的代码进行使用一次读写一个字节数组的方式进行改进
package com.itheima.inputstream_demo;import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;/*需求 : 对复制图片的代码进行使用一次读写一个字节数组的方式进行改进FileInputStream类 :public int read(byte[] b):1 从输入流读取最多b.length个字节的数据2 返回的是真实读到的数据个数*/ public class FileInputStreamDemo7 {public static void main(String[] args) throws IOException {// 创建字节输入流对象FileInputStream fis = new FileInputStream("D:\\传智播客\\安装包\\好看的图片\\liqin.jpg");// 创建字节输出流FileOutputStream fos = new FileOutputStream("day11_demo\\copy.jpg");byte[] bys = new byte[1024];int len;// 每次真实读到数据的个数int by;while ((len = fis.read(bys)) != -1) {fos.write(bys, 0, len);}// 释放资源fis.close();fos.close();} }
4 字符流
与字节流类似,字符流也有两个抽象基类,分别是Reader和Writer。其他的字符流实现类都是继承了这两个类。
以Reader为例,它的主要实现子类如下图:


当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
小贴士:字符流,只能操作文本文件,不能操作图片,视频等非文本文件。当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流。
4.4.1 字符输入流【Reader】
java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
public int read(): 从输入流读取一个字符。 虽然读取了一个字符,但是会自动提升为int类型。返回该字符的Unicode编码值。如果已经到达流末尾了,则返回-1。public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。每次最多读取cbuf.length个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。public int read(char[] cbuf,int off,int len):从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,从cbuf[off]开始的位置存储。每次最多读取len个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。public void close():关闭此流并释放与此流相关联的任何系统资源。
小贴士:close方法,当完成流的操作时,必须调用此方法,释放系统资源。
4.4.2 FileReader类
java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径。类似于FileInputStream 。如果该文件不存在,则报FileNotFoundException。如果传入的是一个目录,则会报IOException异常。
package com.atguigu.fileio;import org.junit.Test;import java.io.FileReader;
import java.io.IOException;public class FRRead {@Testpublic void test01() throws IOException {// 使用文件名称创建流对象FileReader fr = new FileReader("read.txt");// 定义变量,保存数据int b;// 循环读取while ((b = fr.read())!=-1) {System.out.println((char)b);}// 关闭资源fr.close();
/*输出结果:尚硅谷*/}@Testpublic void test02()throws IOException {// 使用文件名称创建流对象FileReader fr = new FileReader("read.txt");// 定义变量,保存有效字符个数int len;// 定义字符数组,作为装字符数据的容器char[] cbuf = new char[2];// 循环读取while ((len = fr.read(cbuf))!=-1) {System.out.println(new String(cbuf));}// 关闭资源fr.close();/*输出结果:尚硅谷硅最后错误数据硅,是因为最后一次流中只有一个字符“谷”,读取一个字符没有覆盖char[]数组cbuf的所有元素*/}@Testpublic void test03() throws IOException {// 使用文件名称创建流对象FileReader fr = new FileReader("read.txt");// 定义变量,保存有效字符个数int len;// 定义字符数组,作为装字符数据的容器char[] cbuf = new char[2];// 循环读取while ((len = fr.read(cbuf)) != -1) {System.out.println(new String(cbuf, 0, len));}// 关闭资源fr.close();/*输出结果:尚硅谷*/}}
4.4.3 字符输出流【Writer】
java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void write(int c)写入单个字符。public void write(char[] cbuf)写入字符数组。public void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。public void write(String str)写入字符串。public void write(String str, int off, int len)写入字符串的某一部分,off字符串的开始索引,len写的字符个数。public void flush()刷新该流的缓冲。public void close()关闭此流,但要先刷新它。
4.4.4 FileWriter类
java.io.FileWriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。如果文件不存在,则会自动创建。如果文件已经存在,则会清空文件内容,写入新的内容。
1、写出字符数据
package com.atguigu.fileio;import org.junit.Test;import java.io.FileWriter;
import java.io.IOException;public class FWWrite {@Testpublic void test01()throws IOException {// 使用文件名称创建流对象FileWriter fw = new FileWriter("fw.txt");// 写出数据fw.write(97); // 写出第1个字符fw.write('b'); // 写出第2个字符fw.write('C'); // 写出第3个字符fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字。/*【注意】FileWriter与FileOutputStream不同。如果不关闭,数据只是保存到缓冲区,并未保存到文件。*/// fw.close();}@Testpublic void test02()throws IOException {// 使用文件名称创建流对象FileWriter fw = new FileWriter("fw.txt");// 字符串转换为字节数组char[] chars = "尚硅谷".toCharArray();// 写出字符数组fw.write(chars); // 尚硅谷// 写出从索引1开始,2个字符。fw.write(chars,1,2); // 硅谷// 关闭资源fw.close();}@Testpublic void test03()throws IOException {// 使用文件名称创建流对象FileWriter fw = new FileWriter("fw.txt");// 字符串String msg = "尚硅谷";// 写出字符数组fw.write(msg); //尚硅谷// 写出从索引1开始,2个字符。fw.write(msg,1,2); // 硅谷// 关闭资源fw.close();}
}
2、续写
public FileWriter(File file,boolean append): 创建文件输出流以写入由指定的 File对象表示的文件。public FileWriter(String fileName,boolean append): 创建文件输出流以指定的名称写入文件。
这两个构造方法,参数中都需要传入一个boolean类型的值,true 表示追加数据,false 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了,代码使用演示:
操作类似于FileOutputStream。
package com.atguigu.fileio;import org.junit.Test;import java.io.FileWriter;
import java.io.IOException;public class FWWriteAppend {@Testpublic void test01()throws IOException {// 使用文件名称创建流对象,可以续写数据FileWriter fw = new FileWriter("fw.txt",true);// 写出字符串fw.write("尚硅谷真棒");// 关闭资源fw.close();}
}
3、换行
package com.atguigu.fileio;import java.io.FileWriter;
import java.io.IOException;public class FWWriteNewLine {public static void main(String[] args) throws IOException {// 使用文件名称创建流对象,可以续写数据FileWriter fw = new FileWriter("fw.txt");// 写出字符串fw.write("尚");// 写出换行fw.write("\r\n");// 写出字符串fw.write("硅谷");// 关闭资源fw.close();}
}
4、关闭和刷新
【注意】FileWriter与FileOutputStream不同。因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。
flush:刷新缓冲区,流对象可以继续使用。close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
代码使用演示:
package com.atguigu.fileio;import java.io.FileWriter;
import java.io.IOException;public class FWWriteFlush {public static void main(String[] args)throws IOException {// 使用文件名称创建流对象FileWriter fw = new FileWriter("fw.txt");// 写出数据,通过flushfw.write('刷'); // 写出第1个字符fw.flush();fw.write('新'); // 继续写出第2个字符,写出成功fw.flush();// 写出数据,通过closefw.write('关'); // 写出第1个字符fw.close();fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closedfw.close();}
}
小贴士:即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
5 缓冲流
缓冲流,也叫高效流,按照数据类型分类:
- 字节缓冲流:
BufferedInputStream,BufferedOutputStream - 字符缓冲流:
BufferedReader,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
5.1 构造方法
public BufferedInputStream(InputStream in):创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流。
构造举例,代码如下:
// 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
public BufferedReader(Reader in):创建一个 新的缓冲输入流。public BufferedWriter(Writer out): 创建一个新的缓冲输出流。
构造举例,代码如下:
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
5.2 效率测试
查询API,缓冲流读写方法与基本的流是一致的,我们通过复制大文件(375MB),测试它的效率。
package com.atguigu.buffer;import org.junit.Test;import java.io.*;public class BufferedIO {@Testpublic void testNoBuffer() throws IOException {// 记录开始时间long start = System.currentTimeMillis();// 创建流对象FileInputStream fis = new FileInputStream("jdk8.exe");FileOutputStream fos = new FileOutputStream("copy.exe");// 读写数据byte[] data = new byte[1024];int len;while ((len = fis.read(data)) != -1) {fos.write(data,0,len);}fos.close();fis.close();// 记录结束时间long end = System.currentTimeMillis();System.out.println("普通流复制时间:"+(end - start)+" 毫秒");}@Testpublic void testUseBuffer() throws IOException {// 记录开始时间long start = System.currentTimeMillis();// 创建流对象BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk8.exe"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));// 读写数据int len;byte[] data = new byte[1024];while ((len = bis.read(data)) != -1) {bos.write(data, 0 , len);}bos.close();bis.close();// 记录结束时间long end = System.currentTimeMillis();System.out.println("缓冲流使用数组复制时间:"+(end - start)+" 毫秒");}
}
5.3 字符缓冲流特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
- BufferedReader:
public String readLine(): 读一行文字。 - BufferedWriter:
public void newLine(): 写一行行分隔符,由系统属性定义符号。
package com.atguigu.buffer;import org.junit.Test;import java.io.*;public class BufferedIOLine {@Testpublic void testReadLine()throws IOException {// 创建流对象BufferedReader br = new BufferedReader(new FileReader("in.txt"));// 定义字符串,保存读取的一行文字String line;// 循环读取,读取到最后返回nullwhile ((line = br.readLine())!=null) {System.out.println(line);}// 释放资源br.close();}@Testpublic void testNewLine()throws IOException{// 创建流对象BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));// 写出数据bw.write("尚");// 写出换行bw.newLine();bw.write("硅");bw.newLine();bw.write("谷");bw.newLine();// 释放资源bw.close();}
}
5.4 流的关闭顺序
package com.atguigu.buffer;import org.junit.Test;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;public class IOClose {@Testpublic void test01() throws IOException {FileWriter fw = new FileWriter("d:/1.txt");BufferedWriter bw = new BufferedWriter(fw);bw.write("hello");fw.close();bw.close();//java.io.IOException: Stream closed/*缓冲流BufferedWriter,把数据先写到缓冲区,默认情况下是当缓冲区满,或调用close,或调用flush这些情况才会把缓冲区的数据输出。bw.close()时,需要把数据从缓冲区的数据输出。数据的流向: 写到bw(缓冲区)-->fw ->"d:/1.txt"此时,我先把fw关闭了,bw的数据无法输出了*/}@Testpublic void test02() throws IOException {FileWriter fw = new FileWriter("d:/1.txt");BufferedWriter bw = new BufferedWriter(fw);bw.write("hello");bw.close();fw.close();/*原则:先关外面的,再关里面的。例如:FileWriter fw = new FileWriter("d:/1.txt"); //里面 穿内衣BufferedWriter bw = new BufferedWriter(fw); //外面 穿外套关闭bw.close(); //先关外面的 先脱外套fw.close(); //再关里面的 再脱内衣*/}
}
6 其他内容
6.1 位、字节、字符
字节(Byte)是计量单位,表示数据量多少,是计算机信息技术用于计量存储容量的一种计量单位,通常情况下一字节等于八位。
字符(Character)计算机中使用的字母、数字、字和符号,比如’A’、‘B’、’$’、’&'等。
一般在英文状态下一个字母或字符占用一个字节,一个汉字用两个字节表示。
字节与字符:
- ASCII 码中,一个英文字母(不分大小写)为一个字节,一个中文汉字为两个字节。
- UTF-8 编码中,一个英文字为一个字节,一个中文为三个字节。
- Unicode 编码中,一个英文为一个字节,一个中文为两个字节。
- 符号:英文标点为一个字节,中文标点为两个字节。例如:英文句号 . 占1个字节的大小,中文句号 。占2个字节的大小。
- UTF-16 编码中,一个英文字母字符或一个汉字字符存储都需要 2 个字节(Unicode 扩展区的一些汉字存储需要 4 个字节)。
- UTF-32 编码中,世界上任何字符的存储都需要 4 个字节。
6.2 IO流效率对比
首先,对比下普通字节流和缓冲字节流的效率:
public class MyTest {public static void main(String[] args) throws IOException {File file = new File("C:/Mu/test.txt");StringBuilder sb = new StringBuilder();for (int i = 0; i < 3000000; i++) {sb.append("abcdefghigklmnopqrstuvwsyz");}byte[] bytes = sb.toString().getBytes();long start = System.currentTimeMillis();write(file, bytes);long end = System.currentTimeMillis();long start2 = System.currentTimeMillis();bufferedWrite(file, bytes);long end2 = System.currentTimeMillis();System.out.println("普通字节流耗时:" + (end - start) + " ms");System.out.println("缓冲字节流耗时:" + (end2 - start2) + " ms");}// 普通字节流public static void write(File file, byte[] bytes) throws IOException {OutputStream os = new FileOutputStream(file);os.write(bytes);os.close();}// 缓冲字节流public static void bufferedWrite(File file, byte[] bytes) throws IOException {BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(file));bo.write(bytes);bo.close();}
}
运行结果:
普通字节流耗时:250 ms
缓冲字节流耗时:268 ms
这个结果让我大跌眼镜,不是说好缓冲流效率很高么?要知道为什么,只能去源码里找答案了。翻看字节缓冲流的write方法:
public synchronized void write(byte b[], int off, int len) throws IOException {if (len >= buf.length) {/* If the request length exceeds the size of the output buffer,flush the output buffer and then write the data directly.In this way buffered streams will cascade harmlessly. */flushBuffer();out.write(b, off, len);return;}if (len > buf.length - count) {flushBuffer();}System.arraycopy(b, off, buf, count, len);count += len;
}
注释里说得很明白:如果请求长度超过输出缓冲区的大小,刷新输出缓冲区,然后直接写入数据。这样,缓冲流将无害地级联。
但是,至于为什么这么设计,我没有想明白,有哪位明白的大佬可以留言指点一下。
基于上面的情形,要想对比普通字节流和缓冲字节流的效率差距,就要避免直接读写较长的字符串,于是,设计了下面这个对比案例:用字节流和缓冲字节流分别复制文件。
public class MyTest {public static void main(String[] args) throws IOException {File data = new File("C:/Mu/data.zip");File a = new File("C:/Mu/a.zip");File b = new File("C:/Mu/b.zip");StringBuilder sb = new StringBuilder();long start = System.currentTimeMillis();copy(data, a);long end = System.currentTimeMillis();long start2 = System.currentTimeMillis();bufferedCopy(data, b);long end2 = System.currentTimeMillis();System.out.println("普通字节流耗时:" + (end - start) + " ms");System.out.println("缓冲字节流耗时:" + (end2 - start2) + " ms");}// 普通字节流public static void copy(File in, File out) throws IOException {// 封装数据源InputStream is = new FileInputStream(in);// 封装目的地OutputStream os = new FileOutputStream(out);int by = 0;while ((by = is.read()) != -1) {os.write(by);}is.close();os.close();}// 缓冲字节流public static void bufferedCopy(File in, File out) throws IOException {// 封装数据源BufferedInputStream bi = new BufferedInputStream(new FileInputStream(in));// 封装目的地BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(out));int by = 0;while ((by = bi.read()) != -1) {bo.write(by);}bo.close();bi.close();}
}
运行结果:
普通字节流耗时:184867 ms
缓冲字节流耗时:752 ms
这次,普通字节流和缓冲字节流的效率差异就很明显了,达到了245倍。
再看看字符流和缓冲字符流的效率对比:
public class IOTest {public static void main(String[] args) throws IOException {// 数据准备dataReady();File data = new File("C:/Mu/data.txt");File a = new File("C:/Mu/a.txt");File b = new File("C:/Mu/b.txt");File c = new File("C:/Mu/c.txt");long start = System.currentTimeMillis();copy(data, a);long end = System.currentTimeMillis();long start2 = System.currentTimeMillis();copyChars(data, b);long end2 = System.currentTimeMillis();long start3 = System.currentTimeMillis();bufferedCopy(data, c);long end3 = System.currentTimeMillis();System.out.println("普通字节流1耗时:" + (end - start) + " ms,文件大小:" + a.length() / 1024 + " kb");System.out.println("普通字节流2耗时:" + (end2 - start2) + " ms,文件大小:" + b.length() / 1024 + " kb");System.out.println("缓冲字节流耗时:" + (end3 - start3) + " ms,文件大小:" + c.length() / 1024 + " kb");}// 普通字符流不使用数组public static void copy(File in, File out) throws IOException {Reader reader = new FileReader(in);Writer writer = new FileWriter(out);int ch = 0;while ((ch = reader.read()) != -1) {writer.write((char) ch);}reader.close();writer.close();}// 普通字符流使用字符流public static void copyChars(File in, File out) throws IOException {Reader reader = new FileReader(in);Writer writer = new FileWriter(out);char[] chs = new char[1024];while ((reader.read(chs)) != -1) {writer.write(chs);}reader.close();writer.close();}// 缓冲字符流public static void bufferedCopy(File in, File out) throws IOException {BufferedReader br = new BufferedReader(new FileReader(in));BufferedWriter bw = new BufferedWriter(new FileWriter(out));String line = null;while ((line = br.readLine()) != null) {bw.write(line);bw.newLine();bw.flush();}// 释放资源bw.close();br.close();}// 数据准备public static void dataReady() throws IOException {StringBuilder sb = new StringBuilder();for (int i = 0; i < 600000; i++) {sb.append("abcdefghijklmnopqrstuvwxyz");}OutputStream os = new FileOutputStream(new File("C:/Mu/data.txt"));os.write(sb.toString().getBytes());os.close();System.out.println("完毕");}
}
运行结果:
普通字符流1耗时:1337 ms,文件大小:15234 kb
普通字符流2耗时:82 ms,文件大小:15235 kb
缓冲字符流耗时:205 ms,文件大小:15234 kb
测试多次,结果差不多,可见字符缓冲流效率上并没有明显提高,我们更多的是要使用它的readLine()和newLine()方法。
7、重新认识System.out和Scanner
7.1 PrintStream类
我们每天都在用的System.out对象是PrintStream类型的。它也是IO流对象。
PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;另外,PrintStream 可以设置自动刷新。
- PrintStream(File file) :创建具有指定文件且不带自动行刷新的新打印流。
- PrintStream(File file, String csn):创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
- PrintStream(OutputStream out) :创建新的打印流。
- PrintStream(OutputStream out, boolean autoFlush):创建新的打印流。 autoFlush如果为 true,则每当写入 byte 数组、调用其中一个 println 方法或写入换行符或字节 (‘\n’) 时都会刷新输出缓冲区。
- PrintStream(OutputStream out, boolean autoFlush, String encoding) :创建新的打印流。
- PrintStream(String fileName):创建具有指定文件名称且不带自动行刷新的新打印流。
- PrintStream(String fileName, String csn) :创建具有指定文件名称和字符集且不带自动行刷新的新打印流。


package com.atguigu.systemio;import java.io.FileNotFoundException;
import java.io.PrintStream;public class TestPrintStream {public static void main(String[] args) throws FileNotFoundException {PrintStream ps = new PrintStream("io.txt");ps.println("hello");ps.println(1);ps.println(1.5);ps.close();}
}
72 Scanner类
构造方法
- Scanner(File source) :构造一个新的 Scanner,它生成的值是从指定文件扫描的。
- Scanner(File source, String charsetName) :构造一个新的 Scanner,它生成的值是从指定文件扫描的。
- Scanner(InputStream source) :构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
- Scanner(InputStream source, String charsetName) :构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
常用方法:
- boolean hasNextXxx(): 如果通过使用nextXxx()方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 Xxx 值,则返回 true。
- Xxx nextXxx(): 将输入信息的下一个标记扫描为一个Xxx
package com.atguigu.systemio;import org.junit.Test;import java.io.*;
import java.util.Scanner;public class TestScanner {@Testpublic void test01() throws IOException {Scanner input = new Scanner(System.in);PrintStream ps = new PrintStream("1.txt");while(true){System.out.print("请输入一个单词:");String str = input.nextLine();if("stop".equals(str)){break;}ps.println(str);}input.close();ps.close();}@Testpublic void test2() throws IOException {Scanner input = new Scanner(new FileInputStream("1.txt"));while(input.hasNextLine()){String str = input.nextLine();System.out.println(str);}input.close();}
}
7.3 System类的三个IO流对象
System类中有三个常量对象:
- System.out
- System.in
- System.err
查看System类中这三个常量对象的声明:
public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;
奇怪的是,
- 这三个常量对象有final声明,但是却初始化为null。final声明的常量一旦赋值就不能修改,那么null不会空指针异常吗?
- 这三个常量对象为什么要小写?final声明的常量按照命名规范不是应该大写吗?
- 这三个常量的对象有set方法?final声明的常量不是不能修改值吗?set方法是如何修改它们的值的?
final声明的常量,表示在Java的语法体系中它们的值是不能修改的,而这三个常量对象的值是由C/C++等系统函数进行初始化和修改值的,所以它们故意没有用大写,也有set方法。
public static void setOut(PrintStream out) {checkIO();setOut0(out);}public static void setErr(PrintStream err) {checkIO();setErr0(err);}public static void setIn(InputStream in) {checkIO();setIn0(in);}private static void checkIO() {SecurityManager sm = getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("setIO"));}}private static native void setIn0(InputStream in);private static native void setOut0(PrintStream out);private static native void setErr0(PrintStream err);
相关文章:
IO流你了解多少
IO流你了解多少 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生,目前在某公…...
【C++】C++ 11 新特性之auto关键字
文章目录类型别名的思考auto简介auto关键字的特性类型别名的思考 随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在: 类型难于拼写含义不明确导致容易出错 #include <string> #include <map> int main() {std::ma…...
nodejs的后端框架egg,thinkjs,nestjs,nuxtjs,nextjs对比
1. Egg.js:优点:Egg.js是一个基于Koa的Node.js企业级应用开发框架,它提供了完整的开发规范和一套稳定性和安全性较高的架构体系,能够帮助开发者快速构建高可用、高性能的应用程序。同时,Egg.js还提供了很多自定义插件和…...
SpringBoot @SpringBootTest 无法启动服务
这几天在看Hikari、Druid连接池。按照网上代码写Junit测试类。当时代码如下: package com.ceaning.crudp.utils;import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; impo…...
PyTorch深度学习实战 | 神经网络的优化难题
即使我们可以利用反向传播来进行优化,但是训练过程中仍然会出现一系列的问题,比如鞍点、病态条件、梯度消失和梯度爆炸,对此我们首先提出了小批量随机梯度下降,并且基于批量随机梯度下降的不稳定的特点,继续对其做出方…...
如何缩小pdf文件的大小便于上传?在线压缩pdf工具推荐
平时在工作、学习时我们经常都需要用到pdf文件,那么当遇上需要将pdf压缩大小的时候,该使用哪种pdf压缩(https://www.yasuotu.com/pdfyasuo)方式呢?今天分享一个在线压缩pdf的方法,需要的小伙伴一起来了解…...
使用C++编写一个AVL的增删改查代码并附上代码解释
//qq460219753提供其他代码帮助 #include <iostream> using namespace std;struct Node {int data;Node *left;Node *right;int height; };// 获取结点高度 int height(Node *node) {if (node nullptr){return 0;}return node->height; }// 获取两个数中较大的一个 i…...
React/ReactNative 状态管理: redux-toolkit 如何使用
有同学反馈开发 ReactNative 应用时状态管理不是很明白,接下来几篇文章我们来对比下 React 及 ReactNative 状态管理常用的几种框架的使用和优缺点。 上一篇文章介绍了 redux 的使用,这篇文章我们来看下 redux 的升级版:redux-toolkit。 下…...
14基于双层优化的电动汽车优化调度研究
说明书 MATLAB代码:基于双层优化的电动汽车优化调度研究 关键词:双层优化 选址定容 输配协同 时空优化 参考文档:《考虑大规模电动汽车接入电网的双层优化调度策略_胡文平》中文版 《A bi-layer optimization based temporal and sp…...
古茗科技面试:为什么 ElasticSearch 更适合复杂条件搜索?
文章目录 ElasticSearch 简介倒排索引联合索引查询跳表合并策略Bitset 合并策略MySQL 最多使用一个条件涉及的索引来过滤,然后剩余的条件只能在遍历行过程中进行内存过滤。 上述这种处理复杂条件查询的方式因为只能通过一个索引进行过滤,所以需要进行大量的 I/O 操作来读取行…...
【数据结构】哈希表
目录 1、哈希表 1.1 哈希表的简介 1.2 降低哈希冲突率 1.3 解决哈希冲突 1.3.1 闭散列 1.3.2 开散列(哈希桶) 1、哈希表 1.1 哈希表的简介 假设我们目前有一组数据,我们要从这组数据中找到指定的 key 值,那么咱们目…...
物联网常用协议MQTT协议相关介绍
概述 MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,旨在在网络带宽有限的情况下,为物联网设备之间的通信提供可靠的、低延迟的消息传递服务。MQTT协议具有订阅/发布模式,支持多种传输协议&a…...
【C语言进阶】13. 假期测评②
day10 1. int类型字节数 求函数返回值,传入 -1 ,则在64位机器上函数返回( ) int count 0; int x -1; while (x) {count;x x >> 1; } printf("%d", count);A: 1 B: 2 C: 32 D: 死循环,没结果 【答案解析】C xx&(x-1)这…...
【国产FPGA】国产FPGA搭建图像处理平台
最近收到了高云寄过来的FPGA板卡,下图:来源:https://wiki.sipeed.com/hardware/zh/tang/tang-primer-20k/primer-20k.htmlFPGA主要参数:FPGA型号参数GW2A-LV18PG256C8/I7逻辑单元(LUT4) 20736寄存器(FF) 15552分布式静态随机存储器S-SRAM(bit…...
你的应用太慢了,给我司带来了巨额损失,该怎么办
记得很久之前看过谷歌官方有这么样的声明:如果一个页面的加载时间从 1 秒增加到3 秒,那么用户跳出的概率将增加 32%。 但是早在 2012 年,亚马逊就计算出了,页面加载速度一旦下降一秒钟,每年就会损失 16 亿美元的销售额…...
第十四届蓝桥杯三月真题刷题训练——第 22 天
目录 第 1 题:受伤的皇后_dfs 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码: 思路: 第 2 题:完全平方数 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约…...
机器学习:朴素贝叶斯模型算法原理(含实战案例)
机器学习:朴素贝叶斯模型算法原理 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏&…...
Linux 多线程:理解线程
目录一、理解线程的思想二、Linux中的线程与进程1.Linux中的进程2.Linux中的线程三、线程的工作方式四、线程的独有数据与共享数据1.独有数据2.共享数据一、理解线程的思想 线程就是把一个进程分成多个执行部分,一个部分就是一个线程,比如可以让一个线程…...
Web前端学习:章四 -- JavaScript初级(四)-- BOM
138:Object数据格式简介 1、object对象 JS中独有 的一种数据格式 名字可以随便取,值一般就那几种数据格式 139:BOM - JS跳转页面 BOM Browser Object Model:浏览器对象模型 使用JavaScript控制浏览器交互 控制浏览器里面的内…...
Lesson9.网络基础1
网络协议初识 所谓的协议就是人们为了通信的一种约定 操作系统要进行协议管理,必然会先描述,再组织协议本质就是软件,软件是可以"分层"协议在设计的时候,就是被层状的划分的, 为什么要划分成为层状结构 场景复杂功能解耦(便于人们进行各种维护)OSI七层模型 局域网中…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
