java中的流以及文件常用操作

1 流相关概念

            字节流:
                   (1) 输入流

                           以Stream结尾的,以字节数组byte[]的形式来读

                           常见:文件字节输入流 FileInputStream 、BufferedInputStream

                   (2) 输出流

                            以Stream结尾的,以字节数组byte[]的形式来写

                            常见:文件字节输出流 FileOutputStream、BufferedOutputstream

            字符流
                    (1) 输入流

                            以Reader结尾的,以字符形式来读

                            常见:文件字符输入流  FileReader、BufferedReader

                    (2) 输出流

                            以Writer结尾的,以字符的形式来写

                            常见:文件字符输出流  FileWriter、BufferedWriter

           总结:
                   字节流使用的是ASCII码,处理的是二进制,由字节byte[]组成,字符流处理的是字符也就是String,本质上是byte[]和String。字节输入流的超类是InputStream,字节输出流的超类是OutputStream,字符输入流的超类是Reader,字符输出流的超类是Writer。

2 读取数据库/目的数据 组装成文件

(1)指定生成文件名称 路径
(2)创建输出流(字符输出流、指定输出的编码如:GBK)
(3)将数据写入到文件里

3 浏览器下载服务器上已有的文件模版

(1) 在服务器指定的路径放上对应的excel文件,使用文件工具类进行浏览器下载

文件工具类

package com.sinog.core.util;

import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @desc 文件工具类
 * @author ypc
 * @date 2025/3/9 15:50
 */
@Slf4j
public class FileUtils {

    private static final String MSIE_STR = "MSIE";
    private static final String TRIDENT_STR = "Trident";

    /**
     * 整合版文件下载
     * @param request request
     * @param resp resp
     * @param filePath filePath
     * @param filename filename
     */
    public static void downloadFile(HttpServletRequest request,HttpServletResponse resp,String filePath,String filename) throws java.io.UnsupportedEncodingException {
        //获取浏览器
        String userAgent = request.getHeader("User-Agent");
        if(!userAgent.contains("Windows")){
            PrintWriter writer = null;
            resp.setContentType("text/html; charset=utf-8");
            try {
                writer = resp.getWriter();
                writer.println("<script type=\"text/javascript\">alert('目前仅支持Windows安装包下载,其他客户端操作系统请自行下载或联系管理员');window.history.back(-1);</script>");
                writer.flush();
            } catch(IOException e) {
                log.error("发生异常",e);
            } finally {
                Objects.requireNonNull(writer).close();
            }
        }
        if(userAgent.contains(MSIE_STR) || userAgent.contains(TRIDENT_STR)) {
            //IE浏览器处理
            filename = URLEncoder.encode(filename,"UTF-8");
        } else {
            // 非IE浏览器的处理
            filename = new String(filename.getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1);
        }
        File file = new File(filePath);
        //判断文件父目录是否存在
        if(file.exists()) {
            resp.setContentType("application/force-download");
            resp.setHeader("Content-Disposition","attachment;filename=" + filename);
            resp.setContentLength((int)file.length());
            byte[] buffer = new byte[1024];
            //文件输入流
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            OutputStream os = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                os = resp.getOutputStream();
                int len;
                while(-1 != (len = bis.read(buffer))) {
                    os.write(buffer,0,len);
                }
                resp.flushBuffer();
            } catch(IOException e) {
                PrintWriter writer = null;
                resp.setContentType("text/html; charset=utf-8");
                try {
                    writer = resp.getWriter();
                    writer.println("<script type=\"text/javascript\">alert('文件下载失败,请稍后重试');window.history.back(-1);</script>");
                    writer.flush();
                } catch(IOException e1) {
                    log.error("发生异常",e1);
                } finally {
                    Objects.requireNonNull(writer).close();
                }
                log.error("发生异常",e);
            } finally {
                try {
                    if(null != bis) {
                        bis.close();
                    }
                } catch(IOException e) {
                    log.error("发生异常",e);
                }
                try {
                    if(null != os) {
                        os.close();
                    }
                } catch(IOException e) {
                    log.error("发生异常",e);
                }
                try {
                    if(null != fis) {
                        fis.close();
                    }
                } catch(IOException e) {
                    log.error("发生异常",e);
                }
            }
        } else {
            PrintWriter writer = null;
            resp.setContentType("text/html; charset=utf-8");
            try {
                writer = resp.getWriter();
                writer.println("<script type=\"text/javascript\">alert('文件不存在,请联系管理员');window.history.back(-1);</script>");
                writer.flush();
            } catch(IOException e) {
                log.error("发生异常",e);
            } finally {
                Objects.requireNonNull(writer).close();
            }
        }
    }
}

(2)使用poi现组装一个excel文件,然后立马用浏览器进行下载

1 使用poi生成workbook,然后将workbook输出到file中
package com.sinog.core.util;

import org.apache.poi.ss.usermodel.Workbook;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class PoiWriteExcel {

    /**
     * @return
     * @author ypc
     * @Description 将poi生成的workbook(工作簿)写成file文件
     */
    public static File createFile(String filePath, String fileName, Workbook workbook) {
        FileOutputStream fileOutputStream = null;
        File exportFile = null;
        //File.separator‌是Java中File类的一个静态字段,用于表示当前操作系统下的文件分隔符。
        // 在不同操作系统中,文件分隔符可能不同,例如在Windows系统中使用反斜杠 \\ 作为文件分隔符,而在Unix/Linux系统中使用斜杠 / 作为文件分隔符。
        // 使用File.separator可以确保代码在不同操作系统上都能正确使用相应的文件分隔符,从而提高代码的可移植性‌
        String exportFilePath = filePath + File.separator + fileName;
        //文件路径白名单检查是一种安全措施,用于确保应用程序只允许访问或操作特定的文件或目录。这种机制通常用于防止未授权的访问或潜在的安全漏洞,
        // 例如路径遍历攻击(Path Traversal Attack),它允许攻击者访问系统上不应该被访问的文件。
        try {
            SecurityWhiteList.checkPath(exportFilePath);
            exportFile= new File(exportFilePath);
            if (!exportFile.getParentFile().exists()) {
                // 父目录不存在,创建父目录
                exportFile.getParentFile().mkdirs();
            }
            //尝试在当前路径下创建一个新的空文件。如果文件不存在,则创建文件并返回true;如果文件已经存在,则不创建新文件并返回false
            exportFile.createNewFile();
            fileOutputStream = new FileOutputStream(exportFilePath);
            workbook.write(fileOutputStream);
            //在使用FileOutputStream时,通常的做法是在数据写入完成后调用flush()方法,以确保所有缓冲的数据都被处理,
            // 然后再调用close()方法关闭流。这样可以最大程度地保证数据的完整性和一致性‌。不调用flush()就直接调用close(),可能会导致部分数据丢失
            fileOutputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != fileOutputStream) {
                try {
                    fileOutputStream.close();
                }catch (IOException e) {
                    System.out.println(e.toString());
                }
            }
            if (null != workbook) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return exportFile;
    }
}
2 通过上面的FileUtils中的downloadFile方法将生成file输出到浏览器下载
3 输入流 上传文件 转为工作簿
InputStream inputStream = file.getInputStream();
try(Workbook workbook = WorkbookFactory.create(inputStream)) {
	// 对工作簿的操作
}

(3)导出功能 将页面查询的数据全部导出(不在服务器生成文件形式)

 /**
     * POI导出 -- 生成excel 下载
     * @param response
     */
    @Override
    public void exportExcel(HttpServletResponse response) {
        //定义excel的表头
        String[] titles = {"指令名称","优先级","指令类型","指令描述"};
        //创建工作簿 workbook - excel  -- 因为POI没有定义
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
        //在工作簿中创建Sheet -- 也可以给这个sheet起名字
        HSSFSheet hssfSheet = hssfWorkbook.createSheet();
        //在当前hssfSheet中创建Row 行 -- 来放置表头
        HSSFRow hssfRow = hssfSheet.createRow(0);
        //在第一行中进行表头数据的设置
        for (int i = 0; i < titles.length; i++) {
            //根据列来放表头
            hssfRow.createCell(i).setCellValue(titles[i]);
        }
        //放数据 -- 查询所有数据
        List<DispOrd> dispOrdList = this.list();
        //循环数据 -- null写到前面
        if (null != dispOrdList) {
            for (int i = 0; i < dispOrdList.size(); i++) {
                //取出每一行的数据
                DispOrd dispOrd = dispOrdList.get(i);
                //从第二行开始放入数据 -- 只能一列一列的进行放置 -- 提前和用户商量好excel的顺序
                HSSFRow row = hssfSheet.createRow(i+1);
                row.createCell(0).setCellValue(dispOrd.getOrderName());
                row.createCell(1).setCellValue(dispOrd.getPriority());
                row.createCell(2).setCellValue(dispOrd.getSpecType());
                row.createCell(3).setCellValue(dispOrd.getOrderDesc());
            }
        }
        //生成excel通过日期来命名
        String fileName = new String(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        //导出功能
        try {
            //设置东西
            response.setHeader("Content-disposition","attachment; filename=" + fileName + ".xls");
            ServletOutputStream outputStream = response.getOutputStream();
            //使用工作簿来写入东西
            hssfWorkbook.write(outputStream);
            //关闭流等 -- flush清空缓存区中的数据流 -- 因为读入数据完成不代表写入数据完成
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值