读取FTP中不同文件格式的文件流后导出到浏览器

news2024/9/27 6:49:36

序言

有一个新的需求,前端提供下载的入口,后端能将指定了全路径的各种文件格式的文件下载到浏览器。
对于压缩的zip文件格式需要解析后写入到txt文件格式的文件中,其他的写入原本的文件格式的文件中。

1、连接ftp

<!--   jsch-sftp连接     -->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.54</version>
        </dependency>
@Slf4j
public class SftpUtil {
	public static ChannelSftp login(String userName, String host, String port, String password) throws JSchException {
	
	   Session session;
	   Channel channel;
	   JSch jSch = new JSch();
	
	   try {
	       session = jSch.getSession(userName, host, Integer.parseInt(port));
	       session.setPassword(password);
	
	       // 配置链接的属性
	       Properties properties = new Properties();
	       properties.setProperty("StrictHostKeyChecking", "no");
	       session.setConfig(properties);
	
	       //设置超时时间:3分钟
	       session.setTimeout(180000);
	       // 进行sftp链接
	       session.connect();
	
	       // 获取通信通道
	       channel = session.openChannel("sftp");
	       channel.connect();
	       log.info("连接ftp成功,ftp信息为:userName:{}, host:{}, port:{}", userName, host, port);
	   } catch (JSchException e) {
	       log.error("连接ftp异常,异常信息:{}", e.getMessage());
	       return null;
	   }
	   return (ChannelSftp) channel;
	}
}

2、设置不同文件格式的格式名和导出的文件格式的枚举类

import lombok.Getter;

/**
 * @version 1.0
 * @date 2024年08月22日 11:55
 */
@Getter
public enum FileFormatEnum {
    XLSX(1001, "xlsx","xlsx"),
    XLS(1002, "xls","xls"),
    CSV(1003, "csv","csv"),
    ZIP(1004, "zip","txt"),
    TXT(1005, "txt","txt"),
    NO_FORMAT(1007, "",""),
    ;
    private final Integer code;
    private final String value;
    /**
     * 解压或解密后的文件格式
     **/
    private final String parseFormat;

    FileFormatEnum(Integer code, String value, String desc) {
        this.code = code;
        this.value = value;
        this.parseFormat = desc;
    }
}

3、读取各种类型的文件数据

3.1 通过监听器来读取大数据量的xls文件:

import com.google.common.collect.Lists;
import org.apache.poi.hssf.eventusermodel.*;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.usermodel.HSSFDataFormatter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class MyHSSFListener implements HSSFListener {
    public MyHSSFListener(Integer readRowNum) {
        this.readRowNum = readRowNum;
    }


    /**
     * 当前行
     */
    private final Integer readRowNum;

    /**
     * 是否输出formula,还是它对应的值
     */
    private final boolean outputFormulaValues = true;

    /**
     * 用于转换formulas
     */
    private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;

    //excel2003工作簿
    private HSSFWorkbook stubWorkbook;

    private SSTRecord sstRecord;

    private FormatTrackingHSSFListener formatListener;

    private final HSSFDataFormatter formatter = new HSSFDataFormatter();

    private BoundSheetRecord[] orderedBSRs;

    private final List<BoundSheetRecord> boundSheetRecords = new ArrayList<>();

    private boolean outputNextStringRecord;

    //存储一行记录所有单元格的容器
    private final List<String> cellList = Lists.newLinkedList();

    /**
     * 判断整行是否为空行的标记
     */
    private boolean flag = false;

    /**
     * 遍历excel下所有的sheet
     */
    public void process(InputStream inputStream) throws Exception {
        POIFSFileSystem fs = new POIFSFileSystem(inputStream);
        MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
        formatListener = new FormatTrackingHSSFListener(listener);
        HSSFEventFactory factory = new HSSFEventFactory();
        HSSFRequest request = new HSSFRequest();
        if (outputFormulaValues) {
            request.addListenerForAllRecords(formatListener);
        } else {
            workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
            request.addListenerForAllRecords(workbookBuildingListener);
        }
        factory.processWorkbookEvents(request, fs);
    }

    /**
     * HSSFListener 监听方法,处理Record
     * 处理每个单元格
     * @param record 文件内容
     */
    @Override
    public void processRecord(Record record) {
        int thisColumn;
        String thisStr = null;
        String value;
        //当前行
        switch (record.getSid()) {
            case BoundSheetRecord.sid:
                boundSheetRecords.add((BoundSheetRecord) record);
                break;
            case BOFRecord.sid: //开始处理每个sheet
                BOFRecord br = (BOFRecord) record;
                if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
                    //如果有需要,则建立子工作簿
                    if (workbookBuildingListener != null && stubWorkbook == null) {
                        stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
                    }
                    if (orderedBSRs == null) {
                        orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
                    }
                }
                break;
            case SSTRecord.sid:
                sstRecord = (SSTRecord) record;
                break;
            case BlankRecord.sid: //单元格为空白
                BlankRecord brec = (BlankRecord) record;
                thisColumn = brec.getColumn();
                cellList.add(thisColumn, "");
                break;
            case BoolErrRecord.sid: //单元格为布尔类型
                BoolErrRecord berec = (BoolErrRecord) record;
                thisColumn = berec.getColumn();
                thisStr = berec.getBooleanValue() + "";
                cellList.add(thisColumn, thisStr);
                checkRowIsNull(thisStr);  //如果里面某个单元格含有值,则标识该行不为空行
                break;
            case FormulaRecord.sid://单元格为公式类型
                FormulaRecord frec = (FormulaRecord) record;
                thisColumn = frec.getColumn();
                if (outputFormulaValues) {
                    if (Double.isNaN(frec.getValue())) {
                        outputNextStringRecord = true;
                    } else {
                        thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
                    }
                } else {
                    thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';
                }
                cellList.add(thisColumn, thisStr);
                checkRowIsNull(thisStr);  //如果里面某个单元格含有值,则标识该行不为空行
                break;
            case StringRecord.sid: //单元格中公式的字符串
                if (outputNextStringRecord) {
                    outputNextStringRecord = false;
                }
                break;
            case LabelRecord.sid:
                LabelRecord lrec = (LabelRecord) record;
                thisColumn = lrec.getColumn();
                value = lrec.getValue().trim();
                value = value.equals("") ? "" : value;
                cellList.add(thisColumn, value);
                checkRowIsNull(value);  //如果里面某个单元格含有值,则标识该行不为空行
                break;
            case LabelSSTRecord.sid: //单元格为字符串类型
                LabelSSTRecord lsrec = (LabelSSTRecord) record;
                thisColumn = lsrec.getColumn();
                if (sstRecord == null) {
                    cellList.add(thisColumn, "");
                } else {
                    value = sstRecord.getString(lsrec.getSSTIndex()).toString().trim();
                    value = value.equals("") ? "" : value;
                    cellList.add(thisColumn, value);
                    checkRowIsNull(value);  //如果里面某个单元格含有值,则标识该行不为空行
                }
                break;
            case NumberRecord.sid: //单元格为数字类型
                NumberRecord numrec = (NumberRecord) record;
                thisColumn = numrec.getColumn();
                //参照formatNumberDateCell里面的实现方法编写
                double valueDouble = numrec.getValue();
                String formatString = formatListener.getFormatString(numrec);
                if (formatString.contains("m/d/yy")){
                    formatString="yyyy-MM-dd hh:mm:ss";
                }
                int formatIndex = formatListener.getFormatIndex(numrec);
                value = formatter.formatRawCellContents(valueDouble, formatIndex, formatString).trim();
                value = value.equals("") ? "" : value;
                //向容器加入列值
                cellList.add(thisColumn, value);
                checkRowIsNull(value);  //如果里面某个单元格含有值,则标识该行不为空行
                break;
            default:
                break;
        }

        //空值的操作
        if (record instanceof MissingCellDummyRecord) {
            MissingCellDummyRecord mc = (MissingCellDummyRecord) record;
            thisColumn = mc.getColumn();
            cellList.add(thisColumn, "");
        }
        //行结束时的操作
        if (record instanceof LastCellOfRowDummyRecord) {
            int rowNum = ((LastCellOfRowDummyRecord) record).getRow();
            //有些地方只需要读取前10行,根据MyHSSFListener构造中传过来的readRowNum来判断是否继续把读到的数据放到集合中
            if (rowNum >= 0 && Objects.nonNull(readRowNum) && rowNum >= readRowNum) {
                return;
            }
            if (flag) {
                ExcelForXlsRowListUtil.sendRows(cellList);
            }
            //清空容器
            cellList.clear();
            flag = false;
        }
    }

    /**
     * 如果里面某个单元格含有值,则标识该行不为空行
     * @param value 数据值
     */
    public void checkRowIsNull(String value){
        if (value != null && !"".equals(value)) {
            flag = true;
        }
    }
}

3.2 将监听类读取到的每行数据放到新的集合中:

public class ExcelForXlsRowListUtil {
    public static List<List<String>> rowList = new ArrayList<>();

    public static void sendRows(List<String> cellList) {
        rowList.add(new ArrayList<>(cellList));
    }
    public static List<List<String>> getRowList() {
        return rowList;
    }
}

3.3 读取xlsx,xls以及csv文件格式的工具类:

@Slf4j
public class ExcelReadUtil {
    /**
     * <p>
     * 	通过输入流创建workbook,单独调用记得关闭流(上面通过try()的方式会自动关闭流,因为他们实现了AutoCloseble)
     * </p>
     * @param inputStream excel文件流
     * @return Workbook对象
     */
    public static Workbook getWorkbookByInputStream(InputStream inputStream) {
        try {
            return StreamingReader.builder()
                    .rowCacheSize(5000)  //缓存到内存中的行数,默认是10
                    .bufferSize(4096)  //读取资源时,缓存到内存的字节大小,默认是1024
                    .open(inputStream);//打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件
        } catch (Exception e) {
            log.error("通过输入流创建workbook异常,异常信息为:{}", e.getMessage());
        }
        return null;
    }

    /**
     * 读取xlsx文件流的数据后并写入新的workbook中
     * @param inputStream 文件流
     * @date  2024/8/22 15:34
     * @return  Workbook
     **/
    public static Workbook getWorkbookForXlsx(InputStream inputStream) {
        Workbook workbook = getWorkbookByInputStream(inputStream);
        if (Objects.isNull(workbook)) {
            log.error("读取xlsx文件流为空");
            return null;
        }

        Workbook newWorkbook = null;
        try {
            newWorkbook = new XSSFWorkbook();
            Sheet newSheet = newWorkbook.createSheet("Sheet1");
            Sheet sheet = workbook.getSheetAt(0);
            int i = 0;
            for (Row row : sheet) {
                Row newRow = newSheet.createRow(i);
                int j = 0;
                for (Cell cell : row) {
                    CellType cellType = cell.getCellType();
                    String cellValue = getCellValue(cellType, cell);
                    Cell newCell = newRow.createCell(j);
                    newCell.setCellValue(cellValue);
                    j++;
                }
                i++;
            }
        } catch (Exception e) {
            log.error("读取xlsx文件异常,异常信息为:{}", e.getMessage());
        }
        return newWorkbook;
    }
    
    /**
     * 读取xls文件流的数据
     * @param inputStream 文件流
     * @date  2024/8/22 11:30
     * @return  Workbook
     **/
     public static Workbook getWorkbookForXls(InputStream inputStream) {
         MyHSSFListener excelXls = new MyHSSFListener(null);
         Workbook workbook;
         try {
             excelXls.process(inputStream);
             List<List<String>> rowList = ExcelForXlsRowListUtil.getRowList();
             workbook = new HSSFWorkbook();
             Sheet sheet = workbook.createSheet("Sheet1");
             for (int i = 0; i < rowList.size(); i++) {
                 Row row = sheet.createRow(i);
                 List<String> cellDataList = rowList.get(i);
                 for (int j = 0; j < cellDataList.size(); j++) {
                     Cell cell = row.createCell(j);
                     cell.setCellValue(cellDataList.get(j));
                 }
             }
         } catch (Exception e) {
             throw new ServiceException("读取xls文件异常,异常信息为:" + e.getMessage());
         }
         return workbook;
     }
     
      /**
      * 读取csv文件流的数据内容
      * @param inputStream 文件流
      * @date  2024/8/22 11:40
      * @return  String
      **/
    public static String getFileDataForCsv(InputStream inputStream) {
        StringBuilder data = new StringBuilder();
        String CSV_ROW_SEPARATOR = System.lineSeparator();
        try (CSVReader reader = new CSVReader(new InputStreamReader(inputStream,"GB2312"))) {
            String[] line;
            while ((line = reader.readNext()) != null) {
                String join = String.join(",", line);
                data.append(join).append(CSV_ROW_SEPARATOR);
            }
        } catch (IOException | CsvValidationException e) {
            throw new ServiceException("导出csv文件异常,异常信息为:" + e.getMessage());
        }
        return data.toString();
    }
  }
}

3.4 读取zip文件的数据内容(无需解压到本地)

@Slf4j
public class ZipReadUtil {
  /**
     * 读取未加密的zip文件流数据
     * @param inputStream 文件流
     * @date  2024/8/22 11:36
     * @return data
     **/
    public static String getFileDataForZIP(InputStream inputStream) {
        ZipInputStream zipInputStream = new ZipInputStream(inputStream, StandardCharsets.UTF_8);
        ZipEntry zipEntry;
        String data = "";
        try {
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (!zipEntry.isDirectory() && zipEntry.getName().toLowerCase().endsWith(".txt")) {
                    long size = zipEntry.getSize();
                    if (size == -1) {
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        while (true) {
                            int bytes = zipInputStream.read();
                            if (bytes == -1) {
                                break;
                            }
                            baos.write(bytes);
                            data = baos.toString();
                        }
                        baos.close();
                    }
                }
            }
        } catch (IOException e) {
            throw new ServiceException("获取zip文件异常,异常信息为:" + e.getMessage());
        }
        return data;
    }
}

3.5 读取txt和无后缀的文件格式的文件内容

@Slf4j
public class TXTAndNoSuffixReadUtil {
    /**
     * 读取txt文件或无后缀文件流的内容
     * @param inputStream 文件流
     * @date  2024/8/22 11:39
     * @return  String
     **/
    public static String getFileData(InputStream inputStream) {
        //无格式文件和txt的读取方式一样
        StringBuilder data = new StringBuilder();
        try (InputStreamReader reader = new InputStreamReader(inputStream)) {
            BufferedReader bufferedReader = new BufferedReader(reader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                data.append(line).append(System.lineSeparator());
            }
        } catch (IOException e) {
            throw new ServiceException("对无后缀文件时异常:" + e.getMessage());
        }
        return data.toString();
    }
}

4、文件导出到浏览器的工具类

import com.tr.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @version 1.0
 * @date 2024年08月22日 11:32
 */
@Slf4j
public class ExportFileUtil {
    /**
     * 导出excel文件到浏览器
     * @param response 响应
     * @param fileName 文件名
     * @param workbook  workbook
     * @date  2024/8/21 17:23
     **/
    public static void browserDownloadForExcel(HttpServletResponse response, String fileName, Workbook workbook) {
        if (Objects.isNull(workbook)) {
            throw new ServiceException("要导出的excel文件数据为空,文件名为:" + fileName);
        }

        try (OutputStream outputStream = response.getOutputStream()) {
            response.reset();
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(outputStream);
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }

    /**
     * 导出txt文件到浏览器
     * @param response 响应
     * @param fileName 文件名
     * @param text  文件内容
     * @date  2024/8/21 17:26
     **/
    public static void browserDownloadForTxt(HttpServletResponse response, String fileName, String text) {
        if (StringUtils.isBlank(text)) {
            throw new ServiceException("要导出的数据为空,文件名为:" + fileName);
        }
        try {
            response.setCharacterEncoding("utf-8");
            //设置响应的内容类型
            response.setContentType("text/plain");
            //设置名称格式,没有这个中文名称无法显示
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        BufferedOutputStream buff = null;
        ServletOutputStream outStr = null;
        try {
            outStr = response.getOutputStream();
            buff = new BufferedOutputStream(outStr);
            buff.write(text.getBytes(StandardCharsets.UTF_8));
            buff.flush();
            buff.close();
        } catch (Exception e) {
            throw new ServiceException("导出文件文件出错:" + e.getMessage());
        } finally {
            try {
                if (buff != null) {
                    buff.close();
                }
                if (outStr != null) {
                    outStr.close();
                }
            } catch (Exception e) {
               log.error("关闭流对象出错:" + e.getMessage());
            }
        }
    }
}

这里需要注意:由于有些文件是有中文名的,所以需要后端通过使用 URLEncoder 将汉字编码为 URL 兼容的格式。前端使用 decodeURIcomponent 将从后端接收到的编码字符串解码为原始汉字。
在这里插入图片描述

5、下载的service接口

/**
 * @version 1.0
 * @date 2024年08月21日 15:20
 */
public interface FileDownLoadService {
    void downloadFile(Long filesaveId, String filePath, HttpServletResponse response);
}

6、下载的service实现类

@Slf4j
@Service
@RequiredArgsConstructor
public class FileDownLoadServiceImpl implements FileDownLoadService {
    @Override
    public void downloadFile(FTPConfig ftpConfig,String filePath,String sourceFileFormat, HttpServletResponse response) {
 String fullFileName = filePath.substring(filePath.lastIndexOf("/") + 1);//获取文件名+文件格式
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf(".") + 1);//只要文件名,去掉文件后缀
 ChannelSftp channelSftp;
        //连接sftp,读取要写入数据库的文件全路径列表
        try {
            channelSftp = SftpUtil.login(ftpConfig.getFtpUser(), ftpConfig.getFtpHost(), ftpConfig.getFtpPort(),ftpConfig.getFtpPassword());
        } catch (JSchException e) {
            throw new ServiceException("连接ftp异常,异常信息为:" + e.getMessage());
        }
		 InputStream inputStream = null;
		  try {
		        inputStream = channelSftp.get(filePath);
		        if (Objects.equals(FileFormatEnum.XLSX.getValue(), sourceFileFormat)) {
	                   Workbook workbook = ExcelReadUtil.getWorkbookForXlsx(inputStream);
	                   ExportFileUtil.browserDownloadForExcel(response, fullFileName, workbook);
	                   try {
	                       if (workbook != null) {
	                           workbook.close();
	                       }
	                   } catch (IOException e) {
	                       log.error("关闭流异常,异常信息为:{}", e.getMessage());
	                   }
	             } else if (Objects.equals(FileFormatEnum.XLS.getValue(), sourceFileFormat)) {
	                   Workbook workbook = ExcelReadUtil.getWorkbookForXls(inputStream);
	                   ExportFileUtil.browserDownloadForExcel(response, fullFileName, workbook);
	                   try {
	                       workbook.close();
	                   } catch (IOException e) {
	                       log.error("关闭流异常,异常信息为:{}", e.getMessage());
	                   }
	             } else if (Objects.equals(FileFormatEnum.ZIP.getValue(), sourceFileFormat)) {
	                   String data = ZipReadUtil.getFileDataForNoSecret(inputStream);
	                   ExportFileUtil.browserDownloadForTxt(response, fileName + FileFormatEnum.ZIP.getParseFormat(), data);
	             } else if (Objects.equals(FileFormatEnum.NO_FORMAT.getValue(), sourceFileFormat)
	                       || Objects.equals(FileFormatEnum.TXT.getValue(), sourceFileFormat)) {
	                   String data = TXTAndNoSuffixReadUtil.getFileData(inputStream);
	                   ExportFileUtil.browserDownloadForTxt(response, fullFileName, data);
	             } else if (Objects.equals(FileFormatEnum.CSV.getValue(), sourceFileFormat)) {
	                   String data = ExcelReadUtil.getFileDataForCsv(inputStream);
	                   ExportFileUtil.browserDownloadForTxt(response, fullFileName, data);
	             }   
		  } catch (SftpException e) {
		            throw new ServiceException("ftp获取文件异常,异常信息为:" + e.getMessage());
	      } finally {
	            if (Objects.nonNull(inputStream)) {
	                try {
	                    inputStream.close();
	                } catch (IOException e) {
	                    log.error("关闭文件流失败, 异常信息为: {}", e.getMessage());
	                }
	            }
	            if (sftp != null) {
		            if (sftp.isConnected()) {
		                sftp.disconnect();  //若sftp正在连接,则断开
		            }
	            }
	      }   
 }       

7、下载的controller

import com.tr.common.exception.ServiceException;
import com.tr.itom.service.FileDownLoadService;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.util.Objects;

/**
 * @author FanHuiFang
 * @version 1.0
 * @date 2024年08月21日 15:19
 */
@Tag(name = "文件下载", description = "文件下载")
@RequiredArgsConstructor
@RestController
@RequestMapping("/file")
public class FileDownLoadController {
    private final FileDownLoadService fileDownLoadService;

    @ApiOperation("文件下载")
    @PostMapping(value = "/download")
    public void downloadFile(@NotNull Long filesaveId, @NotNull String filePath, HttpServletResponse response) {
        if (Objects.isNull(filesaveId) || StringUtils.isBlank(filePath)) {
            throw new ServiceException("规则id或文件路径不允许为空!");
        }
        fileDownLoadService.downloadFile(filesaveId, filePath, response);
    }
}

-----------------------你知道的越多,不知道的越多--------------------------

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

构建第一个zk

1 必要步骤 视频学习&#xff1a;5. Circcom 中的基本算术电路_哔哩哔哩_bilibili 文字学习&#xff1a;https://hackmd.io/YlNLZS2ESI21OSqdTW_mPw/S1jqN-h80/edit 第五课&#xff0c;circom实践&#xff0c;需要安装 1 vscode 2 rust&#xff1a;Windows安装Rust环境&…

【C++】模拟(例题 学习)

引言 模拟就是用计算机来模拟题目中要求的操作。 模拟题目通常具有码量大、操作多、思路繁复的特点。由于它代码量大&#xff0c;经常会出现难以查错的情况&#xff0c;如果在考试中写错是相当浪费时间的。 注&#xff1a;模拟没有基础思路和模板&#xff0c;所以要多刷题锻…

vscode中文设置(一招解决)

打开vscode 点击这个Estentions图标 搜索Chinese,直接安装,重启就生效了

Jmeter提取token并设置为全局变量

参考文章&#xff1a;Jmeter提取token并设置为全局变量&#xff08;最详细的步骤&#xff09;_jmeter提取token到全局变量-CSDN博客 一般来说&#xff0c;系统内大多数接口&#xff0c;都需要先获取登录后的token值&#xff0c;所以我们需要创建一个获取token的接口&#xff0c…

es相关概念、索引操作(相当于mysql中的数据库操作)

文章目录 1、概念2、索引操作&#xff08;index&#xff09;2.1、查询索引&#xff08;数据库&#xff09;2.2、创建索引&#xff08;数据库&#xff09;2.3、查看单个索引&#xff08;数据库&#xff09;2.4、删除索引&#xff08;数据库&#xff09; 1、概念 RDBMSesMongoDB…

87.游戏改造-UI修正全面分析

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;86.游戏改造-UI修正暴力分析 首先来到下图位置 一个函数上来就 ECX4 这种不用想直接就看…

羚羊软件:处理sql server 2008 R2 Error 9003

在很多情况下,服务器突然断电或其他原因会造成&#xff0c;数据库附加时出现&#xff1a;错误代码为90003的错误。 解决办法&#xff1a; 1、新建一个同名得数据库&#xff08;Ly_Men_16_2005&#xff09;。 2、停止SQL服务。 3、用原来得主数据库文件&#xff0c;覆盖新建得…

使用在AMD GPU上运行的ROCm进行大语言模型的自然语言处理任务

Performing natural language processing tasks with LLMs on ROCm running on AMD GPUs — ROCm Blogs 在这篇博客中&#xff0c;您将学习如何使用在AMD的Instinct GPU上运行的ROCm进行一系列流行且有用的自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;使用不同的大…

CSS学习笔记(01)flex布局

1、首先对父元素设置disiplay&#xff1a;felx&#xff0c; 其有6个属性 fex-direction:设置主轴的方向 justify-content:设置主轴上的子元素排列方式 flex-wrap:设置子元素是否换行 align-content:设置侧轴上的子元素的排列方式(多行) align-items:设置侧轴上的子元素排列方式…

Debain 安装 MySql

一 Debian安装MySQL 5.7 1 更新安装列表 sudo apt update 2 添加MySql官方APT仓库到Debian wget https://dev.mysql.com/get/mysql-apt-config_0.8.22-1_all.deb sudo dpkg -i mysql-apt-config_0.8.22-1_all.deb先下载再安装源&#xff0c;如下图&#xff1a; 再次执行更新…

从零到一,2024年数据恢复软件新手到专家指南

在数字化的时代&#xff0c;相信你的数据大部分也都是存在一些电子设备里吧。很多时候因为一些意外情况会导致我们数据的丢失&#xff0c;这个时候有什么办法能恢复我们的数据资料呢&#xff1f;这次我们就来一起探讨一些大家都在用的数据恢复工具吧。 1.福昕数据恢复 链接直…

热点 | 爆款游戏的诞生与游戏出海的持续增长

近日&#xff0c;《黑神话&#xff1a;悟空》一经上线就在国内获得了空前的关注。国产大IP3A国际水准带来的超炫视觉体验专业发行与市场营销等&#xff0c;共同引爆了这个现象级的话题。同时&#xff0c;我们也关注到&#xff0c;这款游戏同时在海外多个发行平台进行全球发售。…

Redis 源码安装

目录 1 Redis 的获取 2 Redis 部署 2.1 下载并解压 2.2 Makerfile 文件 2.3 安装所需要编译所需要的包 2.4 开始源码编译 2.5 utils 下的 install_server.sh 脚本文件 2.5 运行脚本进行安装 3 systemd 管理 3.1 编写Redis systemd 服务脚本 3.2 重新加载 systemd 系统 3.3 …

Apache CloudStack Official Document 翻译节选(九)

关于 Apache CloudStack 的 最佳实践 &#xff08;三&#xff09; 配置云外的 防火墙与交换机 对Cisco VNMC&#xff08;Cisco Virtual Network Management Center&#xff09;设备集成云外的客户机网路防火墙&#xff1a; 思科虚拟网络管理中心为思科网络虚拟服务提供了中心…

考试:计算机网络(01)

网络功能和分类 计算机网络是计算机技术与通信技术相结合的产物&#xff0c;它实现了远程通信、远程信息处理和资源共享。 计算机网络的功能&#xff1a;数据通信、资源共享、管理集中化、实现分布式处理、负载均衡。 网络性能指标&#xff1a;速率、带宽(频带宽度或传送线路…

我的新书《Android系统多媒体进阶实战》正式发售

我的新书要正式发售了&#xff0c;把链接贴在下面&#xff0c;感兴趣的朋友可以支持下。 ❶发售平台&#xff1a;当当&#xff0c;京东&#xff0c;抖音北航社平台&#xff0c;小红书&#xff0c;b站 ❷目前当当和京东已开启预售 ❸当当网 https://u.dangdang.com/KIDHJ ❹…

机器人语音聊天绕坑

为了给机器人添加语音&#xff0c;网上淘了一块离线语音芯片&#xff0c;用过之后就有些后悔了。离线语音定制性比较差&#xff0c;有150句限制&#xff0c;而且与大模型接驳需要一块额外的esp8266或者esp32。如果使用了esp32&#xff0c;事实上可以自己制作离线语音&#xff0…

【多线程】深入剖析线程安全问题

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;多线程 / javaEE初阶 前言 线程安全问题是在多线程学习中一个十分重要的话题。多个线程并发执行就容易产生许多冲突与问题&#xff0c;如何协调好每个线程的执行&#xff0c;让多线程编程“多而不乱…

图神经网络实战(19)——异构图神经网络

图神经网络实战&#xff08;19&#xff09;——异构图神经网络 0. 前言1. 异构图1.1 异构图基本概念1.2 构建异构图数据集 2. 将同构图神经网络转换为异构图神经网络2.1 数据集介绍2.2 同构图注意力网络2.3 异构图神经网络 小结系列链接 0. 前言 我们已经学习了如何生成包含不…

4、Unity【基础】画线功能Linerenderer、物理系统Physics

文章目录 画线功能Linerenderer1、LineRenderer是什么2、LineRender参数相关3、LineRender代码相关思考1 请写一个方法&#xff0c;传入一个中心点&#xff0c;传入一个半径&#xff0c;用LineRender画个圆出来思考2 在Game窗口长按鼠标用LineRender画出鼠标移动的轨迹 核心系统…