Linux 机器安装nodejs 、puppeteer及踩坑(页面抓取转pdf)

安装一些必备命令

yum -y install wget unzip

node安装

  • 1.获取nodejs

    wget -c https://nodejs.org/dist/v10.16.3/node-v10.16.3-linux-x64.tar.xz
    
  • 2.解压

    tar -xvf node-v10.16.3-linux-x64.tar.xz
    
  • 3.移动文件夹 将文件夹移动到用户目录下,并重命名为node(通常该步骤是便于应用程序使用)

    mv node-v10.16.3-linux-x64 ~/node
    
  • 4.建立软连接

    sudo ln -s ~/node/bin/node /usr/local/bin/node
    sudo ln -s ~/node/bin/npm /usr/local/bin/npm
    
  • 5.添加环境变量 和上步略有重复,不过建议加上

    sudo vi /etc/profile; 
    //特别提醒:如果前文移动目录自定义,这里也要同步修改
    export NODE_HOME=~/node/bin
    export PATH=$NODE_HOME:$PATH
     
    
  • 6.自测

    node -v
    //打印版本号说明安装成功
    

puppeteer安装

node对于路径很看重,因此把模块安装在哪个目录下很关键,否则你的js文件可能因为缺少模块而不能运行

如果完成上述node安装,你的node所在路径应该是/node,之后的包安装都在/node下进行

  • 1.安装

    //确保进入node文件夹下
    cd ~/node 
    //安装puppeteer,不下载chrome
    npm install puppeteer --ignore-scripts --save
    
  • 2.获取chrome

    • 查看所需chrome版本号:版本号可以在node_modules/puppeteer/package.jsonpuppeteer.chromium_revision获得,现在是818858,根据puppeteer需要自行替换,后续用%d代替(必须,否则puppeteer特性可能不支持)|版本中也许不存在版本信息,先下载上,自测中会提示需要的版本
    wget -c 'https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/818858/chrome-linux.zip'
    

已经下载好 链接:https://pan.baidu.com/s/1c0pKDeqCmt0UIFAf6TncDA
提取码:gs26

  • 3.将chrome放在指定目录下

    cd node_modules/puppeteer/ 
    // .不能少
    mkdir .local-chromium
    cd .local-chromium
    // 818858:%d 根据自己的替换
    mkdir linux-818858
    cd linux-818858
    // 如果上述按照步骤来走,移动文件夹,否则,自行替换路径
    mv ~/node/chrome-linux.zip ~/node/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux.zip
    //解压
    unzip chrome-linux.zip
    
  • 4.安装依赖(不可忽略)

    #依赖库
    sudo yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 nss.x86_64 -y
     
    #字体
    sudo yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
    
  • 5.自测

    cd ~/node
    // 建立文件,此后要跑的js建议都放在这里
    vim test.js
    
    • test.js内容如下

      const puppeteer = require('puppeteer');
      (async () => {
        const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
        const page = await browser.newPage();
        await page.goto('https://www.baidu.com');
        await page.screenshot({path: 'author3q.png'});
        await browser.close();
      })();
      
  • 在该目录下运行:

    node test.js
    //如果目录下有author3q.png,说明一切就绪
    
  • FAQ

    • 手动下载Chrome并解决puppeteer无法使用问题

      https://www.jb51.net/article/150592.htm

      http://jartto.wang/2018/10/13/nodejs-pdf/

    • puppeteer使用截图功能出现乱码

      • 1.安装fontconfig

        yum -y install fontconfig
        //这个命令执行完成之后,就可以在/usr/share文件夹里面看到fonts和fontconfig
        
      • 2.添加中文字体库

        //从window的C:\Windows\Fonts里面把你需要的字体拷贝出来。比如simfang.ttf
        //在CentOS的/usr/share/fonts新建一个叫chinese的文件夹
        //然后把刚刚拷贝字体放到CentOS的/usr/share/fonts/chinese里面
        //修改chinese目录的权限:
         
        mkdir /usr/share/fonts/chinese
        chmod -R 775 /usr/share/fonts/chinese
        
      • 3.接下来需要安装ttmkfdir来搜索目录中所有的字体信息,并汇总生成fonts.scale文件,输入命令

        yum -y install ttmkfdir
        ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir
        
      • 4.修改字体配置文件

        vi /etc/fonts/fonts.conf
        
        <!-- Font directory list -->
         
         <dir>/usr/share/fonts</dir>
         <dir>/usr/share/X11/fonts/Type1</dir>
         <dir>/usr/share/X11/fonts/TTF</dir>
         <dir>/usr/local/share/fonts</dir>
         添加这行
         <dir>/usr/local/share/fonts/chinese</dir>
         
         <dir prefix="xdg">fonts</dir>
         <!-- the following element will be removed in the future -->
         <dir>~/.fonts</dir>
        
      • 5.刷新内存中的字体缓存

        fc-cache
        //看一下现在机器上已经有了刚才添加的字体
        fc-list :lang=zh
        
  • 最终运行文件

    node 1.js path fileName dir

    const puppeteer = require('puppeteer');
    var arguments = process.argv.splice(2);
    console.log('所传递的参数是:', arguments);
    const path = arguments[0] || "";
    const fileName = arguments[1] || "";
    const dir = arguments[2] || "/root/pdf/";
    if (path == "" ) {
      console.log('请传入path:', path);
      return;
    }
    if (fileName == "") {
       console.log('请传入fileName:', fileName);
       return;
    }
     console.log('上传文件目录:', dir);
    (async () => {
      const browser = await puppeteer.launch({
          args: [
            '--no-sandbox',
            '--disable-setuid-sandbox',
            '--disable-dev-shm-usage', 
            '--disable-accelerated-2d-canvas',
            '--disable-gpu'
          ],
          timeout: 50000  //设置超时时间
      });
      const page = await browser.newPage();
      // const url = 'http://10.11.15.1:16868/#/CIAManage/report/detail/'+reportId+'/'+uid;
      const url = path;
      // 防止cpu居高不下,一定要使用try catch 关闭page
      try {
          await page.goto(url, {
              timeout: 30 * 1000,     //超时时间
              waitUntil: 'networkidle0' //无request请求时触发
          });
          console.log('全路径为:', url);
          await page.addStyleTag({
            content: "#cover {display:none}"
          });
          await page.pdf({path: dir + fileName + '.pdf',
              printBackground: true,
              width: '740.725',
              height: '1052.3625',
              '-webkit-print-color-adjust': 'exact',
          });
          await browser.close();
          console.log('导出成功');
    } catch (error) {
        console.log('[REPORTPDF_ERROR_LOG] reportId is [' + reportId + '], error: ', error.message)
        await browser.close();//关闭
      } finally {
        console.log('[REPORTPDF_FINALLY_LOG] reportId is [' + reportId + '] 结束');
      }
    })().catch(error => console.log('[REPORTPDF_ERROR_LOG] reportId is [' + reportId + '], error: ', error.message));
    
    
    
    

    java操作篇

  • yml配置

    scp:
      ip: 192.168.100.128
      port: 22
      username: root
      password: 123456
      url: http://10.11.15.1:16868/#/CIAManage/report/detail
      dir: /root/pdf/
    
  • 控制器

    package com.faner.fast.controller.test;
    
    import com.faner.fast.upms.pojo.bo.FileBO;
    import com.faner.fast.upms.service.FileService;
    import com.faner.fast.util.FileUtil;
    import com.faner.fast.util.ScpClientUtil;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.http.MediaType;
    import org.springframework.mock.web.MockMultipartFile;
    import org.springframework.util.LinkedMultiValueMap;
    import org.springframework.util.MultiValueMap;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * description: execController
     * date: 2020/12/2 15:42
     * author: faner
     */
    @Slf4j
    @Validated
    @RestController
    @RequestMapping("/exec")
    @RequiredArgsConstructor
    @Api(value = "exec", tags = "exec")
    public class execController {
    
        private final FileService fileService;
    
        @Value("${scp.ip:127.0.0.1}")
        private String ip;
        @Value("${scp.port:22}")
        private int port;
        @Value("${scp.username:root}")
        private String username;
        @Value("${scp.password:123456}")
        private String password;
        @Value("${scp.url}")
        private String url;
        @Value("${scp.dir:/root/pdf/}")
        private String dir;
        /**
         * 登录远端服务器
         * @return 当前的连接
         * @throws IOException
         */
        @ApiOperation("shell执行")
        @RequestMapping(value = "/pdf",method= {RequestMethod.POST})
        public void  shell() throws IOException {
            String reportId = "37ca8617a73945d7ae8ddad7eddd854e";
            Integer uid = 204;
            String fileName = UUID.randomUUID().toString().replace("-", "");
            File dire = new File(dir);
            if(!dire.exists()){
                dire.mkdirs();
            }
            ScpClientUtil scpClientUtil = ScpClientUtil.getInstance(ip, port, username, password);
            String script = "node /root/node/test3.js "+ url +"/"+reportId+"/"+uid+ " " +fileName + " " + dir;
            ScpClientUtil.ShellResult exec = scpClientUtil.exec(script, StandardCharsets.UTF_8);
            log.info(">>>>>>Result>>>>>>>");
            log.info(exec.getResult());
            log.info(">>>>>>ErrorMsg>>>>>>>>");
            log.info(exec.getErrorMsg());
            String name =dir+fileName+".pdf";
            //校验文件是否存在
    
            boolean exists = FileUtil.exists(name);
            if (exists){
                MultiValueMap<String, MultipartFile> o1 = new LinkedMultiValueMap<String, MultipartFile>();
                //上传oss
                MultipartFile file = new MockMultipartFile(name,name, MediaType.MULTIPART_FORM_DATA_VALUE, FileUtil.getByte(new File(name)));
                o1.add("file",file);
                List<FileBO> upload = fileService.upload(o1);
                //删除文件
                FileUtil.deleteFile(name);
                //发送邮件发送链接删除后操作即可 发送文件需要在删除前操作 比较耗费服务器资源 建议发送链接
            }
        }
    }
    
    
  • linux操作工具类

    <!-- shell       -->
            <dependency>
                <groupId>ch.ethz.ganymed</groupId>
                <artifactId>ganymed-ssh2</artifactId>
                <version>build210</version>
            </dependency>
    
package com.faner.fast.util;

import ch.ethz.ssh2.*;
import com.faner.fast.exception.FailedException;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 远程执行linux命令
 * description: ExecUtil
 * date: 2020/12/2 16:44
 * author: faner
 */
@Slf4j
public class ScpClientUtil {
    /** 超时时间 */
    private static final int TIME_OUT = 1000 * 5 * 60;

    static private Map<String,ScpClientUtil> instance = Maps.newHashMap();

    static synchronized public ScpClientUtil getInstance(String ip, int port, String username, String password) {
        if (instance.get(ip) == null) {
            instance.put(ip, new ScpClientUtil(ip, port, username, password));
        }
        return instance.get(ip);
    }

    public ScpClientUtil(String ip, int port, String username, String password) {
        this.ip = ip;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    /**
     * 执行一个命令
     * @param scripts  需要执行的脚本
     * @param charset  字符编码
     * @return ShellResult类
     * @throws Exception
     */
    public ShellResult exec( String scripts, Charset charset) throws IOException {

        Connection conn = new Connection(ip, port);

        try {
            conn.connect();
            // Open a new {@link Session} on this connection
            boolean isAuthenticated = conn.authenticateWithPassword(username, password);
            if (!isAuthenticated) {
                log.error("authentication failed");
                throw new FailedException("authentication failed");
            }
            Session session = conn.openSession();
            InputStream stdOut = new StreamGobbler(session.getStdout()); InputStream stdErr = new StreamGobbler(session.getStderr());
            session.execCommand(scripts);
            String outStr = processStream(stdOut, charset.name());
            String outErr = processStream(stdErr, charset.name());
            session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
            int exitStatus = session.getExitStatus();
            return new ShellResult(outStr, outErr, exitStatus);
        }finally{
            conn.close();
        }
    }

    /**
     * 执行脚本
     * @param in      输入流
     * @param charset 字符编码
     * @return
     * @throws IOException
     */
    private static String processStream(InputStream in, String charset) throws IOException {
        byte[] buf = new byte[1024];
        StringBuilder sb = new StringBuilder();
        while (in.read(buf) != -1) {
            sb.append(new String(buf, charset));
        }
        return sb.toString();
    }

    public void getFile(String remoteFile, String localTargetDirectory) {
        Connection conn = new Connection(ip, port);
        try {
            conn.connect();
            boolean isAuthenticated = conn.authenticateWithPassword(username, password);
            if (!isAuthenticated) {
                System.err.println("authentication failed");
            }
            SCPClient client = new SCPClient(conn);
            client.get(remoteFile, localTargetDirectory);
        } catch (IOException ex) {
            Logger.getLogger(SCPClient.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            conn.close();
        }
    }

    public void putFile(String localFile, String remoteTargetDirectory) {
        putFile(localFile, null, remoteTargetDirectory);
    }

    public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory) {
        putFile(localFile, remoteFileName, remoteTargetDirectory,null);
    }

    public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory, String mode) {
        Connection conn = new Connection(ip, port);
        try {
            conn.connect();
            boolean isAuthenticated = conn.authenticateWithPassword(username, password);
            if (!isAuthenticated) {
                System.err.println("authentication failed");
            }
            SCPClient client = new SCPClient(conn);
            if ((mode == null) || (mode.length() == 0)) {
                mode = "0600";
            }
            if (remoteFileName == null) {
                client.put(localFile, remoteTargetDirectory);
            } else {
                client.put(localFile, remoteFileName, remoteTargetDirectory, mode);
            }
        } catch (IOException ex) {
            Logger.getLogger(ScpClientUtil.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            conn.close();
        }
    }

    private String ip;
    private int port;
    private String username;
    private String password;


    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public  class ShellResult  {

        /** 脚本输出结果 */
        private String result;
        /** 异常输出结果 */
        private String errorMsg;
        /** 回话退出状态 */
        private int exitStatus;

        /** 是否成功关闭会话 */
        public boolean getSuccess() {
            return this.exitStatus == 0;
        }
    }
}

  • 文件工具类

    <!-- io       -->
    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
    </dependency>
    
package com.faner.fast.util;

import cn.hutool.core.util.IdUtil;
import com.faner.fast.exception.FileTooLargeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * description: FileUtil
 * date: 2020/11/26 15:19
 * author: faner
 */
@Slf4j
public class FileUtil {

    /**
     * 系统临时目录
     * <br>
     * windows 包含路径分割符,但Linux 不包含,
     * 在windows \\==\ 前提下,
     * 为安全起见 同意拼装 路径分割符,
     * <pre>
     *       java.io.tmpdir
     *       windows : C:\Users/xxx\AppData\Local\Temp\
     *       linux: /temp
     * </pre>
     */
    public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
    /**
     * 定义GB的计算常量
     */
    private static final int GB = 1024 * 1024 * 1024;
    /**
     * 定义MB的计算常量
     */
    private static final int MB = 1024 * 1024;
    /**
     * 定义KB的计算常量
     */
    private static final int KB = 1024;

    /**
     * 格式化小数
     */
    private static final DecimalFormat DF = new DecimalFormat("0.00");

    public static final String IMAGE = "图片";
    public static final String TXT = "文档";
    public static final String MUSIC = "音乐";
    public static final String VIDEO = "视频";
    public static final String OTHER = "其他";

    private static List<String> filePathList = new ArrayList<String>();
    /**
     * MultipartFile转File
     */
    public static File toFile(MultipartFile multipartFile) {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = "." + getExtensionName(fileName);
        File file = null;
        try {
            // 用uuid作为文件名,防止生成的临时文件重复
            file = File.createTempFile(IdUtil.simpleUUID(), prefix);
            // MultipartFile to File
            multipartFile.transferTo(file);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return file;
    }

    /**
     * 获取文件扩展名,不带 .
     */
    public static String getExtensionName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }

    /**
     * Java文件操作 获取不带扩展名的文件名
     */
    public static String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    /**
     * 文件大小转换
     */
    public static String getSize(long size) {
        String resultSize;
        if (size / GB >= 1) {
            //如果当前Byte的值大于等于1GB
            resultSize = DF.format(size / (float) GB) + "GB   ";
        } else if (size / MB >= 1) {
            //如果当前Byte的值大于等于1MB
            resultSize = DF.format(size / (float) MB) + "MB   ";
        } else if (size / KB >= 1) {
            //如果当前Byte的值大于等于1KB
            resultSize = DF.format(size / (float) KB) + "KB   ";
        } else {
            resultSize = size + "B   ";
        }
        return resultSize;
    }

    /**
     * inputStream 转 File
     */
    static File inputStreamToFile(InputStream ins, String name) throws Exception {
        File file = new File(SYS_TEM_DIR + name);
        if (file.exists()) {
            return file;
        }
        OutputStream os = new FileOutputStream(file);
        int bytesRead;
        int len = 8192;
        byte[] buffer = new byte[len];
        while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
        return file;
    }

    /**
     * 将文件名解析成文件的上传路径
     */
    public static File upload(MultipartFile file, String filePath) {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
        String name = getFileNameNoEx(file.getOriginalFilename());
        String suffix = getExtensionName(file.getOriginalFilename());
        String nowStr = "-" + format.format(date);
        try {
            String fileName = name + nowStr + "." + suffix;
            String path = filePath + fileName;
            // getCanonicalFile 可解析正确各种路径
            File dest = new File(path).getCanonicalFile();
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
                if (!dest.getParentFile().mkdirs()) {
                    System.out.println("was not successful.");
                }
            }
            // 文件写入
            file.transferTo(dest);
            return dest;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static String getFileType(String type) {
        String documents = "txt doc pdf ppt pps xlsx xls docx";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(type)) {
            return IMAGE;
        } else if (documents.contains(type)) {
            return TXT;
        } else if (music.contains(type)) {
            return MUSIC;
        } else if (video.contains(type)) {
            return VIDEO;
        } else {
            return OTHER;
        }
    }

    public static void checkSize(long maxSize, long size) {
        // 1M
        int len = 1024 * 1024;
        if (size > (maxSize * len)) {
            throw new FileTooLargeException("文件超出规定大小");
        }
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(File file1, File file2) {
        String img1Md5 = getMd5(file1);
        String img2Md5 = getMd5(file2);
        return img1Md5.equals(img2Md5);
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(String file1Md5, String file2Md5) {
        return file1Md5.equals(file2Md5);
    }

    /**
     * 将文件转换成byte数组
     * @param file
     * @return byte[]
     */
    public static byte[] getByte(File file) {
        // 得到文件长度
        byte[] b = new byte[(int) file.length()];
        try {
            InputStream in = new FileInputStream(file);
            try {
                System.out.println(in.read(b));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        return b;
    }

    /**
     * 获取文件md5值
     */
    public static String getMd5(File file) {
        return getMd5(getByte(file));
    }

    public static String getMd5(byte[] bytes) {
        // 16进制字符
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(bytes);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char[] str = new char[j * 2];
            int k = 0;
            // 移位 输出字符串
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 判断文件是否存在
     * @param filePath
     * @return
     */
    public static boolean exists(String filePath) {
        boolean exists = false;
        File file = new File(filePath);
        if (file.exists()) {
            exists = true;
        }
        return exists;
    }
    /**
     * 删除指定文件夹
     *
     * @param filePath
     */
    public static void deleteDirectory(String filePath) {
        FileUtils.deleteQuietly(new File(filePath));
    }

    /**
     * 删除指定文件
     * @param filePath
     */
    public static void deleteFile(String filePath) {
        try {
            FileUtils.forceDelete(new File(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查找指定路径下指定后缀的所有文件(非递归查找)
     *
     * @param filePath      文件目录
     * @param extensionName 文件扩展名
     */
    public static List<String> getFileUnderFolder(String filePath, String extensionName) {
        List<String> filPathList = new ArrayList<String>();
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        for (File f : fileList) {
            if (f.isFile() && f.getName().endsWith(extensionName)) {
                filPathList.add(f.getAbsolutePath());
            }
        }
        return filPathList;
    }

    /**
     * 查找指定路径下指定后缀的所有文件(递归查找)
     *
     * @param filePath      文件目录
     * @param extensionName 文件扩展名
     */
    public static List<String> getFileUnderFolderCursively(String filePath, String extensionName) {
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        for (File f : fileList) {
            if (f.isFile() && f.getName().endsWith(extensionName)) {
                filePathList.add(f.getAbsolutePath());
            } else if (f.isDirectory()) {
                getFileUnderFolderCursively(f.getAbsolutePath(), extensionName);
            }
        }
        return filePathList;
    }

    /**
     * 递归复制指定路径下指定后缀的所有文件到指定目录
     *
     * @param filePath
     * @param extensionName
     */
    public static void copyFilesUnderFolderCursively(String filePath, String extensionName, String dstPath) {
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        for (File f : fileList) {
            if (f.isFile() && f.getName().endsWith(extensionName)) {
                try {
                    FileUtils.copyFileToDirectory(f, new File(dstPath));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else if (f.isDirectory()) {
                copyFilesUnderFolderCursively(f.getAbsolutePath(), extensionName, dstPath);
            }
        }
    }

    /**
     * 读取文件内容
     * @param filePath
     * @param charsetName 编码格式
     * @return
     */
    public static String readFileContent(String filePath, String charsetName) {
        String content = "";
        File file = new File(filePath);
        if (file.exists()) {
            Long fileLength = file.length();
            byte[] fileContent = new byte[fileLength.intValue()];
            try {
                FileInputStream in = new FileInputStream(file);
                in.read(fileContent);
                in.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                content = new String(fileContent, charsetName);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return content;
    }

    /**
     * 读取文件内容
     */
    public static ArrayList<String> readFileContentByLine(String filePath, String charsetName) {
        ArrayList<String> list = new ArrayList<String>();
        String str = "";
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null; // 用于包装InputStreamReader,提高处理性能,因为BufferedReader有缓冲,InputStreamReader则没有

        try {
            fis = new FileInputStream(filePath); // FileInputStream
            // 从文件系统中的某个文件中获取字节
            isr = new InputStreamReader(fis, charsetName);// InputStreamReader是字节流通往字符流的桥梁
            br = new BufferedReader(isr);// 从字符输入流中读取文件中的内容,封装了一个new
            while ((str = br.readLine()) != null) {
                list.add(str);
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到指定文件");
        } catch (IOException e) {
            System.out.println("读取文件失败");
        } finally {
            try {
                br.close();
                isr.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }


    /**
     * 下载文件
     *
     * @param request  /
     * @param response /
     * @param file     /
     */
    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
        response.setCharacterEncoding(request.getCharacterEncoding());
        response.setContentType("application/octet-stream");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                    if (deleteOnExit) {
                        file.deleteOnExit();
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }


}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容