天天看點

Java IO與檔案讀寫

目錄

      • 一、從控制台輸入
      • 二、 擷取目前代碼運作的工作目錄路徑
      • 三、判斷檔案、檔案夾是否存在以及建立
      • 四、判斷檔案夾下有多少個檔案和檔案夾
      • 五、周遊擷取檔案夾下所有檔案的路徑和名稱
      • 六、擷取檔案名
      • 七、擷取檔案大小
      • 八、常用的檔案資訊的擷取和處理方法
      • 九、位元組流與字元流的差別
      • 十、使用位元組流讀寫檔案
      • 十一、使用字元流讀寫檔案
      • 十二、輸入流轉化為byte數組
      • 十三、java8使用Files.readAllBytes()或Files.readAllLines優雅讀文本檔案
      • 十四、java8優雅寫檔案
      • 十五、使用位元組流複制檔案
      • 十六、java8使用Files.copy()複制檔案
      • 十七、使用IOUtils優雅操作流(字元串與InputStream的轉化)
      • 十八、 對象的序列化與反序列化
      • 十九、使用sftp進行伺服器檔案上傳下載下傳
      • 二十、圖檔大小轉換
      • 二十一、将圖檔BufferedImage轉換為MultipartFile
      • 二十二、檔案壓縮
      • 二十三、InputStream、FileInputStream 轉 byte[ ]
      • 二十四、文本檔案的InputStream、FileInputStream 轉 String
      • 二十五、MultipartFile或byte[]轉InputStream
      • 二十六、檔案轉byte[]

一、從控制台輸入

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = null;
while ((inputStr = br.readLine())!=null) {
   System.out.println(inputStr);
}
           

或使用Scanner:

Scanner scanner = new Scanner(System.in);
String inputStr = null;
while ((inputStr = scanner.next()) != null) {
   System.out.println(inputStr);
}

/* Scanner scanner = new Scanner(System.in);
    String inputStr = null;  //輸入字元串
    if (scanner.hasNextLine()) {
      String str2 = scanner.nextLine();
      System.out.println(str2);
    }
    scanner.close();*/
           

next()和nextLine()差別:

  • 1、nextLine()以Enter為結束符,也就是說 nextLine()方法傳回的是輸入回車之前的所有字元。
  • 2、nextLine()可以獲得空格。

判斷輸入的是整數還是小數:

Scanner scan = new Scanner(System.in);
    // 從鍵盤接收資料
    int i = 0;
    float f = 0.0f;
    System.out.print("輸入數字:");

    if (scan.hasNextInt()) {// 判斷輸入的是否是整數
      i = scan.nextInt();
      System.out.println("整數資料:" + i);
    }

    if (scan.hasNextFloat()) {// 判斷輸入的是否是小數
      f = scan.nextFloat();
      System.out.println("小數資料:" + f);
    }
    scan.close();
           

二、 擷取目前代碼運作的工作目錄路徑

三、判斷檔案、檔案夾是否存在以及建立

  • 判斷檔案是否存在,不存在則建立
String filePth= "F:/cc/test2.txt";
File file = new File(filePth);
if(!file.exists()){
    System.out.println("檔案不存在");
    //建立檔案,如果cc檔案夾不存在會報錯,所有要先檢查檔案前的檔案夾路徑是否存在,不存在要先建立檔案夾,最後再建立檔案
    file.createNewFile();
}else {
    System.out.println("檔案存在");
}
           
  • 判斷檔案夾是否存在,不存在則建立
String filePth= "F:/test/aa/bb";//判斷bb檔案夾是否存在
File folder = new File(filePth);
if (!folder.exists() && !folder.isDirectory()) {
   folder.mkdirs();   //如果test下連aa檔案夾也沒有,會連同aa一起建立
   System.out.println("建立檔案夾");
} else {
   System.out.println("檔案夾已存在");
}
           

四、判斷檔案夾下有多少個檔案和檔案夾

String path = "D:\\video\\";
int fileCount = 0;
int folderCount = 0;
File d = new File(path);
File list[] = d.listFiles();
for(int i = 0; i < list.length; i++){
    if(list[i].isFile()){
        fileCount++;
    }else{
        folderCount++;
   }
}
System.out.println("檔案個數:"+fileCount);
System.out.println("檔案夾數:"+folderCount);
           

五、周遊擷取檔案夾下所有檔案的路徑和名稱

擷取絕對路徑的檔案名(擷取的list裡隻有檔案,沒有檔案夾):

public static List<String> getFilesList(String path){
       List<String> list = new ArrayList<>();
       File file = new File(path);
       File[] tempList = file.listFiles();
       for (int i = 0; i < tempList.length; i++) {
           if (tempList[i].isFile()) {
               list.add(tempList[i].toString());
           }
       }
    return  list;
}
           

測試:

String path = "D:\\video\\";
System.out.println(getFilesList(path)); //[D:\video\1.mp4, D:\video\2.mp4, D:\video\建立文本文檔.txt]
           

擷取相對路徑的檔案名(檔案和檔案夾都有):

File path = new File("D:\\ffmpegMedia\\");

		//擷取D:\ffmpegMedia\路徑下的檔案名和檔案夾名
        String fileNamePath[] = path.list();
        for (String f : fileNamePath) {
            System.out.println(f);
        }

        System.out.println("------------------------------------");

	    //擷取D:\ffmpegMedia\路徑下的檔案名和檔案夾名,傳回類型為file類型
        File[] files = path.listFiles();
        for (File f : files) {
            if (f.isFile()){
                System.out.println(f.getName() + " ---> 是一個檔案 " );
            }
            if (f.isDirectory()){
                System.out.println(f.getName() + " ---> 是一個檔案夾 " );
            }
        }
           

輸出:

507-#網愈雲故事收藏館.mp4
aaa.mp3
pictur
temp
刻在我心底的名字-五月天.mp3
------------------------------------
507-#網愈雲故事收藏館.mp4 ---> 是一個檔案 
aaa.mp3 ---> 是一個檔案 
pictur ---> 是一個檔案夾 
temp ---> 是一個檔案夾 
刻在我心底的名字-五月天.mp3 ---> 是一個檔案 
           

list()和listFiles()差別:

  • list()傳回的是檔案和檔案夾字元串數組
  • listFiles()傳回的是檔案和檔案夾File數組,可以進行更多操作,如擷取檔案名、判斷是否是檔案等

六、擷取檔案名

File file = new File("F:/cc/test2.txt");
System.out.println(file.getName());//輸出test2.txt
           

擷取上傳時的檔案名:

String fName = file.getOriginalFilename(); //file的類型是MultipartFile
/*String fileName = fName.substring(fName.lastIndexOf("/")+1);
//或者  
String fileName = fName.substring(fName.lastIndexOf("\\")+1);*/
           

七、擷取檔案大小

檔案夾不适用,隻能擷取檔案大小的整數位

public static void main(String[] args) throws IOException {
        File path = new File("D:\\ffmpegMedia\\");
        File[] files = path.listFiles();
        for (File f : files) {
            if (f.isFile()) {
                System.out.println(f.getName() + " ---> 是一個檔案 " + "檔案大小:" + fileSize(f.length()));
            }
            if (f.isDirectory()) {
                System.out.println(f.getName() + " ---> 是一個檔案夾 "+ "檔案大小:" + fileSize(f.length()));
            }
        }

    }

    /**
     * 檔案大小顯示格式
     *
     * @param size
     * @return
     */
    private static String fileSize(long size) {
        String[] units = new String[]{"B", "KB", "MB", "GB", "TB", "PB"};
        double mod = 1024.0;
        int i = 0;
        for (i = 0; size >= mod; i++) {
            size /= mod;
        }
        return Math.round(size) + units[i];
    }
           

八、常用的檔案資訊的擷取和處理方法

File file = new File("F:/test/test2.txt");
    System.out.println("檔案是否絕對路徑:" + file.isAbsolute());
    System.out.println("取得檔案的根目錄:" + file.getParent());
    System.out.println("檔案是否存在:" + file.exists());
    System.out.println("是否是目錄:" + file.isDirectory());
    System.out.println("是否是檔案:" + file.isFile());
    System.out.println("是否是隐藏檔案:" + file.isHidden());
    System.out.println("是否可讀:" + file.canRead());
    System.out.println("是否可寫:" + file.canWrite());
    System.out.println("删除檔案:" + file.delete());

	/*使用renameTo進行檔案重命名目錄路徑要一緻*/
    File oldName = new File("F:/test/test2.txt");//重命名前的檔案
    File newName = new File("F:/test/test3.txt");//重命名後的檔案
    System.out.println("檔案重命名:" + oldName.renameTo(newName));

    /*使用renameTo進行檔案移動,目錄路徑要不一緻,檔案名要一緻*/
    File oldName = new File("F:/test/hello.txt");
    File newName = new File("F:/tex/hello.txt");
    System.out.println("檔案移動:" + oldName.renameTo(newName));
           

輸出:

檔案是否絕對路徑:true
取得檔案的根目錄:F:\test
檔案是否存在:true
是否是目錄:false
是否是檔案:true
是否是隐藏檔案:false
是否可讀:true
是否可寫:true
删除檔案:true
    
檔案重命名:true
檔案移動:true
           

九、位元組流與字元流的差別

Java IO與檔案讀寫

位元組流:

1.位元組流在操作的時候不會用到緩沖區(也就是記憶體)

2.位元組流可用于任何類型的對象,包括二進制對象

3.位元組流處理單元為1個位元組,操作位元組和位元組數組。

InputStream是所有位元組輸入流的祖先,而OutputStream是所有位元組輸出流的祖先。

字元流:

1.而字元流在操作的時候會用到緩沖區

2.而字元流隻能處理字元或者字元串

3.字元流處理的單元為2個位元組的Unicode字元,操作字元、字元數組或字元串,

Reader是所有讀取字元串輸入流的祖先,而writer是所有輸出字元串的祖先。

在硬碟上的所有檔案都是以位元組形式存在的(圖檔,聲音,視訊),而字元值在記憶體中才會形成。

是以字元流是由Java虛拟機将位元組轉化為2個位元組的Unicode字元為機關的字元而成的。

用位元組流可以操作所有的檔案,因為位元組流在操作字元時,可能會有中文導緻的亂碼,是以由位元組流引申出了字元流。圖檔,聲音,視訊等檔案一般操作用位元組流,文本等檔案用字元流操作。

在從位元組流轉化為字元流時,實際上就是byte[]轉化為String;

而在字元流轉化為位元組流時,實際上是String轉化為byte[];

十、使用位元組流讀寫檔案

  • 讀檔案
    FileInputStream file = new FileInputStream("F:/test/te.txt"); //讀取檔案為位元組流
    BufferedInputStream buf = new BufferedInputStream(file); //加入緩存區
    int len = 0;
    byte[] bys = new byte[1024];
    while ((len = buf.read(bys)) != -1) {    //讀取逐個位元組資料到位元組數組,讀到末尾沒資料了傳回-1
        System.out.println(new String(bys, 0, len, "GBK")); //通過new String将位元組數組轉化為"GBK"編碼的字元串輸出
    }
    file.close(); //關閉流
    buf.close();
               
  • 寫檔案
    //true代表追加模式寫入,沒有參數true檔案的内容會以覆寫形式寫
    FileOutputStream outputStream = new FileOutputStream("F:/test/te.txt", true);
    BufferedOutputStream buf = new BufferedOutputStream(outputStream); 加入緩存區
    
    buf.write("hello".getBytes()); //hello轉化為位元組數組寫入檔案
    buf.write("\n".getBytes()); //換行
    buf.write(97); // 97代表字母a,将a寫入檔案
    buf.write("\n".getBytes()); //換行
    byte[] bys = {97, 98, 99, 100, 101};
    buf.write(bys, 1, 3);//将98, 99, 100代表的bcd寫入檔案
    
    buf.close();  //關閉流
    outputStream.close();
               

    檔案最終内容:hello

    a

    bcd

十一、使用字元流讀寫檔案

  • 讀檔案
    FileInputStream file = new FileInputStream("F:/test/te.txt"); //讀取檔案為位元組流
    InputStreamReader in = new InputStreamReader(file, "GBK"); //位元組流轉化為字元流,以GBK讀取防止中文亂碼
    BufferedReader buf = new BufferedReader(in); //加入到緩存區
    String str = "";
    while ((str = buf.readLine()) != null) { //按行讀取,到達最後一行傳回null
       System.out.println(str);
    }
    buf.close();
    file.close();
               
  • 寫檔案
    FileWriter f = new FileWriter("F:/test/te.txt", true); //檔案讀取為字元流,追加模式寫資料
     BufferedWriter buf = new BufferedWriter(f); //檔案加入緩沖區
    
     buf.write("hello"); //向緩沖區寫入hello
     buf.write("\n"); //向緩沖區寫入換行,或者采用buf.newLine();
     buf.write("def"); //向緩沖區寫入def
     buf.close(); //關閉緩沖區并将資訊寫入檔案
     f.close();
               

十二、輸入流轉化為byte數組

FileInputStream in = new FileInputStream("F:/test/te.txt");//輸入流
ByteArrayOutputStream bos=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=0;
while((len=in.read(buffer))!=-1){   //輸入流轉讀取到位元組數組輸出流
    bos.write(buffer,0,len);
}
in.close();
bos.flush();
byte[] result=bos.toByteArray(); //輸出流轉化成byte數組
           

十三、java8使用Files.readAllBytes()或Files.readAllLines優雅讀文本檔案

Files.readAllBytes():

byte[] data = Files.readAllBytes(Paths.get("F:/oracle_init.sql")); //擷取檔案轉化為位元組數組
String str= new String(data, StandardCharsets.UTF_8); //位元組數組轉化為UTF_8編碼的字元串
//String str= new String(data, "GBK"); //上一行代碼若有中文亂碼,可改用此行代碼
System.out.println(str); //輸出檔案内容
           

優化為一行代碼:

String content = new String(Files.readAllBytes(Paths.get("F:/oracle_init.sql")), StandardCharsets.UTF_8);
System.out.println(content); //輸出檔案内容
           

注意:Files.readAllBytes(Path)方法把整個檔案讀入記憶體,此方法傳回一個位元組數組。在針對大檔案的讀取的時候,可能會出現記憶體不 足,導緻堆溢出。是以大檔案不推薦此方法讀取。

Files.readAllLines:

List<String> lines = Files.readAllLines(Paths.get("F:/zzz.txt") , StandardCharsets.UTF_8);
lines.forEach(v-> System.out.println(v));
           

注意:不适用讀取大檔案

十四、java8優雅寫檔案

文本檔案:

//檔案不存在會自動建立,true表示在檔案末尾追加形式寫入,false則覆寫寫入
try(PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter("F:/ccc.txt", true)))) {
       writer.println("777");
       writer.println("888");
}catch (IOException e) {
      System.err.println(e);
}
           

二進制檔案(圖檔、音頻等):

byte data[] = ...
FileOutputStream out = new FileOutputStream("F:/ccc.mp3");
out.write(data);
out.close();
           

十五、使用位元組流複制檔案

不使用緩沖區(不推薦):

FileInputStream inputStream = new FileInputStream("F:/test/te.txt");    //待複制的檔案
 FileOutputStream outputStream = new FileOutputStream("F:/new/te1.txt"); //要複制到的路徑和檔案名

 byte[] bytes = new byte[1024];
 int len = 0;
 while ((len=inputStream.read(bytes)) != -1) { //讀取待複制的檔案到位元組數組bytes
    outputStream.write(bytes,0,len);           //位元組數組bytes的資料寫入要複制到的檔案
}
inputStream.close();
outputStream.close();
           

使用緩沖區(推薦):

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("F:/test/lv.mp4"));
 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F:/new/lv1.mp4"));

 int len = 0;
 byte[] bytes =new byte[1024];
 while ((len=bis.read(bytes)) != -1) {
    bos.write(bytes,0,len);
 }
 bis.close();
 bos.close();
           

經測試使用緩沖區的複制和下面的使用Files.copy()複制速度最快,比較推薦。

十六、java8使用Files.copy()複制檔案

Path source = Paths.get("F:/oracle_init.sql");   //源檔案路徑
File f = new File("F:/test/new.sql");  //拷貝後的檔案名和路徑
f.createNewFile();  //建立一個空的new.sql, 如果test目錄下已經存在new.sql原來的會被覆寫。
//複制檔案
Files.copy(source, new FileOutputStream(f));
           

十七、使用IOUtils優雅操作流(字元串與InputStream的轉化)

需要導入包org.apache.commons.io

1.從流中讀取資料

  • 檔案内容轉換成List<String>
    FileInputStream fileInputStream = new FileInputStream(new File("F:/test/oracle_init.sql"));
    //也可以用下面的FileOutputStream的構造方法擷取檔案,比較簡潔
    //FileOutputStream fileInputStream = new FileOutputStream("F:/test/oracle_init.sql");
    List<String> list = IOUtils.readLines(fileInputStream, "UTF-8");//隻要是InputStream流都可以,比如http響應的流
    for (String str : list){
          //list中每個元素是一行
    	System.out.println(str);
    }
               
  • 檔案内容轉換成String
    FileInputStream fileInputStream = new FileInputStream(new File("F:/test/oracle_init.sql"));
    String content = IOUtils.toString(fileInputStream,"UTF-8");
    System.out.println(content);
               
  • 把流轉換為byte數組
    FileInputStream fileInputStream = new FileInputStream(new File("F:/test/oracle_init.sql"));
    byte[] bytes = IOUtils.toByteArray(fileInputStream); //隻要是InputStream流都可以
               
  • byte數組轉化為String
    FileInputStream fileInputStream = new FileInputStream(new File("F:/test/oracle_init.sql"));
    byte[] bytes = IOUtils.toByteArray(fileInputStream);
    String str= new String(bytes, StandardCharsets.UTF_8);//若有中文亂碼StandardCharsets.UTF_8改為"GBK"
    System.out.println(str);
               
  • 把字元串轉換為InputStream
  • InputStream 轉換為 String

    參考:https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java?rq=1

2.把資料寫入流

//true為追加模式再檔案末尾寫内容把資料寫入輸出流 
FileOutputStream outputStream = new FileOutputStream("F:/test/te.txt", true);
IOUtils.write("abc", outputStream,"GBK");//将abc寫入檔案,編碼格式為GBK
outputStream.close();
           

3.檔案拷貝

FileInputStream in = new FileInputStream(new File("F:/new/lv.mp4"));
FileOutputStream out = new FileOutputStream("F:/test/lv1.mp4");
IOUtils.copy(in, out);
in.close();
out.close();
           

把oracle_init.sql檔案内容追加到te.txt末尾:

FileInputStream in = new FileInputStream(new File("F:/oracle_init.sql"));
FileOutputStream out = new FileOutputStream("F:/test/te.txt",true);
IOUtils.copy(in, out);
in.close();
out.close();
           

參考:Apache Commons IO之IOUtils優雅操作流

十八、 對象的序列化與反序列化

序列化對象就是把對象轉成位元組數組,便于傳輸或存儲。

反序列化對象就是将序列化後的位元組數組再恢複成對象。

序列化對象方法:

/*對象轉位元組數組*/
    public static byte[] serizlize(Object object){
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(baos != null){
                    baos.close();
                }
                if (oos != null) {
                    oos.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return null;
    }
           

序列化對象方法:

/*位元組數組轉對象*/
    public static Object deserialize(byte[] bytes){
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try{
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            try {
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return null;
    }
           

執行個體:

十九、使用sftp進行伺服器檔案上傳下載下傳

以下是經常用到的檔案上傳、下載下傳、判斷檔案路徑是否存在、建立檔案夾、

從本地上傳、從伺服器上傳到另一台伺服器的一些實用操作。

需要用到的需要jar包:jsch-0.1.54.jar

/**
     * 開啟連接配接
     * 
     * @param  ftpUserName使用者名
     * @param  ftpPassword伺服器密碼
     * @param   ftpHost  伺服器ip
     * @param   ftpPort伺服器端口
     * 
     */
    public static ChannelSftp connect(String ftpUserName, String ftpPassword, String ftpHost, int ftpPort) throws Exception {
        jsch = new JSch();// 建立JSch對象
        session = jsch.getSession(ftpUserName, ftpHost, ftpPort);// 根據使用者名、主機ip、端口号擷取一個Session對象
        session.setPassword(ftpPassword);// 設定密碼

        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);// 為Session對象設定properties
        session.setTimeout(1000 * 30);// 設定逾時
        session.connect();// 通過Session建立連接配接
        logger.info("Session connected.");
        channel = session.openChannel("sftp"); // 打開SFTP通道
        channel.connect(); // 建立SFTP通道的連接配接
        logger.info("Connected successfully to ftpHost = " + ftpHost + ",as ftpUserName = " + ftpUserName);
        return (ChannelSftp) channel;
    }

    /**
     * 關閉連接配接
     */
    public static void close() {
        if (channel != null) {
            channel.disconnect();
            logger.info("關閉channel成功");
        }
        if (session != null) {
            session.disconnect();
            logger.info("關閉session成功");
        }
    }


    /**
     * 判斷目錄是否存在
     * 
     @param directory檔案夾路徑,如:/root/test/saveFile/
     */
    public static boolean isDirExist(String directory, ChannelSftp sftp) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }


    /**
     * 建立一個檔案目錄
     * @throws SystemException
     * 
     * @param createpath要建立的檔案夾路徑,如:/root/test/saveFile/
     */
    public static void createDir(String createpath, ChannelSftp sftp) throws  SftpException {

            if (isDirExist(createpath,sftp)) {

            }else{
                String pathArry[] = createpath.split("/");

                for (String path : pathArry) {
                    if (path.equals("")) {
                        continue;
                    }
                    if (isDirExist(path,sftp)) {
                        try {
                            sftp.cd(path);
                        } catch (SftpException e) {
                            e.printStackTrace();
                        }
                        if (isDirExist(createpath, sftp)) {
                        }
                    } else {
                        // 建立目錄
                        sftp.mkdir(path);
                        // 進入并設定為目前目錄
                        sftp.cd(path);
                    }
                }
            }
    }



    /**
     * 删除檔案
     *
     * @param directory
     *            要删除檔案所在目錄
     * @param deleteFile
     *            要删除的檔案
     * @param sftp
     */
    public void delete(String directory, String deleteFile, ChannelSftp sftp) {
        try {
            sftp.cd(directory);
            sftp.rm(deleteFile);
        } catch (Exception e) {
            System.out.println("delete:"+e);
        }
    }
    



/**
     * 檔案上傳
     */
    public CodeNoteResponse uploadFile(MultipartFile file, String fileAddress) {
        String picName = "";
        // 将檔案上傳到臨時目錄
        String tmpLocation = System.getProperty("user.dir") + "/sftp_file";
        File tmpFile = new File(tmpLocation);
        if (!tmpFile.exists()) {
            tmpFile.mkdirs();
        }
        File dest = new File(tmpLocation + "/" + file.getOriginalFilename());

        ChannelSftp sftp = null;
        try {
            file.transferTo(dest);
            sftp = connect(ftpUserName, ftpPassword, ftpHost, Integer.valueOf(ftpPort));
            createPath(fileAddress, sftp);
            FileInputStream in = new FileInputStream(dest);
            picName = file.getOriginalFilename();
            sftp.put(in, fileAddress + "/" + picName);
        } catch (IOException e) {
            e.printStackTrace();
            return new CodeNoteResponse().fail(-1, e.getMessage());
        } catch (SftpException e) {
            e.printStackTrace();
            return new CodeNoteResponse().fail(-1, e.getMessage());
        } finally {
            close();
        }
        return new CodeNoteResponse<>().ok();
    }

/**
     * 傳回伺服器檔案内容
     */
    public String previewFile(String fileAddress,  String fileName) {
        ChannelSftp sftp = null;
        BufferedReader bufferedReader = null;
        JSONObject response = new JSONObject();
        String str="";
        try {
            sftp = connect(ftpUserName, ftpPassword, ftpHost, Integer.valueOf(ftpPort));
            sftp.cd(fileAddress);//進入指定目錄操作
            InputStream inputStream = null;
            inputStream = sftp.get(fileName);
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            String tempString = "";
            StringBuilder sb = new StringBuilder();//定義一個字元串緩存,将字元串存放緩存中
            while ((tempString = bufferedReader.readLine()) != null) {
                sb.append(tempString + "\n");//将讀取的字元串添加換行符後累加存放在緩存中
            }

             str = sb.toString();
            bufferedReader.close();//關閉流
        } catch (SftpException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }   finally {
            close();
        }
        return str;
    }
           

二十、圖檔大小轉換

  • 通過url 擷取圖檔流 BufferedImage 并轉換大小
    try {
               //通過url擷取BufferedImage圖像緩沖區
                URL img = new URL("https://img1.360buyimg.com/image/jfs/t1/38591/20/3737/314695/5cc69c01E1838df09/dd6dce681bd23031.jpg");
                BufferedImage image = ImageIO.read(img);
         		//擷取圖檔的寬、高
        	    System.out.println("Width: " + image.getWidth());
                System.out.println("Height: " + image.getHeight());
         		//調整圖檔大小為532x532尺寸
                BufferedImage newImage = resizeImage(image,532,532);
         
        	   //圖像緩沖區圖檔儲存為圖檔檔案(檔案不存在會自動建立檔案儲存,檔案存在會覆寫原檔案儲存)
                ImageIO.write(newImage, "jpg", new File("F:/test/pic1.jpg"));
            } catch (IOException e) {
                e.printStackTrace();
            }
               

    resizeImage方法:

    其他可能會用到的方法:

    //BufferedImage圖檔流轉byte[]數組
        public static byte[] imageToBytes(BufferedImage bImage) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            try {
                ImageIO.write(bImage, "jpg", out);
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            return out.toByteArray();
        }
    
     //byte[]數組轉BufferedImage圖檔流
     private static BufferedImage bytesToBufferedImage(byte[] ImageByte) {
            ByteArrayInputStream in = new ByteArrayInputStream(ImageByte);
            BufferedImage image = null;
            try {
                image = ImageIO.read(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return image;
        }
               
  • 讀取圖檔檔案進行調整圖檔大小
    try {
                //讀取原始圖檔
                BufferedImage image = ImageIO.read(new FileInputStream("F:/test/pic1.jpg"));
                System.out.println("Width: " + image.getWidth());
                System.out.println("Height: " + image.getHeight());
                //調整圖檔大小
                BufferedImage newImage = resizeImage(image,200,200);
                //圖像緩沖區圖檔儲存為圖檔檔案(檔案不存在會自動建立檔案儲存,檔案存在會覆寫原檔案儲存)
                ImageIO.write(newImage, "jpg", new File("F:/test/pic2.jpg"));
            } catch (IOException e) {
                e.printStackTrace();
            }
               
    參考:How Can I Resize an Image Using Java?

二十一、将圖檔BufferedImage轉換為MultipartFile

上面一條是将圖檔轉為BufferedImage進行大小調整,有時候我們需要将BufferedImage轉為MultipartFile進行上傳等操作

方法一:

  • 第一步:建立類實作MultipartFile接口
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.*;
    
    public class ConvertToMultipartFile implements MultipartFile {
        private byte[] fileBytes;
        String name;
        String originalFilename;
        String contentType;
        boolean isEmpty;
        long size;
    
        public ConvertToMultipartFile(byte[] fileBytes, String name, String originalFilename, String contentType,
                              long size) {
            this.fileBytes = fileBytes;
            this.name = name;
            this.originalFilename = originalFilename;
            this.contentType = contentType;
            this.size = size;
            this.isEmpty = false;
        }
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public String getOriginalFilename() {
            return originalFilename;
        }
    
        @Override
        public String getContentType() {
            return contentType;
        }
    
        @Override
        public boolean isEmpty() {
            return isEmpty;
        }
    
        @Override
        public long getSize() {
            return size;
        }
    
        @Override
        public byte[] getBytes() throws IOException {
            return fileBytes;
        }
    
        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(fileBytes);
        }
    
        @Override
        public void transferTo(File dest) throws IOException, IllegalStateException {
            new FileOutputStream(dest).write(fileBytes);
        }
    }
    
               
  • 第二步:轉換
    //讀取原始圖檔
     BufferedImage image = ImageIO.read(new FileInputStream("F:/test/pic1.jpg"));
    //BufferedImage轉MultipartFile
    MultipartFile multipartFile = new ConvertToMultipartFile(imageToBytes(image), "pic1", "myPicture", "jpg", imageToBytes(image).length);
               

方法二:

引入依賴:

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.2</version>
        <scope>compile</scope>
    </dependency>
           
try {
 			//讀取圖檔轉換為 BufferedImage
            BufferedImage image = ImageIO.read(new FileInputStream("F:/test/pic1.jpg"));
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write( newImage, "jpg", baos );
			//轉換為MultipartFile 
            MultipartFile multipartFile = new MockMultipartFile("pic1.jpg", baos.toByteArray());
    } catch (IOException e) {
            e.printStackTrace();
    }
           

參考:How to convert BufferedImage to a MultiPart file without saving file to disk?

二十二、檔案壓縮

工具類:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipUtils {
    /**
     *
     * 檔案夾壓縮成ZIP
     *
     * @param srcDir           壓縮檔案夾路徑
     * @param out              壓縮檔案輸出流
     * @param keepDirStructure 是否保留原來的目錄結構,true:保留目錄結構;
     *
     *                         false:所有檔案跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名檔案,會壓縮失敗)
     *
     * @throws RuntimeException 壓縮失敗會抛出運作時異常
     *
     */
    public static void toZip(String srcDir, OutputStream out, boolean keepDirStructure)
            throws RuntimeException {
        long start = System.currentTimeMillis();
        ZipOutputStream zos = null;
        try {
            zos = new ZipOutputStream(out);
            File sourceFile = new File(srcDir);
            compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
            long end = System.currentTimeMillis();
            System.out.println("壓縮完成,耗時:" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 多檔案壓縮成ZIP
     *
     * @param imageMap 需要壓縮的檔案清單,鍵值對為 <檔案名,檔案的位元組數組>,檔案名必須包含字尾
     * @param out      壓縮檔案輸出流
     * @throws RuntimeException 壓縮失敗會抛出運作時異常
     */
    public static void toZip(Map<String, byte[]> imageMap, OutputStream out) throws RuntimeException {
        long start = System.currentTimeMillis();
        try (ZipOutputStream zos = new ZipOutputStream(out)) {
            for (Map.Entry<String, byte[]> map : imageMap.entrySet()) {
                zos.putNextEntry(new ZipEntry(map.getKey()));
                zos.write(map.getValue());
                zos.closeEntry();
            }
            long end = System.currentTimeMillis();
            System.out.println("壓縮完成,耗時:" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        }
    }


    /**
     * 多檔案壓縮成ZIP
     * @param srcFiles 需要壓縮的檔案清單
     * @param out           壓縮檔案輸出流
     * @throws RuntimeException 壓縮失敗會抛出運作時異常
     */
    public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException {
        long start = System.currentTimeMillis();
        try(ZipOutputStream zos= new ZipOutputStream(out)) {
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[2048];
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1){
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
            long end = System.currentTimeMillis();
            System.out.println("壓縮完成,耗時:" + (end - start) +" ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils",e);
        }
    }



    /**
     *
     * 遞歸壓縮方法
     * @param sourceFile       源檔案
     * @param zos              zip輸出流
     * @param name             壓縮後的名稱
     * @param keepDirStructure 是否保留原來的目錄結構,true:保留目錄結構;
     *
     *                         false:所有檔案跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名檔案,會壓縮失敗)
     * @throws Exception
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean keepDirStructure) throws Exception {
        byte[] buf = new byte[2048];
        if (sourceFile.isFile()) {
            // 向zip輸出流中添加一個zip實體,構造器中name為zip實體的檔案的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy檔案到zip輸出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原來的檔案結構時,需要對空檔案夾進行處理
                if (keepDirStructure) {
                    // 空檔案夾的處理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 沒有檔案,不需要檔案的copy
                    zos.closeEntry();
                }
            } else {
                for (File file : listFiles) {
                    // 判斷是否需要保留原來的檔案結構
                    if (keepDirStructure) {
                        // 注意:file.getName()前面需要帶上父檔案夾的名字加一斜杠,
                        // 不然最後壓縮包中就不能保留原來的檔案結構,即:所有檔案都跑到壓縮包根目錄下了
                        compress(file, zos, name + "/" + file.getName(), keepDirStructure);
                    } else {
                        compress(file, zos, file.getName(), keepDirStructure);
                    }
                }
            }
        }
    }
}
           
  • 測試:壓縮多個檔案(利用byte[]壓縮)
    import org.apache.commons.io.IOUtils;
    import utils.ZipUtils;
    import java.io.*;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) {
            try {
                //讀取圖檔轉換為byte[]
                FileInputStream inputStream1 = new FileInputStream("F:/test/pic1.jpg");
                byte[] bytes1 = IOUtils.toByteArray(inputStream1);
                //讀取pdf轉換為byte[]
                FileInputStream inputStream2 = new FileInputStream("F:/test/doc_20210203100237.pdf");
                byte[] bytes2 = IOUtils.toByteArray(inputStream2);
                //讀取txt轉換為byte[]
                FileInputStream inputStream3 = new FileInputStream("F:/test/za.txt");
                byte[] bytes3 = IOUtils.toByteArray(inputStream3);
    
                //三個檔案存入picMap
                Map<String, byte[]> picMap = new HashMap<>();
                picMap.put("pic1.jpg", bytes1);
                picMap.put("doc_20210203100237.pdf", bytes2);
                picMap.put("za.txt", bytes3);
    
                //定義輸出流和最終生成的檔案名,如;MyPic.zip
                FileOutputStream fileOutputStream = new FileOutputStream(new File("F:/test/MyPic.zip"));
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                //開始壓縮
                ZipUtils.toZip(picMap, bufferedOutputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
               
    • 測試,壓縮多檔案檔案(讀取檔案為byte[]壓縮):
    import java.io.*;
    import java.util.ArrayList;
    import utils.ZipUtils;
    import java.util.List;
    
    public class Test {
        public static void main(String[] args) {
       		try {
       			//要壓縮的檔案清單
                List<File> fileList = new ArrayList<>();
                fileList.add(new File("F:/test/pic1.jpg"));
                fileList.add(new File("F:/test/doc_20210203100237.pdf"));
                //壓縮後的檔案名和儲存路徑
                FileOutputStream fos2 = new FileOutputStream(new File("f:/test/Myzip.zip"));
                //開始壓縮
                ZipUtils.toZip(fileList, fos2);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
         }
    }
    
               
  • 壓縮檔案夾
    import utils.ZipUtils;
    import java.io.*;
    
    public class Test {
        public static void main(String[] args) {
       		 try {
               		 //定義輸出流和最終生成的檔案名,如;儲存到 F盤的 MyPic.zip
                	 FileOutputStream   fileOutputStream = new FileOutputStream(new File("F:/Myfolder.zip"));
               		 BufferedOutputStream  bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                	//開始壓縮 F盤下的test檔案夾
                	ZipUtils.toZip("F:/test", bufferedOutputStream,true);
           		 } catch (FileNotFoundException e) {
               			 e.printStackTrace();
           		 }
         }
    }
               

參考:Java實作将檔案或者檔案夾壓縮成zip

二十三、InputStream、FileInputStream 轉 byte[ ]

利用Apache Commons IO包

InputStream is;
//FileInputStream  is;
byte[] bytes = IOUtils.toByteArray(is);
           

參考:Convert InputStream to byte array in Java

二十四、文本檔案的InputStream、FileInputStream 轉 String

利用Apache Commons IO包

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();
           

參考:How do I read / convert an InputStream into a String in Java?

二十五、MultipartFile或byte[]轉InputStream

//multipartFile擷取檔案byte[]
byte[] bytes = multipartFile.getBytes();
//byte[]轉 InputStream
InputStream in = new ByteArrayInputStream(bytes);
           

二十六、檔案轉byte[]

方法一(使用apache.commons.io庫):

File file = new File("F:/oracle_init.sql");
byte[] bytes = FileUtils.readFileToByteArray(file);
           

方法二:

File file = new File("F:/oracle_init.sql");
byte[] bytes = Files.readAllBytes(file.toPath());
//byte[] bytes = Files.readAllBytes(Paths.get("F:/oracle_init.sql"));
           

參考:

java基礎io流——OutputStream和InputStream的故事(溫故知新)

Java:位元組流和字元流(輸入流和輸出流)

Java IO流操作彙總: inputStream 和 outputStream

JAVA中字元流詳解

字元流與位元組流的差別

使用sftp上傳下載下傳删除檔案,建立檔案夾