当前位置: 首页 > news >正文

JAVA如何操作文件?(超级详细)

目录

一、认识文件和相关知识

1.认识文件

2.⽬录

3.⽂件路径(Path) 

4.文本文件和二进制文件的区分 

二、File类操作文件 

1.构造方法 

2.方法

2.1 方法表

2.2  get相关的方法和构造方法

2.2.1 “.” 和 “..”

 2.3 is相关的方法 

2.4 删除相关的方法 

2.5 返回当前目录下的文件

2.5.1 递归实现遍历路径下所有文件 

 2.6 创建目录

2.7 renameTo()

三、流 (Stream)

1.初时“流”

2.输入输出的角度

3.字节流的操作

3.1 InputStream

3.1.1 FileInputStream

3.1.1.1 read()

3.1.1.2 read(byte[] b)

3.1.1.3 read(byte[] b,int off,int len)

3.1.1.4 Scanner获取文件内容

3.2 OutputStream

3.2.1 FileOutputStream

3.2.1.1 write(int b)

 3.2.1.2 write(byte[] b)

3.2.1.3 write(byte[] b, int off, int len)

4.字符流的操作

4.1 Reader

4.1.1 FileReader

4.1.1.1 read() 

4.1.1.2 read(char[] cbuf)

4.1.1.3 read(char[] cbuf,int off,int len)

4.2 Writer

4.2.1FileWriter

4.2.1.1 write(String str)

4.2.1.2 write(char cbuf[])

4.2.1.3 write(char cbuf[], int off,int len)

四、案例练习

1.扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否要删除该⽂件

2.复制普通文件

 3.扫描指定⽬录,并找到内容中包含指定字符的所有普通⽂件(不包含⽬录)


一、认识文件和相关知识

1.认识文件

我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进⾏数据保存时,往往不是保存成⼀个整体,⽽是独⽴成⼀个个的单位进⾏保存,这个独⽴的单位就被抽象成⽂件的概念,就类似办公桌上的⼀份份真实的⽂件⼀般。
简单来说就是,文件是保存在硬盘上的,但是硬盘非常大,硬盘就用逻辑抽象成一个文件
⽂件除了有数据内容之外,还有⼀部分信息,例如⽂件名、⽂件类型、⽂件⼤⼩等并不作为⽂件的数据⽽存在,我们把这部分信息可以视为⽂件的元信息。

2.⽬录

同时,随着⽂件越来越多,对⽂件的系统管理也被提上了⽇程 ,如何进⾏⽂件的组织呢,⼀种合乎⾃ 然的想法出现了,就是按照层级结构进⾏组织⸺也就是我们数据结构中学习过的树形结构。这样,⼀种专⻔⽤来存放管理信息的特殊⽂件诞⽣了,也就是我们平时所谓⽂件夹(folder)或者⽬录(directory)的概念。同时也可以看出,数据结构是n叉树

3.⽂件路径(Path) 

如何在⽂件系统中如何定位我们的⼀个唯⼀的⽂件就成为当前要解决的问题,但这难不倒计算机科学家,因为从树型结构的⻆度来看,树中的每个结点都可以被⼀条从根开始,⼀直到达的结点的路径所描述,⽽这种描述⽅式就被称为⽂件的绝对路径(absolute path)。
例如我要查找这个文件:
绝对路径:C:\Program Files\Java\jdk-11
除了可以从根开始进⾏路径的描述,我们可以从任意结点出发,进⾏路径的描述,⽽这种描述⽅式就被称为相对路径(relative path),相对于当前所在结点的⼀条路径。
相对路径,结合之后的代码讲解

4.文本文件和二进制文件的区分 

我们其实就可以通过记事本打开的方式查看。

  • 如果打开是我们认识的一些东西,包括我们写的.java文件,它大概率就是文本文件
  • 如果通过记事本打开的文件是一堆乱码,也就是二进制文件

所有的文件存储都是二进制,哪怕是文本文件,它底层存储的仍然是二进制,那为什么是我们可以看懂的文字?

因为文本文件会有一个查表的动作,这个“表”是把对应的二进制转换为字符,例如:ASII码表、UTF8、Unicode等

二、File类操作文件 

Java 中通过 java.io.File 类来对⼀个⽂件(包括⽬录)进⾏抽象的描述。
注意,有 File 对象,并不代表真实存在该⽂件

1.构造方法 

签名说明
File(File parent, String child)
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例
File(String pathname)
根据⽂件路径创建⼀个新的 File 实例,路径可以是绝
对路径或者相对路径
File(String parent, String child)
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实
例,⽗⽬录⽤路径表⽰

注意!这里创建的是实例,并不代表一定有这个文件存在

2.方法

2.1 方法表

修饰符及返回值类型
⽅法签名
说明
String
getParent()
返回 File 对象的⽗⽬录⽂件路径
String
getName()
返回 FIle 对象的纯⽂件名称
String
getPath()
返回 File 对象的⽂件路径
String
getAbsolutePath()
返回 File 对象的绝对路径
String
getCanonicalPath()
返回 File 对象的修饰过的绝对路径
boolean
exists()
判断 File 对象描述的⽂件是否真实
存在
boolean
isDirectory()
判断 File 对象代表的⽂件是否是⼀
个⽬录
boolean
isFile()
判断 File 对象代表的⽂件是否是⼀
个普通⽂件
boolean
createNewFile()
根据 File 对象,⾃动创建⼀个空⽂
件。成功创建后返回 true
boolean
delete()
根据 File 对象,删除该⽂件。成功
删除后返回 true
void
deleteOnExit()
根据 File 对象,标注⽂件将被删
除,删除动作会到 JVM 运⾏结束时
才会进⾏
String[]
list()
返回 File 对象代表的⽬录下的所有
⽂件名
File[]
listFiles()
返回File 对象代表的⽬录下的所有
⽂件,以 File 对象表⽰
boolean
mkdir()
创建 File 对象代表的⽬录
boolean
mkdirs()
创建 File 对象代表的⽬录,如果必
要,会创建中间⽬录
boolean
renameTo(File dest)
进⾏⽂件改名,也可以视为我们平
时的剪切、粘贴操作

2.2  get相关的方法和构造方法

    public static void main(String[] args) throws IOException {//打开我们工程目录下的文件File file = new File("E:\\Code\\lear-java\\io\\src");//或者可以使用://        File file = new File("E:/Code/lear-java/io");//返回File对象的父目录文件路径System.out.println(file.getParent());//返回File对象的纯文件名称System.out.println(file.getName());//返回文件路径System.out.println(file.getPath());//返回File对象的绝对路径System.out.println(file.getAbsolutePath());//返回File修饰过的路径System.out.println(file.getCanonicalPath());}

 

这样看后面三种没有区别,在使用相对地址的时候才可以区分出

2.2.1 “.” 和 “..”
  • .  :表示当前目录
  • .. : 表示上一级目录 或者 表示父级目录
    public static void main(String[] args) throws IOException {//打开当前目录File file = new File("./Test.txt");//返回File对象的父目录文件路径System.out.println(file.getParent());//返回File对象的纯文件名称System.out.println(file.getName());//返回文件路径System.out.println(file.getPath());//返回File对象的绝对路径System.out.println(file.getAbsolutePath());//返回File修饰过的路径System.out.println(file.getCanonicalPath());}

那么当前目录又是哪里?

程序默认在idea工程中运行的,那么当前文件就是在当前工程目录下。

例如:我的工程名为《IO》那么就在IO工程下:

结果:

而且我们的Test.txt文件根本就不存在,所以就算你获取到了路径、名字等等,也不能代表文件是真实存在的。

    public static void main(String[] args) throws IOException {//父级目录File file = new File("../Test.txt");//返回File对象的父目录文件路径System.out.println(file.getParent());//返回File对象的纯文件名称System.out.println(file.getName());//返回文件路径System.out.println(file.getPath());//返回File对象的绝对路径System.out.println(file.getAbsolutePath());//返回File修饰过的绝对路径System.out.println(file.getCanonicalPath());}

结果:

 2.3 is相关的方法 

当文件不存在:

    public static void main(String[] args) {//此时这个文件并不存在File file = new File("./Test.txt");//判断文件是真实否存在System.out.println(file.exists());//判断文件是否是一个目录System.out.println(file.isDirectory());//判断文件是否是一个普通文件System.out.println(file.isFile());}

结果
 

此时我们加上创建文件的方法

    public static void main(String[] args) throws IOException {//此时这个文件并不存在File file = new File("./Test.txt");//创建文件System.out.println(file.createNewFile());//判断文件是真实否存在System.out.println(file.exists());//判断文件是否是一个目录System.out.println(file.isDirectory());//判断文件是否是一个普通文件,二进制文件也算是普通文件System.out.println(file.isFile());}

结果:

  • 当文件存在,不会创建,返回false
  • 当文件不存在,创建文件,返回true
  • 创建失败抛出异常IOException

什么情况下会创建失败?

1. 硬盘空间不够了

在日常我们使用的电脑,一般来说不容易遇到这个问题,但是在以后的工作中可能就比较常见,因为每天都会产生大量的日志,会产生新的文件,这个时候就会创建失败抛出异常IOException。

2.没有权限

主要是读和写的权限,如果你只要读的权限去写,肯定也是不行的

3.父目录不存在

写入的目录路径错误,根本就没有这个目录

4.其他I/O错误

如文件路径被占用、硬件故障……

2.4 删除相关的方法 

    public static void main(String[] args) throws IOException {File file = new File("./Test.txt");//创建文件System.out.println(file.createNewFile());//删除文件,删除成功返回trueSystem.out.println(file.delete());}

结果:

除了马上删除,还可以让文件在线程结束的时候删除:

    public static void main(String[] args) throws IOException {File file = new File("./Test.txt");//先创建文件System.out.println(file.createNewFile());//当进程结束的时候才会删除文件file.deleteOnExit();System.out.println("是否要结束进程");//利用Scanner造成阻塞Scanner sc = new Scanner(System.in);sc.next();System.out.println("进程结束");}

使用场景之一:

我们在word创建一个文档且还未保存的时候,它会创建一个临时文件用来保存,你正在编辑的内容。如果程序异常关闭了,就可以通过这个文件恢复之前编辑的内容。

2.5 返回当前目录下的文件

    public static void main(String[] args) {File file = new File(".");String[] s = file.list();for (int i = 0; i < s.length; i++) {System.out.println(s[i]);}}

结果:

打印出来的顺序并不和我们文件中看到的顺序相同

这个方法功能比较有限,我们一般使用listFiles()方法比较多,可以直接获取到目录下每个文件的实例

    public static void main(String[] args) {File file = new File(".");//获取该文件下,所有对象的实例File[] fs = file.listFiles();for (int i = 0; i < fs.length; i++) {System.out.println(fs[i].getName());}}

我们也可以通过这个方法,打印出当前目录下文件的名字。

但是!我们src也是一个目录,目录下的文件并不能通过这样的方式简单打印出来,

就需要使用递归的方法。在此之前我们需要知道这个方法的几种情况:

  1. 当遇到的文件不是目录,返回null
  2. 路径错误,返回null
  3. 如果是一个空目录,就返回一个空数组
2.5.1 递归实现遍历路径下所有文件 

 我们现在可以来实现一下:

    private static void scan(File file) throws IOException {//如果不是目录,就退出if (!file.isDirectory()) {return;}//是目录就获取,目录中每个文件的对象File[] fs = file.listFiles();//   如果是空目录    或者   不存在的路径if (fs.length == 0 || fs == null) {return;}for (int i = 0; i < fs.length; i++) {//如果是普通文件就打印if (fs[i].isFile()) {System.out.println(fs[i].getCanonicalPath());}else {//到这里肯定就是目录了//就先打印目录名,再继续递归System.out.println(fs[i].getName());scan(fs[i]);}}}public static void main(String[] args) {File file = new File(".");try {scan(file);} catch (IOException e) {e.printStackTrace();}}

结果:

 2.6 创建目录

    public static void main(String[] args) {File file = new File("./aaa");//创建一个目录,如果创建成功返回true,否则falseboolean ok = file.mkdir();System.out.println(ok);}

 结果:

那如果在有这个目录的情况下,我们再次运行,会创建成功吗?

直接返回了false创建失败了,说明它会先检查一下是否有同名的文件夹。

那么我们是否能同时创建,多级目录呢?

​public static void main(String[] args) {File file = new File("./bb/cc/dd");//创建一个目录,如果创建成功返回true,否则falseboolean ok = file.mkdir();System.out.println(ok);}​

结果:

并不能同时创建多级目录,但是我们还有一个方法是可以创建多级目录的:

    public static void main(String[] args) {File file = new File("./bb/cc/dd");//创建一个目录,如果有必要会创建多级目录,如果创建成功返回true,否则falseboolean ok = file.mkdirs();System.out.println(ok);}

结果:

那么用mkdirs()方法就可以创建多级目录了

2.7 renameTo()

改名操作:

    public static void main(String[] args) {File file1 = new File("./Test.txt");File file2 = new File("./Test2.txt");//改名或者移动成功返回true,反之falseboolean ok = file1.renameTo(file2);System.out.println(ok);}

结果:

移动操作,需要最后名字写为相同的:

    public static void main(String[] args) {//现在我们想将,之前改名的Test2.txt,移动到之前创建的aaa文件夹中File file1 = new File("./Test2.txt");File file2 = new File("./aaa/Test2.txt");//改名或者移动成功返回true,反之falseboolean ok = file1.renameTo(file2);System.out.println(ok);}

 结果:

三、流 (Stream)

1.初时“流”

关于文件的操作,都是系统提供了API,java已经帮我们封装好了。

我们把这些封装好的类统称为,《文件流》或者《IO流》

流是一个形象的比喻,例如:

水流:

通过水龙头,接100ml水

  1. 直接一口气100ml接完
  2. 一次接50ml,分两次接完
  3. 一次接10ml,分10次接完
  4. 一次接1ml,分100次接完
  5. ……

文件流/IO流:

我要从文件读取100字节的数据

  1. 直接一口气,把100字节的数据读完
  2. 一次读50字节,分两次
  3. 一次读10字节,分10次
  4. 一次读1字节,分100次
  5. ……

java实现IO流的类有很多,分成两个大类

1. 字节流(二进制):读写数据的基本单位,就是字节,实现的主要接口:

  • InputStream(输入)
  • OutputStream(输出)

2. 字符流:读写数据的基本单位,就是字符

  • Writer(输入)
  • Reader(输出)

上述四个类,都是“抽象类”,真正干活的是下面的一堆继承它的类。

实现了这么多类怎么区分字符流和IO流呢

凡是后缀带有 InputStream 或者 OutputStream 就是字节流

凡是后缀带有 Wirte 或者 Reader

我们只需要去了解常用的类就可以了。

2.输入输出的角度

我们从CPU的角度出发:

  • 去硬盘上写数据,就是写
  • 去硬盘上读数据,就是读

3.字节流的操作

3.1 InputStream

常用的方法

修饰符及返回值类型方法签名说明
intread()读取一个字节的数据,返回-1代表已经读完了
int read(byte[] b)最多读取b.length字节的数据到b中, 返回实际读到的数量;-1代表以及读完了
intread(byte[] b,int off,int len)将从文件读取的数据放入到数组b中,off:代表开始存储数组的下标 ,len:代表最多读取的字节个数。返回读取到的字节个数,如果读到末尾返回-1
voidclose()关闭字节流
InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输⼊设备都可以对应⼀个 InputStream 类,我们现在只关⼼从⽂件中读取,所以使⽤ FileInputStream
3.1.1 FileInputStream
    public static void main(String[] args) throws FileNotFoundException {//打开字节流并,打开文件                     这个地址可以是不存在的InputStream inputStream = new FileInputStream("./Test.txt");}

这样的一段代码,它会抛这样一个异常:FileNotFoundException,表示程序尝试打开或访问指定路径的文件时失败。它是IOExciption的一种特殊情况。

如果没有这个文件,就会抛出此异常:

这个语句还隐含了“打开文件”这样的操作既然有打开就有关闭。

    public static void main(String[] args) throws IOException {InputStream inputStream = new FileInputStream("./Test.txt");//关闭字节流inputStream.close();}

如果不关闭,可能会造成程序崩溃:

打开文件,其实是在该进程中的 “文件描述符” 中,创建了一个新的表项。

文件描述符:描述了该进程都要操作哪些文件。数组的每个元素就是一个struct file对象,每个结构体就描述了对应的文件信息,数组的小标就称为“文件描述符”。

每次打开一个文件,就想当于在数组上占用了一个位置,而这个数组又是不能扩容的,如果数组满了就会打开文件失败。除非主动调用close才会关闭文件,或者这个进程直接结束了这个数组也被带走了。

但是难免会存在一些情况导致close()执行不到,例如:在执行到之前抛出了异常、遇到了return。所以我们应该把close()方法放到finally中:

    public static void main(String[] args) {InputStream inputStream = null;try {inputStream = new FileInputStream("./Test.txt");} catch (FileNotFoundException e) {e.printStackTrace();} finally {try {//关闭inputStream.close();} catch (IOException e) {e.printStackTrace();}}}

但是这样写感觉非常的繁琐,那我们其实还有一种解决方式:

    public static void main(String[] args) {//写在这里,就不用加close()了。只有实现了Closeable的语句才可以写在这里try (InputStream inputStream = new FileInputStream("./Test.txt")) {} catch (IOException e) {}

写在try()里的必须是实现了Closeable接口的,这样的写法是非常推荐的:

try()里支持放入多个对象,使用“;”分割

3.1.1.1 read()

每次读取一个字节的内容,读值只会返回0 - 255的数据,如果读取到了末尾返回-1。

 创建一个文件Test.txt在里面写上hello:

    public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./Test.txt")) {while (true) {int b = inputStream.read();if (b == -1) {//如果等于-1就代表读到了文件末尾return;}System.out.printf("0x%x = %c \n",b,b);}} catch (IOException e) {e.printStackTrace();}}

结果:

一次读取太慢了,而且每去读一次,就会执行一次IO操作,IO操作的开销是比较大的,我们可以使用数组参数的read()。此方法虽然还是一个个在读到数组中的,但提升比较大的原因是节省了每次的IO操作开销

3.1.1.2 read(byte[] b)

将读取到的参数,传入到数组b中。如果没有读取到末尾,就返回每次读取到的字节数,到了末尾返回-1

    public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./Test.txt")) {//防止数据一次读不完while (true) {byte[] buffer = new byte[1024];//n代表读取到了多少个字节,读取到末尾仍然返回-1int n = inputStream.read(buffer);if (n == -1) {//如果等于-1就代表读到了文件末尾return;}for (int i = 0; i < n; i++) {System.out.printf("0x%x -> %c\n",buffer[i],buffer[i]);}}} catch (IOException e) {e.printStackTrace();}}

 结果:

3.1.1.3 read(byte[] b,int off,int len)
将从文件读取的数据放入到数组b中,off:代表开始存储数组的下标 ,len:代表最多读取的字节个数。返回读取到的字节个数,如果读到末尾返回-1
    public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./Test.txt")) {byte[] buffer = new byte[1024];//n代表读取到了多少个字节,读取到末尾仍然返回-1//off:代表偏移量,此处写的1,就是从数组为1的位置开始写//len:表示最多读取的字节个数int n = inputStream.read(buffer,1,3);if (n == -1) {//如果等于-1就代表读到了文件末尾return;}for (int i = 1; i < n+1; i++) {System.out.printf("0x%x -> %c\n",buffer[i],buffer[i]);}} catch (IOException e) {e.printStackTrace();}}

 结果:

3.1.1.4 Scanner获取文件内容
Scanner sc = new Scanner(System.in);

在这之前,我们可能一直不知道System.in是什么参数,我们点进去看一下:

public static final InputStream in = null;

我们发现他就是一个InputStream,那我们传入的参数就可以是InputStream对象。

 我们现在文件中是这样的内容:

    public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./Test.txt")) {Scanner sc = new Scanner(inputStream);//判断下一个是否为Int类型while (sc.hasNextInt()) {System.out.println(sc.nextInt());}} catch (IOException e) {e.printStackTrace();}}

结果:

如果里面的内容被其他类型则会中断:

    public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./Test.txt")) {Scanner sc = new Scanner(inputStream);//判断下一个是否为Int类型while (sc.hasNextInt()) {System.out.println(sc.nextInt());}} catch (IOException e) {e.printStackTrace();}}

结果:

这个时候用字符串类型可能就比较好

如果是字符串

    public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("./Test.txt")) {Scanner sc = new Scanner(inputStream);//判断下一个是否为String类型while (sc.hasNext()) {System.out.println(sc.next());}} catch (IOException e) {e.printStackTrace();}}

结果:

3.2 OutputStream

修饰符及返回值类型
⽅法签名
说明
void
write(int b)
写⼊要给字节的数据
void
write(byte[] b)
将 b 这个字符数组中的数据全部写
⼊ os 中
int
write(byte[] b, int off, int len)
将 b 这个字符数组中从 off 开始的
数据写⼊ os 中,⼀共写 len 个
OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件中,所以使⽤ FileOutputStream
3.2.1 FileOutputStream

依然包含打开文件这样的隐藏操作,所以也需要关闭字节流。打开失败依然会抛出FileNotFoundException。如果文件不存在会自动创建文件,但是如果目录都不存在会抛出异常

3.2.1.1 write(int b)

每次输入一个字节b,如果写入失败会抛出IOException

现在将Test.txt文件里的内容清空

    public static void main(String[] args) {//写文件,依然包含打开文件这样的隐藏操作,打开失败依然会抛出FileNotFoundExceptiontry (OutputStream outputStream = new FileOutputStream("./Test.txt")) {//每次写入一个字节outputStream.write(0x68);//houtputStream.write(0x65);//eoutputStream.write(0x6c);//loutputStream.write(0x6c);//loutputStream.write(0x6f);//o} catch (IOException e) {e.printStackTrace();}}

结果: 

 

但是如果我们再次运行:

在我们创建这个对象的时候它回清空文件中的数据,再开始写

那如果我们不想让它清空数据,就在实例化对象的时候填入一个true

OutputStream outputStream = new FileOutputStream("./Test.txt",true)

这个时候就不会清空,文件中的数据了

 3.2.1.2 write(byte[] b)

 将数组b的内容写到文件中,如果写入失败会抛出IOException

 我们用此方法写“你好”:

    public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("./Test.txt",true)) {//此数组中存放的是,“你好”的二进制数据//必须进行强制类型转换,不然会报错byte[] buffer = {(byte) 0xe4,(byte) 0xbd,(byte) 0xa0,(byte) 0xe5,(byte) 0xa5,(byte) 0xbd};outputStream.write(buffer);} catch (IOException e) {e.printStackTrace();}}

 结果:

3.2.1.3 write(byte[] b, int off, int len)

b数组做为数据源,表示要写入的内容,

off:代表从b数组中哪一个元素开始写入

len:表示最多写入多少个字节

    public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("./Test.txt",true)) {byte[] buffer = {(byte) 0xe4,(byte) 0xbd,(byte) 0xa0,(byte) 0xe5,(byte) 0xa5,(byte) 0xbd};//将buffer数组的数据,从0下标开始,输入6个字节的数据outputStream.write(buffer,0,6);} catch (IOException e) {e.printStackTrace();}}

结果:

这个时候如果我们乱输入一个数据范围:

    public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("./Test.txt",true)) {byte[] buffer = {(byte) 0xe4,(byte) 0xbd,(byte) 0xa0,(byte) 0xe5,(byte) 0xa5,(byte) 0xbd};outputStream.write(buffer,1,3);} catch (IOException e) {e.printStackTrace();}}

结果:这个适合它就不认识你写的什么东西了

如果超出了你数据源的范围:

    public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("./Test.txt",true)) {byte[] buffer = {(byte) 0xe4,(byte) 0xbd,(byte) 0xa0,(byte) 0xe5,(byte) 0xa5,(byte) 0xbd};//从 2 下标开始,一共就只有4个数据了,超过了这个就会抛出异常outputStream.write(buffer,2,6);} catch (IOException e) {e.printStackTrace();}}

如果是文本文件的操作,更适合字符流的方式

4.字符流的操作

4.1 Reader

修饰符及返回值类型方法签名说明
intread()读取一个字符的数据,返回读取到的数据,但是是int类型,为了兼容读取到末尾返回-1,正常读取到数据的返回范围是0-65535。
intread(char[] cbuf)
 
将文件中读取到的字符,写到cbuf数组中。返回的是读取到字符的个数,如果读取到文件末尾,则返回-1
intread(char[] cbuf, int off, int len)将在文件读取到的内容返回到cbuf数组中,off:从数组中的哪一个下标开始写,len表示最多读取的字符个数。返回读取到的个数,如果是读取到文件末尾就返回-1
4.1.1 FileReader

这个类和上面讲述的InputStream差不多,我就不过多讲述了

4.1.1.1 read() 

读取一个字符的数据,返回读取到的数据,但是是int类型,为了兼容读取到末尾返回-1,正常读取到数据的返回范围是0-65535。如果文件不存在会自动创建文件,但是如果目录都不存在会抛出异常

    public static void main(String[] args) {try (Reader reader = new FileReader("./Test.txt")) {while (true) {//读取一个字符的内容,但是返回的是int类型,为了兼容-1int c = reader.read();if (c == -1) {//读取到了文件末尾return;}char ch = (char) c;System.out.println(ch);}} catch (IOException e) {e.printStackTrace();}}

结果:

可能熟悉二进制范围的朋友就有疑问了,utf8汉字存储用了3个字节,java中的char类型是2给字节,怎么能装得下的。其实java中char类型进行了转码,转为了Unicode编码。

4.1.1.2 read(char[] cbuf)

将文件中读取到的字符,写到cbuf数组中。返回的是读取到字符的个数,如果读取到文件末尾,则返回-1

    public static void main(String[] args) {try (Reader reader = new FileReader("./Test.txt")) {while (true) {char[] buffer = new char[1024];//返回读取到字符的个数,如果读到文件末尾返回-1int n = reader.read(buffer);if (n == -1) {return;}for (int i = 0; i < n; i++) {System.out.println(buffer[i]);}}} catch (IOException e) {e.printStackTrace();}}
4.1.1.3 read(char[] cbuf,int off,int len)

将在文件读取到的内容返回到cbuf数组中,off:从数组中的哪一个下标开始写,len表示最多读取的字符个数。返回读取到的个数,如果是读取到文件末尾就返回-1

    public static void main(String[] args) {try (Reader reader = new FileReader("./Test.txt")) {char[] buffer = new char[1024];//返回读取到字符的个数,如果读到文件末尾返回-1int n = reader.read(buffer,1,3);if (n == -1) {return;}for (int i = 1; i < n+1; i++) {System.out.println(buffer[i]);}} catch (IOException e) {e.printStackTrace();}}

结果:

4.2 Writer

修饰符及返回值类型方法签名说明
voidwrite(String str)将str中的数据写入文件中
voidwrite(char cbuf[])将cbuf数组中的值,写入到文件中
voidwrite(char cbuf[], int off,int len)将cbuf数组做为数据源,off(偏移量)做为从哪个数组下标开始写,len表示最多写多少个字符。
4.2.1FileWriter

这个类如果不在形参中写true,每次实例化对象的时候也会把文件清空

4.2.1.1 write(String str)

这个方法可以用Stirng传入就非常方便了

    public static void main(String[] args) {try (Writer writer = new FileWriter("./Test.txt")) {writer.write("你好世界");} catch (IOException e) {e.printStackTrace();}}

结果:

把之前的两个你好给清空了

当我们加上true:

    public static void main(String[] args) {try (Writer writer = new FileWriter("./Test.txt",true)) {writer.write("你好世界");} catch (IOException e) {e.printStackTrace();}}

4.2.1.2 write(char cbuf[])

将cbuf数组中的值,写入到文件中

    public static void main(String[] args) {try (Writer writer = new FileWriter("./Test.txt",true)) {char[] buffer = {'哈','哈','哈'};writer.write(buffer);} catch (IOException e) {e.printStackTrace();}}

 结果:

4.2.1.3 write(char cbuf[], int off,int len)

将cbuf数组做为数据源,off(偏移量)做为从哪个数组下标开始写,len表示最多写多少个字符。

    public static void main(String[] args) {try (Writer writer = new FileWriter("./Test.txt",true)) {char[] buffer = {'啊','啊','啊','啊','啊','啊'};writer.write(buffer,1,4);} catch (IOException e) {e.printStackTrace();}}

结果:

四、案例练习

1.扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否要删除该⽂件

public class demo4 {//扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否//要删除该⽂件public static void main(String[] args) {//1.指定目录System.out.println("请输入你要查找的目录");Scanner sc = new Scanner(System.in);String rootPath = sc.next();File file = new File(rootPath);//2.判断地址是否为一个有效地址if (!file.isDirectory()) {//不是一个目录System.out.println("输入路径错位");return;}//3.获取要查找的关键字System.out.println("请输入你要查找的关键字");String key = sc.next();;//4.开始查找scan(file,key);}private static void scan(File file, String key) {//1.不是目录就不能继续递归了if (!file.isDirectory()) {return;}//2.获取当前目录下所有文件的对象File[] fs = file.listFiles();//3.防止发生IO错误 和 如果是一个目录if (fs == null || fs.length == 0) {return;}//4. 开始遍历for (File f : fs) {//5.如果是普通文件,判断是否有key值if (f.isFile()) {//7. 判断是否有key值toDelete(f,key);}else {//6.如果不是普通文件继续递归scan(f,key);}}}private static void toDelete(File f, String key) {Scanner sc = new Scanner(System.in);//获取文件名称是否包含key值if (f.getName().contains(key)) {//提示用户是否删除System.out.println("是否删除" + f.getName() + "文件");System.out.println("是Y/y 否N/n");String ch = sc.next();if (ch.equals("Y") || ch.equals("y")) {f.delete();}}}
}

要删除的目标:

输入的过程:

那么现在我们来看一下是否删除成功了:

2.复制普通文件

public class demo5 {//复制普通文件//读取二进制,并写入到目标文件public static void main(String[] args) {//1.输入要复制的文件Scanner sc = new Scanner(System.in);System.out.println("请输入你要复制的文件路径");String sourcePath = sc.next();File file = new File(sourcePath);//2.如果不是普通文件if (!file.isFile()) {System.out.println("你输入的文件路径有误");return;}//3.输入要复制的文件路径System.out.println("请输入要粘贴的文件路径");String targetPath = sc.next();File destFile = new File(targetPath);//4.目标文件的路径必须存在if (!destFile.getParentFile().isDirectory()) {System.out.println("目标文件的路径有误");return;}//5.开始复制//如果文件不存在,FileInputStream会自动创建文件try (InputStream inputStream = new FileInputStream(sourcePath);OutputStream outputStream = new FileOutputStream(targetPath)) {while (true) {byte[] buffer = new byte[1024];int n = inputStream.read(buffer);if (n == -1) {break;}//数据源不是每一次都能装满1024个字节outputStream.write(buffer,0,n);}} catch (IOException e) {e.printStackTrace();}}
}

 结果:

 3.扫描指定⽬录,并找到内容中包含指定字符的所有普通⽂件(不包含⽬录)

public class demo6 {//扫描指定⽬录,并找到内容中包含指定字符的所有普通⽂件(不包含⽬录)public static void main(String[] args) {Scanner sc = new Scanner(System.in);//1.输入要查找的目录System.out.println("请输入你要查找的目录");String path = sc.next();File file = new File(path);//2.如果不是目录if (!file.isDirectory()) {System.out.println("你输入的路径有误");return;}//3.输入查找词System.out.println("请输入你要查找的内容");String key = sc.next();//4.开始查找scan(file,key);}//5.开始递归遍历private static void scan(File file, String key) {//如果不是目录就不能递归了if (!file.isDirectory()) {return;}File[] fs = file.listFiles();if (fs.length == 0 || fs == null) {return;}for (File f: fs) {//如果是普通文件进行处理判断if (f.isFile()) {search(f,key);} else {//不是普通文件继续遍历scan(f,key);}}}//6.进行内容查询判断private static void search(File f, String key) {//用这个容器来接收所有数据StringBuilder stringBuilder = new StringBuilder();try (Reader reader = new FileReader(f)) {char[] buffer = new char[1024];while (true) {int n = reader.read(buffer);if (n == -1) {break;}//将buffer0下标的数据,读取n个.并以String类型返回String s = new String(buffer,0,n);//放入容器,将字符串拼接起来stringBuilder.append(s);}} catch (IOException e) {e.printStackTrace();}//判断容器中是否有key值if (stringBuilder.indexOf(key) == -1) {//文件中没有要查询的值return;}//到这里肯定就是有key值了System.out.println("找到了匹配的文件 " +  f.getAbsolutePath());}
}

我新建了个文件夹,里面存放了一些文本文件,内容如下:

结果:

相关文章:

JAVA如何操作文件?(超级详细)

目录 一、认识文件和相关知识 1.认识文件 2.⽬录 3.⽂件路径&#xff08;Path&#xff09; 4.文本文件和二进制文件的区分 二、File类操作文件 1.构造方法 2.方法 2.1 方法表 2.2 get相关的方法和构造方法 2.2.1 “.” 和 “..” 2.3 is相关的方法 2.4 删除相关…...

Debian服务器挂载外部存储设备的完整指南

在 Debian 系统中挂载外部存储设备(如 U 盘、移动硬盘、SSD)是服务器运维和桌面使用中非常常见的操作。本文将为你详细拆解从识别设备、格式化到手动/自动挂载的全过程&#xff0c;适合新手到进阶用户参考。 一、准备阶段&#xff1a;插入存储设备并识别 1. 插入外部设备后查看…...

搭建一个网站需要选择什么配置的服务器?

一般要考虑网站规模、技术需求等因素来进行选择。 小型网站&#xff1a;个人博客、小型企业官网等日均量在 1000 以内的网站&#xff0c;一般推荐2 核 CPU、4GB 内存、50GB 硬盘&#xff0c;带宽 1 - 5M。如果是纯文字内容且图片较少的小型网站&#xff0c;初始阶段 1 核 CPU、…...

基于STM32与NB-IoT的智慧路灯远程监控系统

标题:基于STM32与NB-IoT的智慧路灯远程监控系统 内容:1.摘要 随着城市化进程的加快&#xff0c;路灯作为城市基础设施的重要组成部分&#xff0c;其管理和维护的智能化需求日益增长。本文的目的是设计并实现一种基于STM32与NB - IoT的智慧路灯远程监控系统。采用STM32微控制器…...

【高阶数据结构】第三弹---图的存储与遍历详解:邻接表构建与邻接矩阵的BFS/DFS实现

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【高阶数据结构】 目录 1、图的存储结构 1.1、邻接表 1.1.1、边的结构 1.1.2、图的基本结构 1.1.3、图的创建 1.1.4、获取顶点下…...

Tmi-clnet:从影像学、临床和放射学数据融合判断慢性肝病预后的三模态相互作用网络——医学图像论文学习,论文源码下载

论文地址&#xff1a;https://arxiv.org/pdf/2502.00695v1 源码地址&#xff1a;https://github.com/Mysterwll/liver 一、主要内容 本文提出了名为TMI-CLNet的三模态交互网络&#xff0c;用于慢性肝病的预后评估。具体来说&#xff0c;开发了一个模态内聚合模块和一个三模态…...

SpringBoot整合POI实现Excel文件的导出与导入

使用 Apache POI 操作 Excel文件,系列文章: 《SpringBoot整合POI实现Excel文件的导出与导入》 《SpringMVC实现文件的上传与下载》 《C#使用NPOI导出Excel文件》 《NPOI使用手册》 1、Apache POI 的介绍 Apache POI 是一个基于 Java 的开源库,专为读写 Microsoft Office 格…...

编程行业语言学习与竞争剖析:探寻冷门中的机遇

编程行业语言学习与竞争剖析&#xff1a;探寻冷门中的机遇 在编程领域不断拓展与演变的进程里&#xff0c;“编程行业什么开发语言竞争小易学习” 这一问题&#xff0c;始终萦绕在众多编程爱好者与初涉此道者的心头。今日&#xff0c;我&#xff08;卓伊凡&#xff0c;优雅草的…...

数据库学习通期末复习二

&#x1f31f; 各位看官好&#xff0c;我是maomi_9526&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; &#x1f680; 今天来学习C语言的相关知识。 &#x1f44d; 如果觉得这篇文章有帮助&#xff0c;欢迎您一键三连&#xff0c;分享给更…...

道可云人工智能每日资讯|首届世界人工智能电影节在法国尼斯举行

道可云元宇宙每日简报&#xff08;2025年4月15日&#xff09;讯&#xff0c;今日元宇宙新鲜事有&#xff1a; 杭州《西湖区打造元宇宙产业高地的扶持意见》发布 杭州西湖区人民政府印发《西湖区打造元宇宙产业高地的扶持意见》。该意见已于4月4日正式施行&#xff0c;有效期至…...

Python 冷门魔术方法

__init_subclass__ https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__ Python 3.6 新增。 父类派生子类后会调用该方法&#xff0c;方法中 cls 指向派生出的子类。 若__init_subclass__被定义为普通方法&#xff0c;将会被隐式转换为类方法&…...

【已更新完毕】2025泰迪杯数据挖掘竞赛C题数学建模思路代码文章教学:竞赛智能客服机器人构建

基于大模型的竞赛智能客服机器人构建 摘要 随着国内学科和技能竞赛的增多&#xff0c;参赛者对竞赛相关信息的需求不断上升&#xff0c;但传统人工客服存在效率低、成本高、服务不稳定和用户体验差的问题。因此&#xff0c;设计一款智能客服机器人&#xff0c;利用人工智能技术…...

L1-028 判断素数

L1-028 判断素数 L1-028 判断素数 - 团体程序设计天梯赛-练习集 (pintia.cn) 题解 素数概念&#xff1a;一个数如果只能被1和这个数本身整除&#xff0c;那么这个数就是素数。 并且1不是素数&#xff0c;2是素数。 因为题目中数最长位数是9位数&#xff0c;所以我用了long…...

向量数据库

目录标题 阶段二&#xff1a;核心技术深入学习阶段三&#xff1a;工具与实践 1. 基础概念问题&#xff1a;什么是向量数据库&#xff1f;它与传统关系型数据库的区别是什么&#xff1f;问题&#xff1a;向量数据库的核心数据结构是什么&#xff1f;为什么向量适合用于高维数据&…...

《Vue3学习手记2》

今天主要学习Vue3中的数据监视&#xff1a; ps: 代码中的注释写的很详细&#xff0c;这样更有利于理解 watch 作用: 监视数据的变化(和Vue2中watch作用一致) 特点: Vue3中的watch只能监视以下四种数据: ref创建定义的数据&#xff08;基本类型、对象类型&#xff09;reactiv…...

zigbee和wifi都是无线通信,最大区别是低功耗,远距离!

zigbee和wifi都属于短距离无线通信技术&#xff0c;都使用了2.4GHz的无线频段&#xff0c;并采用了直接序列扩频传输技术&#xff08;DSSS&#xff09;。并广泛应用于人们的生产生活之中。但是&#xff0c;它们之间却存在很大区别。 1、传输速率不同 ①、zigbee传输速率 zigb…...

JavaWeb开发 Servlet底层 Servlet 过滤器 过滤器和拦截器 手写一个限制访问路径的拦截器

目录 万能图 过滤器自我理解 案例 实现Filter 接口 配置文件 web.xml 将过滤器映射到 servlet 用处 拦截器 手写案例 重写 preHandle() 方法 拦截处理 重写 postHandle() 方法 后处理 重写 afterHandle() 方法 完成处理 代码 如何配置拦截器 万能图 还是看一下这张…...

Zookeeper三台服务器三节点集群部署(docker-compose方式)

1. 准备工作 - 服务器:3 台服务器,IP 地址分别为 `10.10.10.11`、`10.10.10.12`、`10.10.10.13`。 - 安装 Docker:确保每台服务器已安装 Docker 和 Docker Compose。 - 网络通信:确保三台服务器之间可以通过 IP 地址互相访问,并开放以下端口: - `2181`:Zookeeper 客户…...

从北京到大同,走过600里,跨越1000年。

人们都说&#xff0c;在中国&#xff0c;地下文物看陕西&#xff0c;地上文物看山西&#xff0c;因此在一个月之前就想来山西走一走&#xff0c;看一看&#xff0c;感受一下我泱泱大国的中华千年的历史积淀。 1、出发前的小花絮 于是&#xff0c;就在清明车票开卖的一瞬间&…...

鸿蒙NEXT开发全局上下文管理类(ArkTs)

type CacheValue string | number | boolean | object;/*** 全局上下文管理类&#xff0c;用于存储和管理全局数据。* author: 鸿蒙布道师* since: 2025/04/15*/ export class GlobalContext {private static instance: GlobalContext;private _objects new Map<string, C…...

【论文阅读】Orion: Online Backdoor Sample Detection via Evolution Deviance

摘要 现有的后门输入检测策略依赖于一个假设&#xff0c;即正常样本和被投毒样本在模型的特征表示中是可分离的。然而&#xff0c;这一假设可能会被先进的特征隐藏型后门攻击打破。在本文中&#xff0c;我们提出了一种新颖的检测框架&#xff0c;称为Orion&#xff08;通过进化…...

Redis之缓存雪崩

Redis之缓存雪崩 文章目录 Redis之缓存雪崩一、什么是缓存雪崩1. 定义2.核心原因① ​缓存集中过期② ​缓存服务故障​③ 资源竞争或流量激增 3. 影响 二、缓存雪崩常见解决方案1. ​分散缓存过期时间2. 多级缓存架构3. ​缓存高可用设计4. ​熔断与降级机制5. ​缓存预热6. ​…...

【HarmonyOS 5】AttributeModifier和AttributeUpdater详解

【HarmonyOS 5】AttributeModifier和AttributeUpdater区别详解 一、AttributeModifier和AttributeUpdater的定义和作用 1. AttributeModifier是ArkUI组件的动态属性&#xff0c;提供属性设置功能。开发者可使用attributeModifier方法&#xff0c;通过自定义实现AttributeModi…...

C# + Python混合开发实战:优势互补构建高效应用

文章目录 前言&#x1f94f;一、典型应用场景1. 桌面应用智能化2. 服务端性能优化3. 自动化运维工具 二、四大技术实现方案方案1&#xff1a;进程调用&#xff08;推荐指数&#xff1a;★★★★☆&#xff09;方案2&#xff1a;嵌入Python解释器&#xff08;推荐指数&#xff1…...

鸿蒙开发中,@Extend、@Styles 和 @Builder 的区别

在鸿蒙&#xff08;HarmonyOS&#xff09;开发中&#xff0c;Extend、Styles 和 Builder 是三种常用的装饰器&#xff0c;用于提升代码复用性和可维护性。以下是它们的详细介绍和示例&#xff1a; 1. Extend&#xff1a;扩展组件样式 说明&#xff1a; 功能&#xff1a;用于…...

poll为什么使用poll_list链表结构而不是数组 - 深入内核源码分析

一&#xff1a;引言 在Linux内核中,poll机制是一个非常重要的I/O多路复用机制。它允许进程监视多个文件描述符,等待其中任何一个进入就绪状态。poll的内部实现使用了poll_list链表结构而不是数组,这个设计选择背后有其深层的技术考量。本文将从内核源码层面深入分析这个设计决…...

从健康干预到成本优化:健康管理系统如何驱动企业降本增效?

在全球经济竞争日益激烈的背景下&#xff0c;企业正面临劳动力成本上升、员工健康问题频发、医疗支出居高不下等多重挑战&#xff0c;在当今商业环境中&#xff0c;企业的降本增效至关重要&#xff0c;而员工的健康状况是影响企业成本和效率的关键因素之一。健康管理系统作为一…...

12【模块学习】DS18B20(二):高级使用

DS18B20 1、改变采样分辨率2、总线上有多个设备的使用2.1、获取总线上单个设备的ROM码2.2、通过匹配ROM指令使用总线上多个设备 3、项目&#xff1a;4路温度检测LCD显示 1、改变采样分辨率 需要改变采样的分辨率&#xff0c;则需要向暂存器的配置寄存器中写入配置参数。在向寄…...

NLP高频面试题(四十三)——什么是人类偏好对齐中的「对齐税」(Alignment Tax)?如何缓解?

一、什么是「对齐税」(Alignment Tax)? 所谓「对齐税」(Alignment Tax),指的是在使人工智能系统符合人类偏好的过程中,所不可避免付出的性能损失或代价。换句话说,当我们迫使AI遵循人类价值观和规范时,AI系统往往无法达到其最大理论性能。这种性能上的妥协和折衷,就…...

线代第二章矩阵第一课:矩阵的概念

一、矩阵的概念 矩阵 i还是表示的是行&#xff0c;j表示的是列&#xff1b;行数未必等于列数 同型矩阵&#xff1a; A,B行数相等&#xff0c;列数相等 矩阵相等&#xff1a; 同型矩阵&#xff0c;且对应元素相等 零矩阵&#xff1a; 所有元素均为0 二、特殊矩阵 方阵 行数…...

如何获取Google Chrome的官方最新下载链接【获取教程】

一、为什么选择官方下载链接 安装谷歌浏览器的最安全方式始终是通过其官方网站。非官方渠道可能存在版本落后、功能缺失&#xff0c;甚至潜藏恶意插件等风险。因此&#xff0c;获取Google Chrome的官方最新下载链接&#xff0c;是保障浏览器安全与性能的重要前提。 此外&…...

软件测试——BUG概念

一、软件测试生命周期 软件测试贯穿于软件的整个生命周期 软件测试的生命周期指测试流程&#xff0c;每个阶段有不同的目标和交付产物 需求分析 从用户角度考虑软件需求是否合理 从技术角度考虑技术上是否可行&#xff0c;是否有优化空间 从测试角度考虑是否存在业务逻辑错误…...

Docker安装 (centos)

1.安装依赖包&#xff1a; sudo yum install -y yum-utils device-mapper-persistent-data lvm2 2.删除已有的 Docker 仓库文件&#xff08;如果有&#xff09;&#xff1a; sudo rm -f /etc/yum.repos.d/docker-ce.repo 3.添加阿里云的 Docker 仓库&#xff1a; sudo yum…...

MySQL数据库 - 存储引擎

存储引擎 此笔记参考黑马教程&#xff0c;仅学习使用&#xff0c;如有侵权&#xff0c;联系必删 文章目录 存储引擎1. MySQL 体系结构2. 存储引擎简介2.1 语法代码演示 3. 存储引擎特点InnoDB介绍特点文件逻辑存储结构 MyISAM介绍特点文件 Memory介绍特点文件 总结 4. 存储引擎…...

【网络篇】UDP协议的封装分用全过程

大家好呀 我是浪前 今天讲解的是网络篇的第二章&#xff1a;UDP协议的封装分用 我们的协议最开始是OSI七层网络协议 这个OSI 七层网络协议 是计算机的大佬写的&#xff0c;但是这个协议一共有七层&#xff0c;太多了太麻烦了&#xff0c;于是我们就把这个七层网络协议就简化为…...

数据结构——布隆过滤器

目录 一、什么是布隆过滤器&#xff1f; 二、布隆过滤器的原理 三、布隆过滤器的特点 一、什么是布隆过滤器&#xff1f; 布隆过滤器是一种空间效率高、适合快速检索的数据结构&#xff0c;用于判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来…...

pytorch实现逻辑回归

pytorch实现逻辑回归 数据准备&#xff0c;参数初始化前向计算计算损失计算梯度更新参数 在官网上找到线性函数的公式表达式 import torch from sklearn.datasets import load_iris # from sklearn.model_selection import train_test_split #train_test_split是sklearn中的…...

03-Spring Cloud Gateway 深度解析:从核心原理到生产级网关实践

Spring Cloud Gateway 深度解析&#xff1a;从核心原理到生产级网关实践 一、网关技术演进与 Spring Cloud Gateway 定位 1. 微服务网关的核心价值 作为微服务架构的流量入口&#xff0c;网关承担着 路由转发、流量治理、安全防护 三大核心职能&#xff1a; 统一接入&#…...

Spark-sql编程

创建子模块并添加依赖‌ 在IDEA中创建一个名为Spark-SQL的子模块。 在该子模块的pom.xml文件中添加Spark-SQL的依赖&#xff0c;具体依赖为org.apache.spark:spark-sql_2.12:3.0.0。 编写Spark-SQL测试代码‌ 定义一个User case class&#xff0c;用于表示用户信息&#xf…...

K8s 生产落地

深夜收到报警短信&#xff0c;集群突然宕机——这可能是每个运维人最不愿面对的噩梦。生产级Kubernetes集群的部署&#xff0c;远不是几条命令就能搞定的事情。本文将结合真实踩坑经验&#xff0c;从零拆解一个高可用、高安全、可自愈的Kubernetes生产环境该如何落地。 一、架…...

SnailJob:分布式环境设计的任务调度与重试平台!

背景 近日挖掘到一款名为“SnailJob”的分布式重试开源项目,它旨在解决微服务架构中常见的重试问题。在微服务大行其道的今天&#xff0c;我们经常需要对某个数据请求进行多次尝试。然而&#xff0c;当遇到网络不稳定、外部服务更新或下游服务负载过高等情况时&#xff0c;请求…...

通过WebRTC源码入门OpenGL ES

文章目录 基本概念Vertex和Fragment着色器程序 准备工作getUniformLocation/getAttribLocationglVertexAttribPointer 开始绘制Demo实现 OpenGL SE是一套适用于嵌入式设备的图形API&#xff0c;本文主要介绍如何通过OpenGL SE在Android设备上进行图形绘制&#xff0c;同时我会通…...

面试题:请描述一下你在项目中是如何进行性能优化的?针对哪些方面进行了优化,采取了哪些具体的措施?

目录 1.算法和数据结构优化 2.内存管理优化 3.并发编程优化 4.数据库优化 5.网络优化 6.持续优化与监控 7.总结 现在是企业招聘和求职者的金三银四&#xff0c;每每问到这个主观性问题的时候&#xff0c;都不知道怎么回答&#xff0c;下面就我知道的一些总结一下&#x…...

从零实现富文本编辑器#2-基于MVC模式的编辑器架构设计

在先前的规划中我们是需要实现MVC架构的编辑器&#xff0c;将应用程序分为控制器、模型、视图三个核心组件&#xff0c;通过控制器执行命令时会修改当前的数据模型&#xff0c;进而表现到视图的渲染上。简单来说就是构建一个描述文档结构与内容的数据模型&#xff0c;并且使用自…...

SAP S4HANA embedded analytics

SAP S4HANA embedded analytics...

linux多线(进)程编程——(7)消息队列

前言 现在修真界大家的沟通手段已经越来越丰富了&#xff0c;有了匿名管道&#xff0c;命名管道&#xff0c;共享内存等多种方式。但是随着深入使用人们逐渐发现了这些传音术的局限性。 匿名管道&#xff1a;只能在有血缘关系的修真者&#xff08;进程&#xff09;间使用&…...

STM32 HAL库 实现485通信

一、引言 在工业自动化、智能家居等众多领域中&#xff0c;RS - 485 通信因其长距离、高抗干扰能力等优点被广泛应用。STM32F407 是一款性能强大的微控制器&#xff0c;其丰富的外设资源为实现 RS - 485 通信提供了良好的硬件基础。本文将详细介绍基于 STM32F407 HAL 库实现 R…...

用 Vue 3 + OpenAI API 实现一个智能对话助手(支持上下文、多角色)

文章目录 一、项目背景与功能介绍二、技术选型与准备工作环境准备 三、智能对话助手的实现第一节&#xff1a;封装 OpenAI 接口请求第二节&#xff1a;构建消息上下文结构第三节&#xff1a;构建对话 UI 组件第四节&#xff1a;滚动自动到底部&#xff08;可选优化&#xff09;…...

ollama修改配置使用多GPU,使用EvalScope进行模型压力测试,查看使用负载均衡前后的性能区别

文章目录 省流结论机器配置不同量化模型占用显存1. 创建虚拟环境2. 创建测试jsonl文件3. 新建测试脚本3. 默认加载方式&#xff0c;单卡运行模型3.1 7b模型输出213 tok/s3.1 32b模型输出81 tok/s3.1 70b模型输出43tok/s 4. 使用负载均衡&#xff0c;多卡运行4.1 7b模型输出217t…...

vue3 setup vite 配置跨域了proxy,部署正式环境的替换

在开发环境中使用 Vite 的 proxy 配置来解决跨域问题是一种常见的做法。然而&#xff0c;在部署到正式环境时&#xff0c;通常需要对接口地址进行调整&#xff0c;具体是否需要更改接口名称取决于你的部署环境和后端服务的配置。以下是几种常见的情况和建议&#xff1a; 1. 正…...