项目文件下载器,基于Thread多线程

目录

1、Http 工具类

2、关于下载的关系类

2.1 展示下载信息

#下载信息展现线程类

#在主下载类中,进行调用上述线程类

2.2 文件的分块下载

#文件分块下载类

#文件按分块进行分别切分的方法

# 使用 LongAdder 类型,更改 DownLoadInfoThread 展现下载信息类

2.3 文件的合并以及临时文件的清除

#文件的合并

#临时文件的清除

#在主下载类中调用上述方法


前言:

一般都是在浏览器中进行点击即下载,这次使用代码结合多线程实现文件的下载操作

1、Http 工具类

在获取 HttpURLConnection 对象方法中,我们通过浏览器访问某个网站的时候,会将当前浏览器的版本,操作系统版本等信息的标识发送到网站所在的服务器中;所以当用程序代码去访问网站时,需要将自定义的标识发送过去

@Slf4j
public class HttpUtil {/***  分块下载* @param url          下载地址* @param startPos    下载文件起始位置* @param endPos      下载文件的结束位置*/public static HttpURLConnection getHttpURLConnection(String url, long startPos, long endPos) throws IOException {HttpURLConnection httpURLConnection = getHttpURLConnection(url);log.info("下载的区间是:{}-{}",startPos,endPos);if (endPos != 0) {httpURLConnection.setRequestProperty("RANGE","bytes="+startPos + "-" + endPos);}else {httpURLConnection.setRequestProperty("RANGE","bytes="+startPos + "-");}return httpURLConnection;}/*** 获取 HttpURLConnection 连接对象*/public static HttpURLConnection getHttpURLConnection(String url) throws IOException {URL httpUrl = new URL(url);HttpURLConnection openConnection = (HttpURLConnection)httpUrl.openConnection(); //建立连接//向文件所在服务器发送标识openConnection.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1");return openConnection;}/*** 获取下载文件的名称*/public static String getHttpFileName(String url){int index = url.lastIndexOf("/");   //获取文件路径中最后一个 “/”return url.substring(index + 1);}/*** 获取下载文件的大小*/public static long getHttpFileContentLength(String url) throws IOException{int fileContentLength;HttpURLConnection httpURLConnection = null;try {httpURLConnection = getHttpURLConnection(url);fileContentLength = httpURLConnection.getContentLength();}finally {//释放资源if(httpURLConnection!=null){httpURLConnection.disconnect();}}return fileContentLength;}}

2、关于下载的关系类

首先,我们先通过 IO 流 的方式进行文件下载操作

这里使用 try -- with -- resource 的形式进行文件的流输入输出,其特点就是在 try 中进行流操作后,后面不用进行 .close() 手动进行关闭,它会自动关闭流

public void my_DownLoad(String url) {//1.获取文件名String fileName = HttpUtil.getHttpFileName(url);//2.与下载目录地址进行拼接,获取当前文件目标下载路径String downLoadPath = Constant.DOWNLOAD_PATH + fileName;//3.获取连接对象HttpURLConnection httpURLConnection = null;try {httpURLConnection = HttpUtil.getHttpURLConnection(url);} catch (IOException e) {throw new RuntimeException(e);}//4.将文件读入内存中 【这里使用的是 try - with - resource 的形式】try (InputStream inputStream = httpURLConnection.getInputStream();BufferedInputStream bis = new BufferedInputStream(inputStream);FileOutputStream outputStream = new FileOutputStream(downLoadPath);BufferedOutputStream bos = new BufferedOutputStream(outputStream)){//4.1 从连接对象中获取下载信息资源,将其下载到目标路径int len = -1;while ((len = bis.read())!=-1){bos.write(len);}System.out.println("当前文件:<"+ fileName + "> ------【下载成功】,  下载目标地址:<" + downLoadPath + ">");}catch (FileNotFoundException e){log.error("下载的文件不存在{}",url);} catch (Exception e) {log.error("下载文件失败");}finally {if(httpURLConnection!=null) {//释放连接资源httpURLConnection.disconnect();}}}

下载运行结果:

现在这样下载的效果不是很好,一般下载都会展现文件的下载速度或者文件大小等

这里可以每隔一段时间来获取文件的下载信息,比如间隔1秒获取一次,然后将信息打印到控制台;同时,文件下载是一个独立的线程,另外还需要再开启一个线程来间隔获取文件的信息java.util.concurrent. ScheduledExecutorService  类可以帮助我们来实现此功能

2.1 展示下载信息

  • #下载信息展现线程类

  这里是定义的相关属性

    //下载文件的总大小private long httpFileContentLength;//本次积累下载的大小public volatile double downSize;    //一个线程改,一个线程读 (本次积累下载减去前一次下载的大小,就等于这一秒内的下载速率)//前一次或多次下载的大小public double prevSize;

其中,downSize 使用 volatile 关键字进行修饰,其作用是确保多个线程能够正确地处理被修饰的变量

主要有两个方面的作用:

  1. 可见性:volatile 保证被修饰的变量对所有线程可见。当一个线程修改了 volatile 变量的值,这个变化对其他线程是立刻可见的。这有助于解决了线程之间的可见性问题,确保线程之间能够及时地感知到变量的更新。没有 volatile 修饰的变量,可能会被线程本地缓存,导致一个线程对变量的修改不会立即反映到其他线程中

  2. 禁止指令重排序:volatile 修饰的变量,禁止编译器和处理器对其进行重排序。这确保了在访问 volatile 变量时,指令的执行顺序是固定的,不会出现意外的重排序导致的线程安全问题

在下载文件时显示剩余文件下载时间,有时可能会出现显示无限大的情况,这通常是因为在计算剩余下载时间时出现了问题或者没有足够的信息来进行准确的计算

以下是一些可能导致显示无限大的原因:

  1. 不完整的数据: 如果你在下载文件的过程中无法获得文件的总大小(Content-Length),那么计算剩余下载时间就会变得困难;通常,剩余下载时间是通过已下载的数据量与总文件大小以及下载速度来计算的;如果缺少总文件大小的信息,就无法进行准确的计算

  2. 下载速度为零: 如果下载速度为零,计算剩余下载时间将导致除以零的操作,结果是无限大;这可能发生在下载速度非常慢或网络连接出现问题的情况下

  3. 不稳定的下载速度: 如果下载速度波动非常大,或者在某些时间段内下载速度为零,那么计算剩余下载时间可能会非常不准确;下载速度的不稳定性会影响计算的准确性

  4. 软件问题: 有时,显示剩余下载时间的软件可能存在bug或问题,导致不正确的计算

完整代码:

public class DownLoadInfoThread implements Runnable{//下载文件的总大小private long httpFileContentLength;//本地已下载的文件大小public static double finishedSize;//本次积累下载的大小public static double downSize;    //一个线程改,一个线程读 (本次积累下载减去前一次下载的大小,就等于这一秒内的下载速率)//前一次或多次下载的大小public double prevSize;public DownLoadInfoThread(Long httpFileContentLength) {this.httpFileContentLength = httpFileContentLength;}@Overridepublic void run() {//1.计算文件的总大小,以 【MB】 为单位,这里保留两位小数String httpFileSize = String.format("%.2f",httpFileContentLength / Constant.MB);//2.计算每秒下载的速度,单位 【KB】int speed = (int)((downSize.doubleValue() - prevSize) / 1024d );prevSize = downSize.doubleValue();    //进行相减过后,将本次所下载的大小赋值给 pre ,以供下一次当作前一次所下载的大小//TODO 3.剩余文件的大小double remainSize = httpFileContentLength - downSize.doubleValue();//3.1 剩余的下载时间String remainTime = String.format("%.1f",remainSize / 1024d / speed);//3.2 判断是否为无限大的情况if("Infinity".equalsIgnoreCase(remainTime)){remainTime = "---";}//TODO 4.已下载的文件大小String alreadyDownloadFileSize = String.format("%.2f", (downSize.doubleValue())/ Constant.MB);String downInfo = String.format("已下载 %smb/%smb,速度 %skb/s,剩余时间 %ss",     //下载信息alreadyDownloadFileSize, httpFileSize, speed, remainTime);System.out.print("\r");System.out.print(downInfo);}
}

  • #在主下载类中,进行调用上述线程类

使用 ScheduledExecutorService 线程类 传入线程方法 FownLoadInfoThread 进行展示:

这里是 ScheduledExecutorService 线程类  的三种常用方法

  • schedule方法

该方法是重载的,这两个重载的方法都是有3个形参,只是第一个形参不同。

  1. Runnable / Callable<V> 可以传入这两个类型的任务
  2. long delay  时间数量
  3. TimeUnit unit 时间单位

该方法的作用是让任务按照指定的时间延时执行

  • scheduleAtFixedRate方法

该方法的作用是按照指定的时间延时执行,并且每隔一段时间再继续执行

  1. Runnable command  执行的任务
  2. long initialDelay     延时的时间数量
  3. long period         间隔的时间数量
  4. TimeUnit unit       时间单位

倘若在执行任务的时候,耗时超过了间隔时间,则任务执行结束之后直接再次执行,而不是再等待间隔时间执行

  • scheduleWithFixedDelay方法

该方法的作用是按照指定的时间延时执行,并且每隔一段时间再继续执行

  1. Runnable command  执行的任务
  2. long initialDelay     延时的时间数量
  3. long period         间隔的时间数量
  4. TimeUnit unit       时间单位

在执行任务的时候,无论耗时多久,任务执行结束之后都会等待间隔时间之后再继续下次任务

完整代码:

//...public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); //启动一个线程public void my_DownLoad(String url) {//1.获取文件名String fileName = HttpUtil.getHttpFileName(url);//2.与下载目录地址进行拼接,获取当前文件目标下载路径String downLoadPath = Constant.DOWNLOAD_PATH + fileName;//获取本地磁盘中文件的下载大小long localFileLength = FileUtils.getFileContentLength(downLoadPath);//3.获取连接对象HttpURLConnection httpURLConnection = null;DownLoadInfoThread downLoadInfoThread = null;try {httpURLConnection = HttpUtil.getHttpURLConnection(url);//3.1 获取下载文件的总大小int contentLength = httpURLConnection.getContentLength();//3.2 获取下载文件的大小,进行比较,判断是否已经下载过if(localFileLength >= contentLength){log.info("{}  >>> 文件已经下载完成,无需再次下载!",fileName);return;}//TODO 这里进行展现下载信息内容的操作 /downLoadInfoThread = new DownLoadInfoThread((long)contentLength);//3.3 每隔一秒执行一次scheduledExecutorService.scheduleAtFixedRate(downLoadInfoThread,1,1, TimeUnit.SECONDS);} catch (IOException e) {throw new RuntimeException(e);}//4.将文件读入内存中 【这里使用的是 try - with - resource 的形式】try (InputStream inputStream = httpURLConnection.getInputStream();BufferedInputStream bis = new BufferedInputStream(inputStream);FileOutputStream outputStream = new FileOutputStream(downLoadPath);BufferedOutputStream bos = new BufferedOutputStream(outputStream)){//4.1 从连接对象中获取下载信息资源,将其下载到目标路径int len = -1;byte[] bytes = new byte[Constant.BYTE_SIZE]; //防止 BufferedOutputStream 中的字节长度不够用while ((len = bis.read(bytes))!=-1){downLoadInfoThread.downSize += len; //为展现信息线程类中的【本次已下载的文件大小属性】赋值bos.write(bytes,0,len);}}catch (FileNotFoundException e){log.error("下载的文件不存在{}",url);} catch (Exception e) {log.error("下载文件失败");}finally {System.out.println("当前文件:<"+ fileName + "> ------【下载成功】,  下载目标地址:<" + downLoadPath + ">");if(httpURLConnection!=null) {//释放连接资源httpURLConnection.disconnect();}//释放【展现下载信息的线程】资源scheduledExecutorService.shutdownNow();}}//...

运行效果:

可见,效果给别人的感觉就是清晰明了(当然,这是实时动态的显示)

2.2 文件的分块下载

定义:文件分块下载有助于提高下载效率、降低成本,提供更好的用户体验,并增加网络资源的有效利用;这使其成为大型文件传输和分发的常见选择

基本思路:先将需要下载的文件进行切分 >>> 然后进行分块下载  >>>  最后将分好的块进行合并

#文件分块下载类

选择继承 Callable 接口的原因:

  1. Callable 接口通常与 Future 接口一起使用;Future 接口表示一个未来可能完成的任务,并提供方法来检查任务的执行状态、取消任 务的执行以及获取任务的执行结果;通过 CallableFuture 的结合使用,可以实现异步执行任务,并在需要时获取任务的执行结果

  2. 多线程编程:Callable 接口通常用于多线程编程,允许将任务提交给线程池或执行器框架,以并行执行多个任务。这可以提高程序的性能和响应性,特别是在需要执行耗时任务时

完整代码: 

@Slf4j
public class DownLoadTask implements Callable<Boolean> {private String url; //下载文件路径private long startPos; //下载文件当前部分块起始位置private long endPos; //下载文件当前部分块结束位置private int part;   //用来标识是哪一部分public DownLoadTask(String url, long startPos, long endPos, int part) {this.url = url;this.startPos = startPos;this.endPos = endPos;this.part = part;}@Overridepublic Boolean call() throws Exception {//1.获取文件名String httpFileName = HttpUtil.getHttpFileName(url);//1.1 分块的文件名httpFileName = httpFileName + ".temp" + part;//1.2 下载的路径httpFileName = Constant.DOWNLOAD_PATH + httpFileName;//2. 获取分块下载的连接对象HttpURLConnection httpURLConnection = HttpUtil.getHttpURLConnection(url, startPos, endPos);try (InputStream inputStream = httpURLConnection.getInputStream();BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); //获取下载文件的大小RandomAccessFile randomAccessFile = new RandomAccessFile(httpFileName,"rw"); ){//3. 进行分块读取信息int len = -1;byte[] bytes = new byte[Constant.BYTE_SIZE];while ((len=bufferedInputStream.read(bytes))!=-1){  //当前循环在 1s 内进行统计多次数据//3.1 在一秒内,使用原子性类型进行统计DownLoadInfoThread.downSize.add(len);randomAccessFile.write(bytes,0,len);}}catch (FileNotFoundException e){log.error("下载的文件不存在:{}",url);return false;}catch (Exception e){log.error("文件下载失败!");return false;}finally {//释放资源if(httpURLConnection!=null) {httpURLConnection.disconnect();}}return true;}
}

#文件按分块进行分别切分的方法

这里分别进行定义线程池的核心线程数量、总线程数量、非核心线程数量、空闲时单位回收的时间以及阻塞队列;

它们的关系一般为:

总线程数量 = 核心线程数量 + 非核心线程数量

工作线程首先进入 核心线程数量,若 核心线程数量 已满,则进入 非核心线程数量 ;同理,非核心线程数量 已满,最后将放入阻塞队列(同时,空闲的线程会在指定的时间内被回收)

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(Constant.THREAD_NUM,Constant.THREAD_NUM,0,TimeUnit.SECONDS,new ArrayBlockingQueue<>(Constant.THREAD_NUM));   //创建线程池

将需要下载的文件进行按条件分块处理,调用以上方法将当前对应的分块文件进行分别下载;并将分块后的块文件加入到 pool线程池 中进行管理,使用 Future 类型的集合进行保存

public void split(String url, ArrayList<Future> futures){try {//1.下载的文件大小long httpFileContentLength = HttpUtil.getHttpFileContentLength(url);//2.计算分块后的文件大小long fileSize = httpFileContentLength / Constant.THREAD_NUM;//3.计算分块的个数for (int i=0;i<Constant.THREAD_NUM;i++){//3.1每一次的文件的起始下载大小long startPos = fileSize * i;long endPos;//3.2 若是最后一部分,则下载剩余部分if(i == Constant.THREAD_NUM - 1){endPos = 0;}else {//3.3 若不是,则该分块最后一部分为起始部分加上分块后的文件大小endPos = startPos + fileSize;}//4.如果不是第一块,则起始位置加一,不然前一个部分的末位为后一部分的起始位,这显然不符合if(startPos != 0){startPos++;}//TODO 进行分块下载 /DownLoadTask downLoadTask = new DownLoadTask(url, startPos, endPos, i);//4.1将任务放到线程池中Future<Boolean> future = poolExecutor.submit(downLoadTask);futures.add(future);}} catch (IOException e) {throw new RuntimeException(e);}}

# 使用 LongAdder 类型,更改 DownLoadInfoThread 展现下载信息类

在展示下载信息类中,将原来的 double 类型更改为 LongAdder 原子性类型,即在执行期间不会被其他线程中断,从而保证了操作的完整性和线程安全性;该类型的主要作用有以下几点:

  1. 原子性操作:LongAdder 类是 Java 并发包中的一种实现,它专门用于在多线程环境下执行原子性的增减操作;与使用 double 类型属性并使用 synchronizedvolatile 等关键字来进行同步相比,LongAdder 可以更高效地执行并发增减操作

  2. 避免竞争:在多线程环境中,使用 double 类型属性时,多个线程可能同时访问和修改该属性,导致竞争和锁竞争;LongAdder 内部采用分段的方式来减小竞争,每个线程在不同的段上执行增减操作,最后将结果累加起来。这可以减少竞争,提高性能

  3. 减小锁粒度:使用 LongAdder 可以避免大范围锁的使用;在某些情况下,使用 synchronized 或其他锁机制可能需要锁住整个对象,而 LongAdder 可以将锁粒度减小,只锁住各自的段,从而减小锁的竞争和开销

  4. 高并发性LongAdder 是为高并发环境设计的,它可以更好地应对大量并发线程的增减操作需求;这使它在需要频繁增减操作的场景中表现更优秀

2.3 文件的合并以及临时文件的清除

#文件的合并

将之前分块文件按末尾顺序依次进行合并,需要注意的是,其合并的顺序要从 0 开始(这里0为第一位)

public boolean merge(String fireName){log.info("文件开始合并:{}",fireName);byte[] bytes = new byte[Constant.BYTE_SIZE];int len;try (RandomAccessFile randomAccessFile = new RandomAccessFile(fireName,"rw")){for (int i = 0;i<Constant.THREAD_NUM;i++){try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fireName + ".temp" + i))){while ((len = bis.read(bytes))!=-1){randomAccessFile.write(bytes,0,len);}}}log.info("文件合并完毕!");} catch (Exception e) {e.printStackTrace();return false;}return true;}

#临时文件的清除

当合并完成后,需要将之前被分块出来的临时文件清除,只保留最后的文件下载结果文件

public boolean clearTemp(String fireName){for (int i=0;i<Constant.THREAD_NUM;i++){File file = new File(fireName + ".temp" + i);file.delete();}log.info("残留文件已经删除成功!");return true;}

#在主下载类中调用上述方法

  

  完整代码:

 public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); //启动一个线程ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(Constant.THREAD_NUM,Constant.THREAD_NUM,0,TimeUnit.SECONDS,new ArrayBlockingQueue<>(Constant.THREAD_NUM));   //创建线程池public void my_DownLoad(String url) {//1.获取文件名String fileName = HttpUtil.getHttpFileName(url);//2.与下载目录地址进行拼接,获取当前文件目标下载路径String downLoadPath = Constant.DOWNLOAD_PATH + fileName;//获取本地磁盘中文件的下载大小long localFileLength = FileUtils.getFileContentLength(downLoadPath);//3.获取连接对象HttpURLConnection httpURLConnection = null;DownLoadInfoThread downLoadInfoThread = null;try {httpURLConnection = HttpUtil.getHttpURLConnection(url);//3.1 获取下载文件的总大小int contentLength = httpURLConnection.getContentLength();//3.2 获取下载文件的大小,进行比较,判断是否已经下载过if(localFileLength >= contentLength){log.info("{}  >>> 文件已经下载完成,无需再次下载!",fileName);return;}//TODO 这里进行展现下载信息内容的操作 /downLoadInfoThread = new DownLoadInfoThread((long)contentLength);//3.3 调用线程,每隔一秒执行一次scheduledExecutorService.scheduleAtFixedRate(downLoadInfoThread,1,1, TimeUnit.SECONDS);//TODO 进行文件分块下载的操作 //ArrayList<Future> futures = new ArrayList<>();split(url,futures);//3.4 这里使用 get() 进行阻塞,以保证文件下载分块下载成功futures.forEach(future -> {try {future.get();} catch (InterruptedException | ExecutionException e) {throw new RuntimeException(e);}});//3.5 进行分块文件的合并并清除临时文件的操作if(merge(downLoadPath)){clearTemp(downLoadPath);}} catch (IOException e) {e.printStackTrace();}finally {System.out.println("当前文件:<"+ fileName + "> ------【下载成功】,  下载目标地址:<" + downLoadPath + ">");//释放资源if(httpURLConnection!=null){httpURLConnection.disconnect();}scheduledExecutorService.shutdownNow();poolExecutor.shutdown();}//4.将文件读入内存中 【这里使用的是 try - with - resource 的形式】
//        try (
//                InputStream inputStream = httpURLConnection.getInputStream();
//
//                BufferedInputStream bis = new BufferedInputStream(inputStream);
//                FileOutputStream outputStream = new FileOutputStream(downLoadPath);
//                BufferedOutputStream bos = new BufferedOutputStream(outputStream)
//        ){
//            //4.1 从连接对象中获取下载信息资源,将其下载到目标路径
//            int len = -1;
//            byte[] bytes = new byte[Constant.BYTE_SIZE]; //防止 BufferedOutputStream 中的字节长度不够用
//            while ((len = bis.read(bytes))!=-1){
//                DownLoadInfoThread.downSize += len; //为展现信息线程类中的【本次已下载的文件大小属性】赋值
//                bos.write(bytes,0,len);
//            }
//
//        }catch (FileNotFoundException e){
//            log.error("下载的文件不存在{}",url);
//        } catch (Exception e) {
//            log.error("下载文件失败");
//        }finally {
//
//            System.out.println("当前文件:<"+ fileName + "> ------【下载成功】,  下载目标地址:<" + downLoadPath + ">");
//
//            if(httpURLConnection!=null) {
//                //释放连接资源
//                httpURLConnection.disconnect();
//            }
//
//            //释放【展现下载信息的线程】资源
//            scheduledExecutorService.shutdownNow();
//        }}

另外,这里可以使用 CountDownLatch 类中的 await() 方法进行代替,以保证在执行最后的文件合并以及临时文件的清除时,之前的线程执行状态为结束状态(使用时记得最后关闭数据流)

运行结果:

  可见,文件合并成功且清除临时文件成功,收工

 

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

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

相关文章

计算机中丢失mfc140u.dll怎么解决

mfc140u.dll是一个Microsoft Visual C库文件&#xff0c;主要用于MFC&#xff08;Microsoft Foundation Class&#xff09;应用程序的开发。它包含了MFC应用程序所需的一些常用功能&#xff0c;如对话框、窗口、菜单等。当mfc140u.dll丢失时&#xff0c;可能会导致MFC应用程序无…

margin-bottom、margin-top设置不起效

问题&#xff1a; 如下&#xff0c;在uniapp项目中使用了tag标签&#xff0c;设置margin时&#xff0c;只有margin-left、margin-right生效&#xff0c;margin-bottom、margin-top设置不起效。f12直接在元素中修改也无效。 原因&#xff1a; uni-ui中的tag标签是行内元素&…

idea 模板参数注释 {@link}

1. 新增组 2. 设置方法注释及变量 增加模板文本 ** * $param$ * return {link $return$} */3. 设置变量表达式 勾选跳过param 参数表达式 groovyScript("def result ;def params \"${_1}\".replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).toList();def param…

Vscode禁止插件自动更新

由于电脑的vscode版本不是很新。2022.10月份的版本1.7.2&#xff0c;电脑vscode的python插件装的也是2022年4月份的某个版本&#xff0c;但插件经常自动更新&#xff0c;导致python代码无法Debug,解决办法&#xff1a; 点设置&#xff0c;搜autoUpdate, 把红色框选成无

Linux中固定ip端口和修改ip地址

一&#xff0c;更改虚拟网络编辑器 1&#xff0c;首先启动VMware&#xff0c;选择自己要更改ip或固定ip的虚拟机&#xff0c;并找到虚拟网络配编辑器&#xff0c;点击进入 2&#xff0c;进入之后需要点击右下角获取管理员权限后才能修改&#xff0c;有管理员权限之后图片如下 …

setpci设定PCIe寄存器

PCIe寄存器信息读取、分析、配置 1.获取bdf &#xff08;bus:device.function&#xff09;地址2.根据bdf地址抓取pci信息3.结合PCIe Spec对读到的信息进行分析使用setpci修改 1.获取bdf &#xff08;bus:device.function&#xff09;地址 在Linux系统下使用命令&#xff1a; l…

django+drf+vue 简单系统搭建 (2) - drf 应用

按照本系统设置目的&#xff0c;是为了建立一些工具用来处理简单的文件。 1. 准备djangorestframework 关于drf的说明请参见&#xff1a;Django REST Framework教程 | 大江狗的博客 本系列直接使用drf的序列化等其他功能。 安装 conda install djangorestframework conda i…

Redis系列之常见数据类型应用场景

文章目录 String简单介绍常见命令应用场景 Hash简单介绍常见命令应用场景 List简单介绍常见命令应用场景 Set简单介绍常见命令应用场景 Sorted Set(Zset)简单介绍常见命令应用场景 Bitmap简单介绍常见命令应用场景 附录 Redis支持多种数据类型&#xff0c;比如String、hash、li…

【达梦数据库】mysql与达梦整数类型对比关系

最近遇了mysql 和达梦整数类型的数据范围对比&#xff0c;做了个表格供大家分享 对比表格 要说明的是我整理的时候&#xff0c;达梦貌似没有无符号整数类型&#xff08;防杠保护&#xff09;&#xff0c;也就是只能将mysql/dm 的有符号整数类型的的范围值进行对比 MYSQL - t…

高性能网络编程 - select、 poll 、epoll 、libevent

文章目录 概述优缺点SelectPollEpollLibEvent 概述 Select&#xff08;选择&#xff09;&#xff1a; Select 是一种传统的 I/O 多路复用机制&#xff0c;用于在类 Unix 操作系统&#xff08;如 Linux&#xff09;中同时管理多个文件描述符&#xff08;如网络套接字或文件&…

Java2 - 数据结构

5 数据类型 5.1 整数类型 在Java中&#xff0c;数据类型用于定义变量或表达式可以存储的数据的类型。Java的数据类型可分为两大类&#xff1a;基本数据类型和引用数据类型。 byte&#xff0c;字节 【1字节】表示范围&#xff1a;-128 ~ 127 即&#xff1a;-2^7 ~ 2^7 -1 sho…

Rust学习日记(二)变量的使用--结合--温度换算/斐波那契数列--实例

前言&#xff1a; 这是一个系列的学习笔记&#xff0c;会将笔者学习Rust语言的心得记录。 当然&#xff0c;这并非是流水账似的记录&#xff0c;而是结合实际程序项目的记录&#xff0c;如果你也对Rust感兴趣&#xff0c;那么我们可以一起交流探讨&#xff0c;使用Rust来构建程…

Camera Raw 16 v16.0.0

Camera Raw 16是一款允许摄影师处理原始图像文件的软件PS增效工具。原始图像文件是未经相机内部软件处理的数码照片&#xff0c;因此包含相机传感器捕获的所有信息。Camera Raw 为摄影师提供了一种在将原始文件转换为更广泛兼容的格式&#xff08;如 JPEG 或 TIFF&#xff09;之…

基于React使用swiperjs实现竖向滚动自动轮播

很多文章&#xff0c;都只提供了js部分&#xff0c;包括官方的文档也只有js部分&#xff0c;如果css设置不正确&#xff0c;会导致轮播图不自动播放。 使用的swiper版本&#xff1a;v11.0.3 文档 https://swiperjs.com/get-startedhttps://swiperjs.com/react 实现效果 使…

AD教程 (十)Value值的核对

AD教程 &#xff08;十&#xff09;Value值的核对 填写器件位号 直接根据原理图的原始编号进行更改 通过位号编辑器快速更改 点击工具&#xff0c;选择标注&#xff0c;选择原理图标注&#xff0c;进入位号编辑器 可以在位号编辑器中 设置处理顺序&#xff0c;从上往下还是从…

layui form 中input输入框长度的统一设置

Layui.form中使用class"layui-input-inline"就可轻松将元素都放到一行&#xff0c;但如果元素过多&#xff0c;就会自动换行。那就需要手动设置input框的长度。 像这种情况&#xff1a; 其实只需要添加css样式就可修改了 .layui-form-item .layui-input-inline {wid…

奔驰E Coupe 升级鼠标按键 操作简单 完美结合

人机交互系统正是汽车智能化发展的产物&#xff0c;它实现了人与车之间的互联。不知道大家有没有发现&#xff0c;在很多奔驰车的中央扶手箱前&#xff0c;有一块类似于“鼠标”的操作区&#xff0c;它并不是我们常见的换挡杆&#xff0c;而是奔驰研发的独立影音控制系统COMAND…

【Dockerfile镜像实战】构建LNMP环境并运行Wordpress网站平台

【Dockerfile镜像实战】构建LNMP环境并运行Wordpress网站平台 Nginx部署MySQL部署PHP部署 Nginx部署 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0[rootlocalhost ~]# docker pull centos:7[rootlocalhost ~]# docker imagescd /opt mkdir n…

从行车记录仪恢复已删除/丢失视频的方法

“我的车里有行车记录仪。几天前&#xff0c;当我下班回家时&#xff0c;一辆卡车不知从哪里冒出来撞向了我。我们的两辆车都损坏了&#xff0c;但幸运的是&#xff0c;没有人受伤。我曾与卡车司机就修理我的汽车进行过会面&#xff0c;但他说我有错。我需要查看我的行车记录仪…

怎么学编程效率高,编程练习网站编程软件下载,中文编程开发语言工具下载

怎么学编程效率高&#xff0c;编程练习网站编程软件下载&#xff0c;中文编程开发语言工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的…