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

有关Java中的IO(1) --字节流和File类

学习目标

● 掌握常用的File类常用的方法
● 掌握字节字符流的基本使用方法

1.File

1.1为什么要了解File

● 因为数据很重要所以我们要把数据永久化/持久化存储。
● 之前开发都把数据存入了内存
● 存储内存优势: 性能快
弊端: 程序结束,数据消失了。不能保证数据的持久化
● 数据只有存在计算机磁盘/缓存中 将数据持久化。
● 我们有必要学习对目录以及文件的相关操作。

1.2 File的概念

● File类位于java.io包下,表示文件或者目录,也就是说如果希望在程序中操作文件或者目录都可以通过File类来完成;
● 一个File对象代表硬盘或网络中可能存在/或者不存在的一个文件或者目录
● File类能做到新建、删除、重命名文件或者目录;

1.3 层级

public class File extends Object  implements Serializable, Comparable<File>{}
//代表磁盘/网络里面任意一个存在/不存在的文件/文件夹的抽象标识。

1.4 常用构造

有关文件路径

● window的路径分隔符使用“\”,而Java中的“\”表示转义字符,所以在Windows中表示路径,需要用两个反斜杠。
或者直接使用“/”也可以,Java程序支持将“/”当成平台无关的路径分隔符。或者直接使用File.separator常量值表示;
● 绝对路径:从盘符开始的路径,这是一个完整的路径;例如 “E:\java\io\resources\a.txt” 就是个绝对路径;
● 相对路径:相对于项目目录的路径,一种简洁的写法,开发中经常使用。

1. File(String pathname);//根据指定文件路径/目录路径(路径可以存在 也可以不存在)创建File类对象2. File(String parent, String child);//根据指定的父级目录路径以及指定的子级文件/目录路径创建File类对象//1. parent 父级目录路径//2. child 子级文件/目录路径
3. File(File parent, String child);
方法描述
public File(String pathname)根据给定的 路径名字符串 创建新的 File实例。
public File(String parent, String child)根据 父路径名字符串和子路径名字符串创建新的 File实例。
public File(File parent, String child)从父路径对应的File对象和子路径名字符串 创建新的 File实例。
private static void demo2() {File file = new File("D:\\demo\\a.txt");File file1 = new File("d:\\demo", "a.txt");File parentDirectory = new File("D:\\demo");File file2 = new File(parentDirectory, "a.txt");File file3 = new File("/a");// E:\\File file4 = new File("src/com/java/file/FileDemo.java");// E:\\}

1.5 常用属性

static String pathSeparator  
static char pathSeparatorChar//代表的是磁盘中系统环境变量的分隔符。windows: ;  unix: :static String separator  ;
static char separatorChar ;//代表路径盘符分割  windows: \   unix: ///路径拼接 
private static void demo1() {System.out.println(File.pathSeparator);System.out.println(File.pathSeparatorChar);System.out.println(File.separator);System.out.println(File.separatorChar);// \
}

1.6 常用方法

1.6.1 作为文件

方法描述
public String getName()返回由此File表示的文件名称。
public long length()返回由此File表示的文件的长度。 如果此路径名表示一个目录,则返回值是不确定的。
public long lastModified()返回File对象对应的文件或目录的最后修改时间(毫秒值)。
public boolean exists()此File表示的文件是否实际存在。
public boolean isFile()此File表示的是否为文件。
public boolean isHidden()此File表示的是否为隐藏文件。
public boolean canExecute()测试应用程序是否可以执行此抽象路径名表示的文件。
public boolean canRead()测试应用程序是否可以读取此抽象路径名表示的文件。
public boolean canWrite()测试应用程序是否可以修改此抽象路径名表示的文件。
public boolean delete()删除指定文件
public boolean setLastModified(long time)修改最后修改文件的时间
public boolean setReadOnly()修改文件为只读
public boolean createNewFile()当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。(一定要保证父级目录存在)
public boolean renameTo(File dest)重新命名此抽象路径名表示的文件或目录。但是此方法行为的许多方面都是与平台有关的:重命名操作无法将一个文件从一个文件系统移动到另一个文件系统。
public String getParent()返回此抽象路径名父目录的路径名字符串
public File getParentFile()返回此抽象路径名父目录的抽象路径名
public String getAbsolutePath()返回文件的绝对路径
public String getPath()返回文件的相对路径
private static void demo3() {//当File代表的是文件的时候File file = new File("D:\\demo\\a.txt");System.out.println(file);//获得文件/目录的相关属性的信息System.out.println("文件名称:" + file.getName());System.out.println("相对路径:" + file.getPath());System.out.println("绝对路径:" + file.getAbsolutePath());System.out.println("获得父级目录路径:" + file.getParent());System.out.println("获得父级目录对象:" + file.getParentFile());System.out.println("获得文件大小(字节):" + file.length());System.out.println("获得上一次操作文件的时间:" + file.lastModified());//毫秒数System.out.println("获得上一次操作文件的时间:" + new Date(file.lastModified()));// 将毫秒数转换成具体的日期类对象  Date  LocalDate  LocalDateTime//判断System.out.println("判断文件是否存在:" + file.exists());//手动创建文件//System.out.println(file.createNewFile());// 1. try...catch...finally  2. throwsSystem.out.println(file.isFile());System.out.println(file.isDirectory());System.out.println(file.canRead());System.out.println(file.isHidden());System.out.println(file.setReadOnly());//更改为只读文件//删除文件System.out.println(file.delete());
}
private static void demo5() {File file = new File("./src/user.txt");//相对于当前的项目  day17System.out.println(file.exists());System.out.println(file.getAbsolutePath());try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}
}

1.6.2 作为目录

方法描述
public String getName()返回由此File表示的目录名称。
public boolean exists()此File表示的目录是否实际存在。
public boolean isDirectory()判断File对象是否是目录
public boolean mkdir()创建由此File表示的目录。
public boolean mkdirs()创建多级目录
public File getParentFile()返回此抽象路径名父目录的抽象路径名
public String getAbsolutePath()返回目录的绝对路径
public String getPath()返回目录的相对路径
public String[] list()获得File目录中的一级子文件名称或目录名称。
public File[] listFiles()获得File目录中的一级子文件对象或目录对象。
public File[] listFiles(FileFilter filter)返回所有满足指定过滤器的文件和目录。如果给定 filter 为 null,则接受所有路径名。否则,当且仅当在路径名上调用过滤器的 FileFilter.accept(File pathname)方法返回 true 时,该路径名才满足过滤器。
private static void demo6() {//File 代表目录-----> 目录路径File directory = new File("/demo", "b/c/d/e");System.out.println(directory.getName());System.out.println(directory.getPath());System.out.println(directory.getAbsolutePath());System.out.println(directory.getParent());//目录不存在  要创建一个目录if (!directory.exists()) {//System.out.println(directory.mkdir());System.out.println(directory.mkdirs());//创建>=1目录}System.out.println(directory.isDirectory());//System.out.println(directory.exists());//System.out.println(directory.delete());  只能删除空目录
}
private static void demo7() {//一般创建的目录都是以当前时间为准//获得当前此刻的时间: 目录名称 String dateStr = LocalDate.now().toString();File dir = new File("src" + File.separator + dateStr);System.out.println(dir.mkdirs());
}
private static void demo8() {File dir = new File("E:\\workspace\\JavaTest");//查询展示指定目录下的所有的子级资源//删除dir里面后缀是txt所有的文件----> file.delete()String[] list = dir.list();//获得1级资源名称(目录名/文件名)System.out.println(Arrays.toString(list));File[] files = dir.listFiles();//获得1级资源对象(目录对象/文件对象)System.out.println(Arrays.toString(files));
}

1.7 递归-斐波那契数列

● 什么是方法的递归?
● 方法的递归是指在一个方法的内部调用自身的过程。 递归必须要有结束条件,不然就会陷入无限递归的状态,永远无法结束调用;

public static void main(String[] args) {File dir = new File("E:\\workspace\\JavaTest\\demo");//System.out.println(dir.delete());//删除目录 只能删除空目录deleteFileTxt(dir);
}
  • 案例: 删除指定目录所有的文件的txt资源
private static void deleteFileTxt(File parentDirectory) {//删除的文件后缀是txtfor (File child : childFiles) {//child 可能是子级目录  也可能是子级文件if (child.isFile()) {//if (child.getName().endsWith("txt")) child.delete();} else {//是目录//继续查询子集  继续执行删除txt//递归deleteFileTxt(child);}}
}public static void main(String[] args) {File dir = new File("E:\\workspace\\day17\\demo");listChild(dir,"|-");
}private static void listChild(File dir, String s) {String[] childNameArray = dir.list();for (String name : childNameArray) {System.out.println(s + name);//如果是目录 需要再次递归//创建一个File 作为目录对象File child = new File(dir, name);if (child.isDirectory()) listChild(child, "| " + s);}
}

2.IO

2.1 为什么要学习IO?

● 由于我们在开发中,需要将数据持久化存储。必须存储磁盘或者缓存进行维护,因此我们学习了File类相关功能。
● 但是File类只能获得文件或者目录相关的属性,不能读写文件存储的数据。
● 数据持久存储,就离不开2个功能: 1.将数据存储文件 2.获得文件数据
● 也就是要实现读写功能,这个时候必须使用IO实现。

2.2 概念

I input 输入 O output 输出
● 数据的传输,可以看做是一种数据的流动,按照流动的方向,分为输入input 和输出output ,即流向Java程序的是输入流,流出Java程序的是输出流;
● Java中I/O操作主要是指使用java.io包下的类与接口进行输入、输出操作。
● 输入也叫做读取数据,输出也叫做作写出数据。
● File对象不能直接读取和写入数据,如果要操作数据,需要IO流。
● File对象好比是到水库的“路线地址”以及水库的描述信息(包括水库的大小、位置、建造时间等),要“存取”里面的水到你“家里”,需要“管道”,IO流就好比是管道。

2.3 流的分类:

  1. 从传输方向上看:
  • 输入流: 将本地磁盘数据传输至JVM
  • 输出流: 将JVM数据传输到本地磁盘
  1. 从传输单位上看:
  • 字节流: 以字节为单位进行传输, 可以传输任意类型的文件, 如文本|图片|视频|音频等
  • 字符流: 以字符为单位记性传输, 只能传输文本类型的文件, 如.txt | .java | .excel等
  1. 从传输功能上看:
  • 节点流: 是具备实际传输功能的流
  • 过滤流: 不具备实际传输作用, 功能为给节点流添加附加功能|增强节点流传输能力

2.4 有关字节流

● 对流中数据 一个字节一个字节的处理;
● 字节输入流是 InputStream ;字节输出流是OutputStream
● 都是抽象类。封装了所有的字节流里面最基本的读写操作

2.4.1 字节流体系

在这里插入图片描述

2.4.2 InputStream

1.层级
public abstract class InputStream extends Object implements Closeable{}

注意:类实现Closeable 证明他就是一个资源。使用完毕之后 需要释放物理资源
不管程序是否出现了异常 都需要释放物理资源,释放方式有
1.finally
2.try…with…resoucres
3.@CleanUp

2.常用方法
方法描述
public int read()从输入流读取一个字节。返回读取的字节值。虽然读取了一个字节,但是会自动提升为int类型。如果已经到达流末尾,没有数据可读,则返回-1。
public int read(byte[] b)从输入流中读取一些字节数,并将它们存储到字节数组 b中 。每次最多读取b.length个字节。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。
public int read(byte[] b,int off,int len)从输入流中读取一些字节数,并将它们存储到字节数组 b中,从b[off]开始存储,每次最多读取len个字节 。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。
public void close()关闭此输入流并释放与此流相关联的任何系统资源。
public byte[] readAllBytes()JDK9中新增的方法;从输入流读取所有字节放到一个字节数组中,返回此字节数组;如果数据过大有可能会发生OOM错误,使用时要注意;
public byte[] readNBytes(int len)JDK11中新增的方法;从输入流总读取指定长度的字节放入字节数组中进行放回;
int available();获得流中有效字节数量
long transferTo(OutputStream out);JDK9新增的方法。将字节流输入内容转换到字节输出流对象中
3.常用子类构造
FileInputStream(String filePath);//name: 文件路径-----> 文件存在
FileInputStream(File file);
BufferedInputStream(InputStream in);
4.使用方法
4.1 read()
private static void testRead1() {//目的: 读取指定文件里面的数据。//1.指定文件String filePath = "src/a.txt";InputStream inputStream = null;try {//2.创建字节输入流对象inputStream = new FileInputStream(filePath);//文件的数据都在inputStreamSystem.out.println(inputStream.available());/*//3.读取文件数据int data = inputStream.read();//一次读取一个字节 -1System.out.println("读取到的1个字节数据:"+(char)data);System.out.println(inputStream.available());*///3.读取文件所有的内容/*int available = inputStream.available();for (int i = 0; i < available; i++) {System.out.print((char) inputStream.read());}*//*int data = inputStream.read();while (data!=-1){System.out.print((char)data);data = inputStream.read();}*/int len;while ((len = inputStream.read()) != -1) {System.out.print((char) len);}//不管使用哪一个字节流  只要操作中文的数据  肯定会乱码的问题} catch (IOException e) {e.printStackTrace();} finally {try {if (inputStream != null) inputStream.close();} catch (IOException e) {e.printStackTrace();}}
}
4.2 try…with…resources

● 在上面的read功能里面,使用流结束之后,我们需要释放资源,调用close方法
● 代码里面嵌套了很多try…catch语句,很臃肿。
● 在JDK1.7之后,建议我们使用try…with…resources替换finally代码块
● 一种更加优雅的方式释放流资源对象。
● 想使用try…with…resources 一定要保证资源类型必须实现Closeable接口,否则程序会报错。

public class MyClass implements Closeable {@Overridepublic void close() throws IOException {System.out.println("我被关闭了.....");}
}
private static void testRead2() throws FileNotFoundException {//使用更加优雅的方式释放流对象  try...with...resources//无需再编写finally  自动调用closeInputStream inputStream = new FileInputStream("src/a.txt");MyClass myClass = new MyClass();try (inputStream; myClass) {//循环读取文件数据int len;while ((len = inputStream.read()) != -1) {System.out.print((char) len);}} catch (IOException e) {e.printStackTrace();}}
4.3 read(byte[] bytes)
private static void testRead2() throws FileNotFoundException {//1.指定文件路径String path = "src/com/java/io/InputStreamDemo.java";//2.创建字节输入流对象InputStream inputStream = new FileInputStream(path);//3.操作流---->读取文件数据try (inputStream) {/*System.out.println("字节数量:" + inputStream.available());byte[] bytes = new byte[1024];//1024的整数倍  理论上length越大 读取的性能高int len = inputStream.read(bytes);//读取到的数据都在bytesSystem.out.println("len:" + len);//读到的有效的字节数量  11//字节数组转StringSystem.out.println(Arrays.toString(bytes));String str = new String(bytes,0,len);System.out.println(str);*///读取src/com/java/io/InputStreamDemo.java//在控制台打印输出byte[] bytes = new byte[500];int len;while ((len = inputStream.read(bytes)) != -1) {System.out.println(new String(bytes, 0, len));}} catch (IOException e) {e.printStackTrace();}}
4.4 read(byte[] b, int index, int len)
  • 这个方法咱们一般不用,了解即可
private static void testRead3() throws FileNotFoundException {InputStream inputStream = new FileInputStream("src/a1.txt");try (inputStream) {byte[] bytes = new byte[10];// public int read(byte b[], int off, int len)//off: index 数组的索引位置//len: 等价于read方法的返回值的结果数据  存储数组里面的真实的字节数量int read = inputStream.read(bytes, 0, bytes.length);System.out.println(Arrays.toString(bytes));System.out.println(read);} catch (IOException e) {e.printStackTrace();}}

2.4.3 OutputStream

1.层级
public abstract class OutputStream extends Object implements Closeable, Flushable{//实现Closeable  也是资源  需要释放物理资源//实现Flushable  底层有缓冲区  在某些情况下需要调用flush()方法
}
2.常用方法
方法描述
public void write(int b)将指定的字节输出流
public void write(byte[] b)将 b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len)从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
public void flush()刷新此输出流并强制任何缓冲的输出字节被写出。
public void close()关闭此输出流并释放与此流相关联的任何系统资源。
3.常用子类构造
public FileOutputStream(String filePath) ;
public FileOutputStream(File file) 
public FileOutputStream(String name, boolean append) ;// append 追加  默认值false 
public FileOutputStream(File file, boolean append);   public BufferedOutputStream(OutputStream out) {this(out, 8192);
}    
4.使用方法
public static void main(String[] args) throws FileNotFoundException {//将指定的数据写入指定文件中//对于字节输入流而言 执行read  保证文件必须存在//对于字节输出流而言 执行write  文件不必存在(会自动的创建新的文件----> File.createNewFile())//前提: 文件的父级目录必须存在String path = "src/b.txt";//1.创建字节输出流对象OutputStream outputStream = new FileOutputStream(path,true);try(outputStream){//2.将数据写入文件中outputStream.write('a');outputStream.write(97);outputStream.write('我');outputStream.write(65);outputStream.write('\n');byte[] bytes = {98,99,100,102};outputStream.write(bytes);outputStream.write('\n');outputStream.write("你太美".getBytes());outputStream.write('\n');outputStream.write("你太美".getBytes(),0,2);} catch (IOException e) {e.printStackTrace();}
}

2.3.4 案例: 用户上传头像

  • 思考
在开发中  哪些功能需要使用IO实现?//文件上传与下载、文件导入导出等//1.选择本地一张图片资源//2.将本地图片的资源复制到另外一台计算中的另外一个文件中   ---> 读取本地资源  写入到另外一个文件中//3.图片是回显成功的(图片服务器里面的资源) ----> 获得资源存在服务器的路径   

● 一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。
● 所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

  • 1.基础版
/*** 上传文件** @param sourceFilePath 原文件路径* @return 上传成功之后的服务器路径*/
public static String uploadImage(String sourceFilePath) throws FileNotFoundException {if (sourceFilePath == null || sourceFilePath.isBlank()) {throw new RuntimeException("文件路径不合法");}//读取原文件数据  写入到服务器中目标文件InputStream inputStream = new FileInputStream(sourceFilePath);//获得原文件的名称String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);String targetFilePath = PARENT_DIRECTORY + fileName;OutputStream outputStream = new FileOutputStream(targetFilePath);//读写try (inputStream; outputStream) {int len;while ((len = inputStream.read()) != -1) {outputStream.write(len);}} catch (IOException e) {e.printStackTrace();}return targetFilePath;
}

2.问题

//以上的上传可以成功。
public static void main(String[] args) throws FileNotFoundException {// A用户上传//System.out.println(uploadImage("D:\\demo\\a.jpg"));//B用户System.out.println(uploadImage("E:\\demo\\a.jpg"));//存在一些问题//1. 用户上传重名的文件 会出现文件被覆盖的问题//2. 遇见大文件的读写  性能低//3. 用户变多  资源变多  查询一个文件 性能低
}
  • 3.升级版
    1.解决文件覆盖/重名
public static String uploadImage(String sourceFilePath) throws FileNotFoundException {if (sourceFilePath == null || sourceFilePath.isBlank()) {throw new RuntimeException("文件路径不合法");}//读取原文件数据  写入到服务器中目标文件InputStream inputStream = new FileInputStream(sourceFilePath);//获得原文件的名称----> 目前就不使用原文件名称  可能出现重名问题----> 文件就会被覆盖//String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);//使用UUIDString name = UUID.randomUUID().toString().replaceAll("-", "");//获得原文件的后缀(扩展名)String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));String targetFilePath = PARENT_DIRECTORY + name + extension;//建议使用StringBuilderOutputStream outputStream = new FileOutputStream(targetFilePath);//读写try (inputStream; outputStream) {int len;while ((len = inputStream.read()) != -1) {outputStream.write(len);}} catch (IOException e) {e.printStackTrace();}return targetFilePath;
}

2.解决读写慢(自定义缓冲区)

public static String uploadImage(String sourceFilePath) throws FileNotFoundException {if (sourceFilePath == null || sourceFilePath.isBlank()) {throw new RuntimeException("文件路径不合法");}//读取原文件数据  写入到服务器中目标文件InputStream inputStream = new FileInputStream(sourceFilePath);//获得原文件的名称----> 目前就不使用原文件名称  可能出现重名问题----> 文件就会被覆盖//String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);//使用UUIDString name = UUID.randomUUID().toString().replaceAll("-", "");//获得原文件的后缀(扩展名)String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));String targetFilePath = PARENT_DIRECTORY + name + extension;//建议使用StringBuilderOutputStream outputStream = new FileOutputStream(targetFilePath);//读写//大文件读写----> 自定义缓冲try (inputStream; outputStream) {byte[] bytes = new byte[1024 * 20];int len;while ((len = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}} catch (IOException e) {e.printStackTrace();}return targetFilePath;}

● 缓冲流,也叫高效流,按照数据类型分类:
○ 字节缓冲流:BufferedInputStream,BufferedOutputStream
○ 字符缓冲流:BufferedReader,BufferedWriter
● 缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
● 缓冲字节输入输出流:BufferedInputStream/BufferedOutputStream;

public static String upload1(String sourceFilePath) throws FileNotFoundException {String name = UUID.randomUUID().toString().replaceAll("-", "");String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));String targetFilePath = PARENT_DIRECTORY + name + extension;// 可以使用高效字节流解决读写慢----> 底层自带缓冲----> 8192  byte[]BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(sourceFilePath));BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(targetFilePath));try (inputStream; outputStream) {int len;byte[] bytes = new byte[1024 * 20];//自定义的缓冲数组>8192  这是时候 底层的缓冲无效了while ((len = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}} catch (IOException e) {e.printStackTrace();}return targetFilePath;}

3.多目录存储

//用户变多  资源变多  查询一个文件 性能低
//  解决: 多目录存储
//      1. 可以以当前日期为目录 维护用户在今日上传的图片资源
//      2. 目录打散---> 获得文件名称16进制的hash数据  获得前几个16进制的字符的数据 作为新的目录的名称//        String name = "a.jpg";
//        String hexString = Integer.toHexString(name.hashCode());
//        System.out.println(hexString);
//        String childPath = hexString.charAt(0) + "/" + hexString.charAt(1);// 5/6//System.out.println(new Object().toString());
/*** 上传文件** @param sourceFilePath 原文件路径* @return 上传成功之后的服务器路径*/
public static String uploadImage(String sourceFilePath) throws FileNotFoundException {if (sourceFilePath == null || sourceFilePath.isBlank()) {throw new RuntimeException("文件路径不合法");}//读取原文件数据  写入到服务器中目标文件InputStream inputStream = new FileInputStream(sourceFilePath);//获得原文件的名称----> 目前就不使用原文件名称  可能出现重名问题----> 文件就会被覆盖//String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);//使用UUIDString name = UUID.randomUUID().toString().replaceAll("-", "");//获得原文件的后缀(扩展名)String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));//upload/user/2022-12-01/a.jpg/*String curDateStr = LocalDate.now().toString();//目录不存在  自动创建----> File.mkdirs()File childDir = new File(PARENT_DIRECTORY, curDateStr);if (!childDir.exists()) {childDir.mkdirs();}*/String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);String hexString = Integer.toHexString(fileName.hashCode());String childPath = hexString.charAt(0)+"/"+hexString.charAt(1);File childDir = new File(PARENT_DIRECTORY, childPath);if (!childDir.exists()) {childDir.mkdirs();}String targetFilePath = PARENT_DIRECTORY + childPath + "/" + name + extension;//建议使用StringBuilderOutputStream outputStream = new FileOutputStream(targetFilePath);//大文件读写----> 自定义缓冲try (inputStream; outputStream) {byte[] bytes = new byte[1024 * 20];int len;while ((len = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}} catch (IOException e) {e.printStackTrace();}//小文件读写/* try (inputStream; outputStream) {int len;while ((len = inputStream.read()) != -1) {outputStream.write(len);}} catch (IOException e) {e.printStackTrace();}*/return targetFilePath;
}

相关文章:

有关Java中的IO(1) --字节流和File类

学习目标 ● 掌握常用的File类常用的方法 ● 掌握字节字符流的基本使用方法 1.File 1.1为什么要了解File ● 因为数据很重要所以我们要把数据永久化/持久化存储。 ● 之前开发都把数据存入了内存 ● 存储内存优势: 性能快 ● 弊端&#xff1a; 程序结束&#xff0c;数据消失…...

基于DeepSeek(本地部署)和RAGFlow构建个人知识库

总结自视频&#xff08;很强的小姐姐视频&#xff0c;讲解清晰明了&#xff09;&#xff1a;【知识科普】【纯本地化搭建】【不本地也行】DeepSeek RAGFlow 构建个人知识库_哔哩哔哩_bilibili 1. 背景 deepseek官方网页版也虽然很强&#xff0c;能够满足绝大部分需求&#xf…...

微信小程序文件缓存处理的完善方案

以下是微信小程序文件缓存处理的 完善方案&#xff0c;涵盖存储管理、缓存策略、清理机制和异常处理&#xff0c;确保高效、可靠的文件缓存系统&#xff1a; 一、文件缓存架构设计 1. **存储分层**&#xff1a;- **内存缓存**&#xff1a;存储高频访问的小文件&#xff08;Bas…...

Tailwind CSS 问题:npm error could not determine executable to run

问题与处理策略 问题描述 npx tailwindcss init -p在使用 Tailwind CSS 的前端项目中&#xff0c;执行上述指令&#xff0c;即初始化 Tailwind CSS 时&#xff0c;报如下错误 npm error could not determine executable to run# 报错npm 错误无法确定要运行的可执行文件问题…...

CAD2025电脑置要求

Windows 系统 操作系统&#xff1a;64 位 Microsoft Windows 11 和 Windows 10 version 1809 或更高版本。 处理器 基本要求&#xff1a;2.5-2.9GHz 处理器&#xff0c;不支持 ARM 处理器。 推荐配置&#xff1a;3GHz 以上处理器&#xff08;基础&#xff09;&#xff0c;4GHz …...

javascript字符串截取有哪些

在 JavaScript 中&#xff0c;字符串截取主要通过以下方法实现&#xff0c;每种方法有不同的特性&#xff0c;适用于不同场景&#xff1a; 1. slice(startIndex, endIndex) 功能&#xff1a;从 startIndex 到 endIndex&#xff08;不包含&#xff09;截取子字符串。特性&#…...

使用CSS Grid布局时,如何避免元素重叠?

使用CSS Grid布局时&#xff0c;如何避免元素重叠&#xff1f; 文章目录 使用CSS Grid布局时&#xff0c;如何避免元素重叠&#xff1f;1. 引言2. 元素重叠的常见原因2.1 显式定位错误2.2 使用 grid-auto-flow: dense2.3 网格区域定义不明确2.4 内容尺寸超出预期 3. 解决策略3.…...

ALG(Alloy+Loki+Grafana)轻量级日志系统

ALG(AlloyLokiGrafana)轻量级日志系统 前提要求 GrafanaMinioNginxPrometheus Grafana日志收集系统旧版是PLG(ProtailLokiGrafana), Protail收集日志, Loki存储, Grafana展示, 后续的Protail不维护了, Grafana推出了Alloy代替Pritial, 除了收集日志外, 还集成管理Prometheus各种…...

Golang的网络流量控制

# Golang的网络流量控制 什么是网络流量控制&#xff1f; 网络流量控制是指针对网络数据传输过程中的流量进行管理和调控的一种技术手段。通过网络流量控制&#xff0c;我们可以对网络中的数据传输速率、带宽使用情况、数据包丢失率等进行监控和调整&#xff0c;以达到优化网络…...

MRI学习笔记-Meta分析之SDM-PSI

软件介绍 软件下载&#xff1a;https://www.sdmproject.com/software/ 软件教程&#xff1a; https://zhoubolin.netlify.app/posts/sdm-psi/sdm-psi Meta-analysis of Voxel-Based Neuroimaging Studies using Seed-based d Mapping with Permutation of Subject Images (…...

Spring Boot 项目中 Redis 常见问题及解决方案

目录 缓存穿透缓存雪崩缓存击穿Redis 连接池耗尽Redis 序列化问题总结 1. 缓存穿透 问题描述 缓存穿透是指查询一个不存在的数据&#xff0c;由于缓存中没有该数据&#xff0c;请求会直接打到数据库上&#xff0c;导致数据库压力过大。 解决方案 缓存空值&#xff1a;即使…...

3-9 WPS JS宏单元格复制、重定位应用(拆分单表到多表)

************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...

Java集合面试篇

目录 1.概念 1.1.数组与集合的区别&#xff0c;用过哪些&#xff1f; 1.2.说说Java中的集合&#xff1f; 1.3.Java中的线程安全的集合是什么&#xff1f; 1.4.集合遍历的方法有哪些&#xff1f; 2.List 2.1.list可以一边遍历一边修改元素吗&#xff1f; 2.2.Arraylist和…...

C++入门——命名空间

C入门——命名空间 本期内容&#xff0c;我们正式进入C专栏。前几期内容中&#xff0c;我们用C语言实现了一些数据结构&#xff0c;包括顺序表&#xff0c;单链表&#xff0c;双向循环链表&#xff0c;栈和队列等等&#xff0c;为C的学习打下了基础。从现在开始&#xff0c;让…...

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例3: 行选择

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

pytest结合allure

Allure 一、文档二、指令三、装饰器3.1 allure.step装饰器3.2 allure.description装饰器3.3 allure.title装饰器3.4 allure.link、allure.issue 和 allure.testcase装饰器3.5 allure.epic、allure.feature 和 allure.story装饰器3.6 allure.severity装饰器 一、文档 allure文档…...

C++入门基础

文章目录 C核心特性详解&#xff08;基础增强版&#xff09;一、第一个C程序&#xff1a;Hello World完整代码解析新手常见问题 二、命名空间&#xff08;详解版&#xff09;1. 为什么需要命名空间&#xff1f;2. 命名空间使用场景3. 嵌套命名空间4. 匿名命名空间 三、输入输出…...

《大语言模型的原理发展与应用》:此文为AI自动生成

《大语言模型的原理发展与应用》&#xff1a;此文为AI自动生成 一、引言&#xff1a;大语言模型&#xff0c;AI 时代的 “新引擎” 在当今数字化浪潮中&#xff0c;大语言模型宛如一颗璀璨的明星&#xff0c;照亮了人工智能发展的道路&#xff0c;成为推动各领域变革的核心驱…...

SpringCloud系列教程(十三):Sentinel流量控制

SpringCloud中的注册、发现、网关、服务调用都已经完成了&#xff0c;现在就剩下最后一部分&#xff0c;就是关于网络控制。SpringCloud Alibaba这一套中间件做的非常好&#xff0c;把平时常用的功能都集成进来了&#xff0c;而且非常简单高效。我们下一步就完成最后一块拼图Se…...

[MySQL初阶]MySQL(4)基本查询

标题&#xff1a;[MySQL初阶]MySQL&#xff08;4&#xff09;基本查询 水墨不写bug 文章目录 一. 数据表设计二、对数据表的操作1. Create 操作&#xff08;插入数据&#xff09;查看最近受影响的行数&#xff1a; 2. Retrieve 操作&#xff08;读取数据&#xff09;&#xff0…...

使用Open WebUI下载的模型文件(Model)默认存放在哪里?

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年2月21日21点21分 &#x1f004;️文章质量&#xff1a;95分 文章目录 使用CMD安装存放位置 默认存放路径 Open WebUI下…...

Maven 私服的搭建与使用(一)

一、引言 在 Java 项目开发中&#xff0c;Maven 作为强大的项目管理和构建工具&#xff0c;极大地提高了开发效率&#xff0c;而 Maven 私服在开发过程中也扮演着至关重要的角色。私服是一种特殊的远程仓库&#xff0c;架设在局域网内&#xff0c;代理广域网上的远程仓库&…...

java每日精进 3.06 【多数据源】

数据库连接池&#xff08;Database Connection Pool&#xff09; 基本信息 是一种用于管理数据库连接的技术。它通过预先创建一定数量的数据库连接&#xff0c;并将其缓存在池中&#xff0c;供多个客户端或应用程序使用&#xff0c;从而减少了每次请求时连接数据库的开销。 …...

Leetcode 3469. Find Minimum Cost to Remove Array Elements

Leetcode 3469. Find Minimum Cost to Remove Array Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3469. Find Minimum Cost to Remove Array Elements 1. 解题思路 这一题我没啥特别好的思路&#xff0c;就只能动态规划了&#xff0c;倒是也能过&#xff0c;不过总…...

多线程-CompletableFuture

简介 CompletableFuture&#xff1a;异步任务编排工具。java 8中引入的一个类&#xff0c;位于juc包下&#xff0c;是Future的增强版。它可以让用户更好地构建和组合异步任务&#xff0c;避免回调地狱。 在CompletableFuture中&#xff0c;如果用户没有指定执行异步任务时的线…...

常用限流算法解析与实现

‌一、固定窗口计数器法‌ ‌原理‌&#xff1a;在固定时间窗口&#xff08;如1秒&#xff09;内统计请求次数&#xff0c;超过阈值则触发限流。 ‌Java实现‌&#xff1a; public class FixedWindowCounter { private static final long WINDOW_MS 1000; // 1秒窗口 priv…...

Swift系列02-Swift 数据类型系统与内存模型

Swift 是一门现代的、安全的编程语言&#xff0c;其类型系统和内存模型设计对性能和安全性有着重要影响。本文将深入探讨 Swift 的数据类型系统与内存模型&#xff0c;帮助你更好地理解并利用这些特性来优化你的 iOS 应用。本文主要包含&#xff1a; 值类型和引用类型&#xf…...

如何不重启,生效windows环境变量

场景 使用php 进行composer 时&#xff0c;composer 要求php7.2以上&#xff0c;我常用的是7.1&#xff0c;不想来回修改&#xff0c;还是重启电脑 临时修改 打印当前环境变量 echo %PATH%临时修改当前环境变量&#xff08;如果需要指定的值&#xff0c;可将全部复制出来&a…...

Ubuntu20.04本地配置IsaacLab 4.2.0的G1训练环境(二):训练与推理

Ubuntu20.04本地配置IsaacLab4 4.2.0的G1训练环境&#xff08;二&#xff09;&#xff1a;训练与推理 训练推理 写在前面&#xff0c;本文档的实现需要IsaacLab的成功安装&#xff0c;可参考&#xff08;一&#xff09;。 训练 在IsaacLab目录下&#xff0c;isaaclab的conda虚…...

设计模式说明

23种设计模式说明 以下是常见的 23 种设计模式 分类及其核心思想、应用场景和简单代码示例&#xff0c;帮助你在实际开发中灵活运用&#xff1a; 一、创建型模式&#xff08;5种&#xff09; 解决对象创建问题&#xff0c;降低对象耦合。 1. 单例模式&#xff08;Singleton&…...

K8s 1.27.1 实战系列(四)验证集群及应用部署测试

一、验证集群可用性 1、检查节点 kubectl get nodes ------------------------------------------------------ NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane 3h48m v1.27.1 k8s-node1 Ready <none> …...

Artec Leo+Ray II 三维扫描仪成功为VR展数字化30吨重设备-沪敖3D

挑战&#xff1a;在贸易展上展示重达30吨的机械设备&#xff0c;同时克服设备搬运和展示的难题&#xff0c;减轻物流负担。。 解决方案&#xff1a;Artec Leo、Artec Ray II、Artec Studio、Blender、Unity、Microsoft HoloLens、HTC VIVE PRO 效果&#xff1a;在虚拟展厅中&am…...

Redis 各数据类型使用场景详解

1. 字符串&#xff08;String&#xff09; 场景 1&#xff1a;计数器&#xff08;如文章阅读量&#xff09; 问题&#xff1a; 高并发下对同一数值进行增减操作时&#xff0c;需保证原子性&#xff0c;避免竞态条件导致数据不一致。 频繁读写可能成为性能瓶颈。 解决方案&a…...

spark写数据库用连接池找不到driver类

最近遇到一个很离谱的bug&#xff0c;在写spark代码把数据写到mysql的时候考虑到连接的开销&#xff0c;所以用了HikariCP连接池&#xff0c;但是无语的是程序执行死活加载不到mysql的Driver类&#xff0c;但是解压了jar看到mysql-conn包就在lib下面&#xff0c;版本也是5.x的没…...

上传文件到对象存储是选择前端还是后端

对于云上对象存储的上传方式选择&#xff08;前端直传或后端代理上传&#xff09;&#xff0c;需综合考虑安全性、性能、成本、业务需求等因素。 1. 推荐前端直传的场景 适用条件&#xff1a; 大文件上传&#xff08;如视频、大型数据集&#xff09;高并发场景&#xff08;如…...

NanoMQ ds笔记250306

NanoMQ多版本下载地址 https://www.emqx.com/zh/downloads/nanomq NanoMQ官方文档 https://nanomq.io/docs/zh/latest/ NanoMQ 是一个专为物联网边缘计算设计的轻量级、高性能 MQTT 消息代理&#xff08;Message Broker&#xff09;&#xff0c;由中国的开源物联网公司 EMQ 开…...

sqlmap:从基础用法到漏洞利用实战

1. sqlmap基础认知 sqlmap是一款开源的渗透测试工具&#xff0c;能自动检测和利用SQL注入漏洞&#xff0c;支持MySQL、Oracle、PostgreSQL等多种数据库管理系统。其设计旨在简化SQL注入检测流程&#xff0c;助力安全人员在复杂网络环境中快速定位与评估漏洞风险。它通过发送精…...

DFS学习笔记

题目描述 X 国王有一个地宫宝库。是 nm 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。 地宫的入口在左上角&#xff0c;出口在右下角。 小明被带到地宫的入口&#xff0c;国王要求他只能向右或向下行走。 走过某个格子时&#xff0c;如果那个格子中的宝贝价值…...

C++ STL string容器全解析

一、引言 在 C 编程的广阔领域中&#xff0c;字符串处理是一项极为基础且频繁的操作。从简单的文本解析&#xff0c;到复杂的文件读取与处理&#xff0c;字符串几乎无处不在。而 C 中的 string 容器&#xff0c;就像是一把瑞士军刀&#xff0c;为我们处理字符串提供了强大而便…...

React基础之项目创建

项目创建 create-react-app 项目名(小写) 运行 pnpm run start 在React中&#xff0c;使用的语法格式是jsx&#xff0c;也就是js与html相结合的形式 import logo from ./logo.svg; import ./App.css; function App() { return ( <div className"App"> <head…...

迷你世界脚本道具接口:Item

道具接口&#xff1a;Item 彼得兔 更新时间: 2023-04-26 10:26:18 继承自 Actor 具体函数名及描述如下: 序号 函数名 函数描述 1 getItemName(...) 获取道具名称 2 getItemId(...) 获取actor对应的道具ID&#xff0c;如球类等 3 getDropItemNum(...) …...

Unity摄像机跟随物体

功能描述 实现摄像机跟随物体&#xff0c;并使物体始终保持在画面中心位置。 实现步骤 创建脚本&#xff1a;在Unity中创建一个新的C#脚本&#xff0c;命名为CameraFollow。 代码如下&#xff1a; using UnityEngine;public class CameraFollow : MonoBehaviour {public Tran…...

计算机毕业设计SpringBoot+Vue.js青年公寓服务平台(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

vue实现日历签到效果

在工作任务进行时&#xff0c;有一个签到日历的功能需求要实现&#xff0c;经过文档查询和样式优化实现了需求&#xff0c;在此记录一下。 技术背景&#xff1a;vue2vant(样式控件&#xff09; less 一个公共样式文件 html实现部分&#xff1a; <div class"calenderB…...

(十 八)趣学设计模式 之 观察者模式!

目录 一、 啥是观察者模式&#xff1f;二、 为什么要用观察者模式&#xff1f;三、 观察者模式的实现方式四、 观察者模式的优缺点五、 观察者模式的应用场景六、 总结 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢博主的讲解方式&#xff0c;…...

笔记:在Git中.gitmodules文件的功能和作用和如何使用

一、目的&#xff1a;简单介绍下在Git中.gitmodules文件的功能和作用已经 .gitmodules 文件是 Git 子模块&#xff08;submodule&#xff09;功能的一部分&#xff0c;用于管理和配置子模块。子模块允许一个 Git 仓库包含另一个 Git 仓库作为其子目录&#xff0c;这对于管理依赖…...

Swift 常量

Swift 常量 引言 Swift 是一种由苹果公司开发的编程语言,主要用于 iOS、macOS、watchOS 和 tvOS 等平台的应用开发。在 Swift 中,常量是一种不可变的变量,它用于存储固定不变的值。了解和使用常量是 Swift 编程的基础,本文将详细介绍 Swift 常量的概念、类型、声明以及使…...

Ubuntu20.04双系统安装及软件安装(七):Anaconda3

Ubuntu20.04双系统安装及软件安装&#xff08;七&#xff09;&#xff1a;Anaconda3 打开Anaconda官网&#xff0c;在右侧处填写邮箱&#xff08;要真实有效&#xff01;&#xff09;&#xff0c;然后Submit。会出现如图示的Success界面。 进入填写的邮箱&#xff0c;有一封Ana…...

Google AI概览升级,AI模式全新登场!

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

【智能体架构:Agent】LangChain智能体类型ReAct、Self-ASK的区别

1. 什么是智能体 将大语言模型作为一个推理引擎。给定一个任务&#xff0c; 智能体自动生成完成任务所需步骤&#xff0c; 执行相应动作&#xff08;例如选择并调用工具&#xff09;&#xff0c; 直到任务完成。 2. 先定义工具&#xff1a;Tools 可以是一个函数或三方 API也…...