一、IO流概要
1.1、概念
開發中經常要進行輸入輸出操作,掌握Java中的IO流顯得非常必要。
流(stream)的概念源於UNIX中管道(pipe)的概念。在UNIX中,管道是一條不間斷的字節流,用來實現程序或進程間的通信,或讀寫外圍設備、外部文件等。
一個流,必有源端和目的端,它們可以是計算機內存的某些區域,也可以是磁盤文件,甚至可以是Internet上的某個URL。
流的方向是重要的,根據流的方向,流可分為兩類:輸入流和輸出流。用戶可以從輸入流中讀取信息,但不能寫它。相反,對輸出流,只能往輸入流寫,而不能讀它。
實際上,流的源端和目的端可簡單地看成是字節的生產者和消費者,對輸入流,可不必關心它的源端是什么,只要簡單地從流中讀數據,而對輸出流,也可不知道它的目的端,只是簡單地往流中寫數據。
形象的比喻——水流 ,文件======程序,文件和程序之間連接一個管道,水流就在之間形成了,自然也就出現了方向:可以流進,也可以流出。便於理解,這么定義流: 流就是一個管道里面有流水,這個管道連接了文件和程序。
Java流操作有關的類或接口:
Java IO流的結構圖:
流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱為流,流的本質是數據傳輸,根據數據傳輸特性將流抽象為各種類,方便更直觀的進行數據操作。
1.2、IO流的分類
根據處理數據類型的不同分為:字符流和字節流
根據數據流向不同分為:輸入流和輸出流
1.2.1、字符流和字節流
字符流的由來: 因為數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基於字節流讀取時,去查了指定的碼表。 字節流和字符流的區別:
讀寫單位不同:字節流以字節(8bit)為單位,字符流以字符為單位,根據碼表映射字符,一次可能讀多個字節。
處理對象不同:字節流能處理所有類型的數據(如圖片、avi等),而字符流只能處理字符類型的數據。
結論:只要是處理純文本數據,就優先考慮使用字符流。 除此之外都使用字節流。
1.2.2、輸入流和輸出流
對輸入流只能進行讀操作,對輸出流只能進行寫操作,程序中需要根據待傳輸數據的不同特性而使用不同的流。
二、File類
2.1、簡介
File類是io包中唯一代表磁盤文件本身的對象。File類定義了一些與平台無關的方法來操作文件,可以通過調用File類中的方法,實現創建、刪除、重命名文件等。File類的對象主要用來獲取文件本身的一些信息,如文件所在目錄、文件的長度、文件讀寫權限等。數據流可以將數據寫入到文件中,而文件也是數據流最常用的數據媒體。
提供定位本地文件系統、描述文件和目錄的功能
是 java.io 包中引用實際磁盤文件的唯一對象
File類對象描述文件路徑、名字、長度、可否讀寫等屬性,可用來命名文件、查詢文件屬性和處理目錄,但不讀寫文件。
解決程序與文件系統的溝通
各種文件系統提供的基本服務一樣,但實現細節互不兼容
構造函數
File(String pathname);
File(String dir, String subpath);
File(File dir, String subpath);
File(String path) 文件(相對路徑),移植性較好: File f1 = new File(“mydir\\myfile.txt”); 目錄(絕對路徑): File f2 = new File(“d:\\mydir\\dir1”); File(String parent, String child ) 文件路徑以及文件名: File f3 = new File(“d:\\d1” , “a.java”) File(File dir, String name) 文件對象與文件名:File f4 = new File(f2 , “myfile.txt”);
常用方法
canRead()、canWrite()、delete()、equals(object)、exists() getAbsolutePath() 和 length()
方法 | 描述 |
String getName() | 獲取文件的名稱 |
boolean canRead() | 判斷文件是否是可讀的 |
boolean canWrite() | 品判斷文件是否可被寫入 |
boolean exits() | 判斷文件長度是否存在 |
int length() | 獲取文件的長度(以字節為單位) |
String getAbsolutePath() | 獲取文件的絕對路徑 |
String getParent() | 獲取文件的父路徑 |
boolean isFile() | 判斷此抽象路徑名表示的文件是否為普通文件 |
boolean isDirectory() | 判斷此抽象路徑名表示的是否是一個目錄 |
boolean isHidden | 判斷文件是否是隱藏文件 |
long lastModified() | 獲取文件最后修改時間 |
Boolean canExecute() |
測試應用程序是否可以執行此抽象路徑名表示的文件。
|
boolean createNewFile() | 當且僅當具有該名稱的文件尚不存在時,原子地創建一個由該抽象路徑名命名的新的空文件。 |
boolean delete() | 刪除由此抽象路徑名表示的文件或目錄。 |
File[] listFiles() | 返回一個抽象路徑名數組,表示由該抽象路徑名表示的目錄中的文件。 |
String[] list() | 返回一個字符串數組,命名由此抽象路徑名表示的目錄中的文件和目錄。 |
boolean mkdirs() | 創建由此抽象路徑名命名的目錄,包括任何必需但不存在的父目錄。可創建多層文件包 |
boolean mkdir() | 創建由此抽象路徑名命名的目錄。只能創建一層文件包 |
boolean reNameTo(File dest) | 重命名由此抽象路徑名表示的文件。 |
boolean setReadOnly() |
標記由此抽象路徑名命名的文件或目錄,以便只允許讀取操作。
|
boolean setWritable(boolean writable) |
一種方便的方法來設置所有者對此抽象路徑名的寫入權限。
|
2.2、文件操作示例
創建與刪除文件:
package com.io; import java.io.File; import java.io.IOException; public class IODemo1 { public static void main(String[] args) throws IOException { File file=new File("d:"+File.separator, "file1.txt"); if(file.exists()){ file.delete(); System.out.println("刪除成功!"); }else{ file.createNewFile(); System.out.println("創建成功!"); } } }
常見文件操作:

package com.file; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class IODemo1 { public static void main(String[] args) throws IOException { //創建方法 /* @SuppressWarnings("unused") File file = new File("F:\\a.txt"); //System.out.println("創建成功了嗎?"+file.createNewFile()); //System.out.println("單級文件夾創建成功了嗎?"+file.mkdir()); //System.out.println("多級文件夾創建成功了嗎?"+file.mkdirs()); //File dest = new File("F:\\電影\\c.txt"); //System.out.println("重命名成功了嗎?"+file.renameTo(dest)); */ /* //刪除方法 File file = new File("F:\\電影"); System.out.println("刪除成功了嗎?"+file.delete()); file.deleteOnExit(); */ //判斷方法 /* File file = new File("F:\\a.txt"); System.out.println("文件或者文件夾存在嗎?"+file.exists()); System.out.println("是一個文件嗎?"+file.isFile()); System.out.println("是一個文件夾嗎?"+file.isDirectory()); System.out.println("是隱藏文件嗎?"+file.isHidden()); System.out.println("此路徑是絕對路徑名?"+file.isAbsolute()); */ //獲取方法 /* File file = new File("f:\\a.txt"); System.out.println("文件或者文件夾得名稱是:"+file.getName()); System.out.println("絕對路徑是:"+file.getPath()); System.out.println("絕對路徑是:"+file.getAbsolutePath()); System.out.println("文件大小是(以字節為單位):"+file.length()); System.out.println("父路徑是"+file.getParent()); //使用日期類與日期格式化類進行獲取規定的時間 long lastmodified= file.lastModified(); Date data = new Date(lastmodified); SimpleDateFormat simpledataformat = new SimpleDateFormat("YY年MM月DD日 HH:mm:ss"); System.out.println("最后一次修改的時間是:"+simpledataformat.format(data)); */ //文件或者文件夾的方法 File[] file = File.listRoots(); System.out.println("所有的盤符是:"); for(File item : file){ System.out.println("\t"+item); } File filename =new File("F:\\Java workspace\\Java"); String[] name = filename.list(); System.out.println("指定文件夾下的文件或者文件夾有:"); for(String item : name){ System.out.println("\t"+item); } File[] f = filename.listFiles(); System.out.println("獲得該路徑下的文件或文件夾是:"); for(File item : f){ System.out.println("\t"+item.getName()); } } }
遞歸獲得所有文件與文件夾:
package com.zhangguo.demo1; import java.io.File; public class FileDemo02 { public static void main(String[] args) { File file01 = new File("e:" + File.separator + "NF"+File.separator+"WebAPI"); ListFile(file01); } public static void ListFile(File file01) { if (file01.isDirectory()) { // 獲得當前文件下所有的文件 File[] files = file01.listFiles(); for (File file : files) { System.out.println(file.getName()); ListFile(file); } } } }
結果:
2.3、Swing介紹
Swing是一個用於開發Java應用程序用戶界面的開發工具包。
以抽象窗口工具包(AWT)為基礎使跨平台應用程序可以使用任何可插拔的外觀風格。Swing開發人員只用很少的代碼就可以利用Swing豐富、靈活的功能和模塊化組件來創建優雅的用戶界面。 工具包中所有的包都是以swing作為名稱,例如javax.swing,javax.swing.event。
Swing 是一個為Java設計的GUI工具包。
Swing包括了圖形用戶界面(GUI)器件如:文本框,按鈕,分隔窗格和表。
Swing提供許多比AWT更好的屏幕顯示元素。它們用純Java寫成,所以同Java本身一樣可以跨平台運行,這一點不像AWT。它們是JFC的一部分。它們支持可更換的面板和主題(各種操作系統默認的特有主題),然而不是真的使用原生平台提供的設備,而是僅僅在表面上模仿它們。這意味着你可以在任意平台上使用JAVA支持的任意面板。輕量級組件的缺點則是執行速度較慢,優點就是可以在所有平台上采用統一的行為。
示例一:
package com.zhangguo.demo1; import javax.swing.*; public class HelloWorldSwing { /** * 創建並顯示GUI。出於線程安全的考慮, 這個方法在事件調用線程中調用。 */ private static void createAndShowGUI() { // 確保一個漂亮的外觀風格 JFrame.setDefaultLookAndFeelDecorated(true); // 創建及設置窗口 JFrame frame = new JFrame("HelloWorldSwing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 添加 "Hello World" 標簽 JLabel label = new JLabel("Hello World"); frame.getContentPane().add(label); // 顯示窗口 frame.pack(); frame.setVisible(true); } public static void main(String[] args) { // 顯示應用 GUI javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }
運行結果:
示例二:
package com.zhangguo.demo1; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; public class SwingLoginExample { public static void main(String[] args) { // 創建 JFrame 實例 JFrame frame = new JFrame("Login Example"); // Setting the width and height of frame frame.setSize(350, 200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); /* 創建面板,這個類似於 HTML 的 div 標簽 * 我們可以創建多個面板並在 JFrame 中指定位置 * 面板中我們可以添加文本字段,按鈕及其他組件。 */ JPanel panel = new JPanel(); // 添加面板 frame.add(panel); /* * 調用用戶定義的方法並添加組件到面板 */ placeComponents(panel); // 設置界面可見 frame.setVisible(true); } private static void placeComponents(JPanel panel) { /* 布局部分我們這邊不多做介紹 * 這邊設置布局為 null */ panel.setLayout(null); // 創建 JLabel JLabel userLabel = new JLabel("User:"); /* 這個方法定義了組件的位置。 * setBounds(x, y, width, height) * x 和 y 指定左上角的新位置,由 width 和 height 指定新的大小。 */ userLabel.setBounds(10,20,80,25); panel.add(userLabel); /* * 創建文本域用於用戶輸入 */ JTextField userText = new JTextField(20); userText.setBounds(100,20,165,25); panel.add(userText); // 輸入密碼的文本域 JLabel passwordLabel = new JLabel("Password:"); passwordLabel.setBounds(10,50,80,25); panel.add(passwordLabel); /* *這個類似用於輸入的文本域 * 但是輸入的信息會以點號代替,用於包含密碼的安全性 */ JPasswordField passwordText = new JPasswordField(20); passwordText.setBounds(100,50,165,25); panel.add(passwordText); // 創建登錄按鈕 JButton loginButton = new JButton("login"); loginButton.setBounds(10, 80, 80, 25); panel.add(loginButton); } }
運行結果:
三、字節流操作
字節流和字符流的區別:
- 讀寫單位不同:字節流以字節(8bit)為單位,字符流以字符為單位,根據碼表映射字符,一次可能讀多個字節。
- 處理對象不同:字節流能處理所有類型的數據(如圖片、avi等),而字符流只能處理字符類型的數據。
結論:只要是處理純文本數據,就優先考慮使用字符流。 除此之外都使用字節流。
3.1、字節輸出流
1.輸出字節流OutputStream
IO 中輸出字節流的繼承圖可見上圖,可以看出:
OutputStream 是所有的輸出字節流的父類,它是一個抽象類。
ByteArrayOutputStream、FileOutputStream 是兩種基本的介質流,它們分別向Byte 數組、和本地文件中寫入數據。PipedOutputStream 是向與其它線程共用的管道中寫入數據,ObjectOutputStream 和所有FilterOutputStream 的子類都是裝飾流。
字節輸出流的常用方法:
示例1:
import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class OutputStreamDemo01 { public static void main(String[] args) throws Exception {//異常拋出不處理 // 第1步:使用File類找到一個文件 File f = new File("d:"+File.separator+"test.txt");//聲明File對象 // 第2步:通過子類實例化父類對象 OutputStream out = null; // 准備好一個輸出的對象 out = new FileOutputStream(f); // 通過對象多態性,進行實例化 // 第3步:進行寫操作 String str = "Hello World!!!"; // 准備一個字符串 byte b[] = str.getBytes();// 只能輸出byte數組,所以將字符串變為byte數組 out.write(b); //將內容輸出,保存文件 // 第4步:關閉輸出流 out.close(); // 關閉輸出流 } }
追加文件內容
示例:
package com.zhangguo.demo1; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class FileDemo03 { public static void main(String[] args) throws Exception { File file03 = new File("e:" + File.separator + "file3.html"); OutputStream os = new FileOutputStream(file03); byte[] content = "<marquee><h1>Hello OutputStream!</h1></marquee>".getBytes(); os.write(content); os.close(); } }
結果:
3.2、字節輸入流
輸入字節流InputStreamIO 中輸入字節流的繼承圖可見上圖,可以看出:
InputStream 是所有的輸入字節流的父類,它是一個抽象類。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的介質流,它們分別從Byte 數組、StringBuffer、和本地文件中讀取數據。PipedInputStream 是從與其它線程共用的管道中讀取數據,與Piped 相關的知識后續單獨介紹。
ObjectInputStream 和所有FilterInputStream 的子類都是裝飾流(裝飾器模式的主角)。
字節輸入流的常用方法:
示例:
import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class InputStramDemo01 { public static void main(String[] args)throws Exception {//異常拋出不處理 // 第1步:使用File類找到一個文件 File f = new File("d:"+File.separator+"test.txt"); // 聲明File對象 // 第2步:通過子類實例化父類對象 InputStream input = null; // 准備好一個輸入的對象 input = new FileInputStream(f); // 通過對象多態性進行實例化 // 第3步:進行讀操作 byte b[] = new byte[1024]; // 所有的內容讀到此數組中 input.read(b); // 把內容取出,內容讀到byte數組中 // 第4步:關閉輸入流 input.close(); // 關閉輸入流 System.out.println("內容為:"+new String(b));//把byte數組變為字符串輸出 } }
示例:
package com.zhangguo.demo1; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class FileDemo04 { public static void main(String[] args) throws Exception { //模板文件 File file04 = new File("e:" + File.separator + "news.template"); InputStream is = new FileInputStream(file04); byte[] content =new byte[(int)file04.length()]; is.read(content); is.close(); String template=new String(content); System.out.println("模板的內容為:"+template); } }
結果:
3.2.1、簡單的動態頁面靜態化
基本過程是:讀模板文件->取內容->替換->生成靜態頁。
package com.zhangguo.demo1; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; public class FileDemo04 { public static void main(String[] args) throws Exception { //模板文件 File file04 = new File("e:" + File.separator + "news.template"); InputStream is = new FileInputStream(file04); byte[] content =new byte[(int)file04.length()]; is.read(content); is.close(); String template=new String(content); System.out.println("模板的內容為:"+template); //生成新聞頁 File file05 = new File("e:" + File.separator + "index.html"); OutputStream os=new FileOutputStream(file05); StringBuffer strb=new StringBuffer(); strb.append("<ul>"); for (int i = 0; i <10; i++) { strb.append("<li>"); strb.append("<a href='news0"+i+".html' >"+UUID.randomUUID()+"</a>"); strb.append("</li>"); } strb.append("</ul>"); String news=template.replace("<!--%content%-->", strb.toString()); os.write(news.getBytes()); os.close(); } }
結果:
四、字符流操作
字符流的由來: 因為數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基於字節流讀取時,去查了指定的碼表。
程序中的輸入輸出都是以流的形式保存的,流中保存的實際上全都是字節文件。
4.1、字符流輸出
在Java中IO操作也是有相應步驟的,以文件操作為例,主要的操作流程如下:
1 使用File類打開一個文件
2 通過字節流或字符流的子類,指定輸出的位置
3 進行讀/寫操作
4 關閉輸入/輸出
IO操作屬於資源操作,一定要記得關閉
輸出流: OutputStream 寫出 就是將數據從程序寫入到外部文件。對應 Writer;
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class WriterDemo1 { public static void main(String[] args) throws IOException { File f = new File("d:"+File.pathSeparator+"test.txt"); Writer out; out = new FileWriter(f); String str = "Hello,World"; out.write(str); out.flush(); out.close(); } }
示例:
package com.zhangguo.demo1; import java.io.File; import java.io.FileWriter; import java.io.Writer; public class FileDemo05 { public static void main(String[] args) throws Exception { File file05 = new File("e:" + File.separator + "file05.txt"); //追加 Writer writer = new FileWriter(file05,true); writer.write("\r\nHello FileWriter!"); writer.flush(); writer.close(); } }
結果:
Hello FileWriter!
Hello FileWriter!
4.2、字符流輸入
輸入流:InputStream 讀入 就是從外部文件中讀取數據到程序。對應 Reader;
import java.io.*; public class ReaderDemo2 { public static void main(String[] args) throws IOException { File f = new File("d:"+ File.pathSeparator+"test.txt"); Reader reader = new FileReader(f); int len = 0; char[] c = new char[1024]; int temp = 0; while((temp = reader.read()) != -1){ c[len] = (char)temp; len++; } reader.close(); System.out.println("內容為:"+ new String(c,0,len)); } }
示例一:
package com.zhangguo.demo1; import java.io.File; import java.io.FileReader; import java.io.Reader; public class FileDemo06 { public static void main(String[] args) throws Exception { File file06 = new File("e:" + File.separator + "file05.txt"); //追加 Reader reader=new FileReader(file06); char[] content=new char[(int) file06.length()]; reader.read(content); reader.close(); System.out.println("內容:"+new String(content)); } }
結果一:
內容:Hello FileWriter!
Hello FileWriter!
示例二:
package com.zhangguo.demo1; import java.io.File; import java.io.FileReader; import java.io.Reader; public class FileDemo06 { public static void main(String[] args) throws Exception { File file06 = new File("e:" + File.separator + "file05.txt"); Reader reader = new FileReader(file06); char[] content = new char[(int) file06.length()]; int temp; int i = 0; while ((temp = reader.read()) != -1) { content[i++] = (char) temp; } System.out.println("內容:" + new String(content)); } }
結果二:
內容:Hello FileWriter!
Hello FileWriter!
五、文件操作工具類與封裝
5.1、文件工具類fileUtil(文件增刪改,文件拷貝等)

package com.zhangguo.demo1; import java.io.*; import java.net.MalformedURLException; import java.net.URL; /** * 文件工具類 */ public class FileUtil { /** * 讀取文件內容 * * @param is * @return */ public static String readFile(InputStream is) { BufferedReader br = null; StringBuffer sb = new StringBuffer(); try { br = new BufferedReader(new InputStreamReader(is, "UTF-8")); String readLine = null; while ((readLine = br.readLine()) != null) { sb.append(readLine+"\r\n"); } } catch (Exception e) { e.printStackTrace(); } finally { try { br.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } public static String readFile(String path){ File file07 = new File(path); InputStream is=null; try { is = new FileInputStream(file07); } catch (FileNotFoundException e) { e.printStackTrace(); } return readFile(is); } /** * 判斷指定的文件是否存在。 * * @param fileName * @return */ public static boolean isFileExist(String fileName) { return new File(fileName).isFile(); } /** * 創建指定的目錄。 如果指定的目錄的父目錄不存在則創建其目錄書上所有需要的父目錄。 * 注意:可能會在返回false的時候創建部分父目錄。 * * @param file * @return */ public static boolean makeDirectory(File file) { File parent = file.getParentFile(); if (parent != null) { return parent.mkdirs(); } return false; } /** * 返回文件的URL地址。 * * @param file * @return * @throws MalformedURLException */ public static URL getURL(File file) throws MalformedURLException { String fileURL = "file:/" + file.getAbsolutePath(); URL url = new URL(fileURL); return url; } /** * 從文件路徑得到文件名。 * * @param filePath * @return */ public static String getFileName(String filePath) { File file = new File(filePath); return file.getName(); } /** * 從文件名得到文件絕對路徑。 * * @param fileName * @return */ public static String getFilePath(String fileName) { File file = new File(fileName); return file.getAbsolutePath(); } /** * 將DOS/Windows格式的路徑轉換為UNIX/Linux格式的路徑。 * * @param filePath * @return */ public static String toUNIXpath(String filePath) { return filePath.replace("", "/"); } /** * 從文件名得到UNIX風格的文件絕對路徑。 * * @param fileName * @return */ public static String getUNIXfilePath(String fileName) { File file = new File(fileName); return toUNIXpath(file.getAbsolutePath()); } /** * 得到文件后綴名 * * @param fileName * @return */ public static String getFileExt(String fileName) { int point = fileName.lastIndexOf('.'); int length = fileName.length(); if (point == -1 || point == length - 1) { return ""; } else { return fileName.substring(point + 1, length); } } /** * 得到文件的名字部分。 實際上就是路徑中的最后一個路徑分隔符后的部分。 * * @param fileName * @return */ public static String getNamePart(String fileName) { int point = getPathLastIndex(fileName); int length = fileName.length(); if (point == -1) { return fileName; } else if (point == length - 1) { int secondPoint = getPathLastIndex(fileName, point - 1); if (secondPoint == -1) { if (length == 1) { return fileName; } else { return fileName.substring(0, point); } } else { return fileName.substring(secondPoint + 1, point); } } else { return fileName.substring(point + 1); } } /** * 得到文件名中的父路徑部分。 對兩種路徑分隔符都有效。 不存在時返回""。 * 如果文件名是以路徑分隔符結尾的則不考慮該分隔符,例如"/path/"返回""。 * * @param fileName * @return */ public static String getPathPart(String fileName) { int point = getPathLastIndex(fileName); int length = fileName.length(); if (point == -1) { return ""; } else if (point == length - 1) { int secondPoint = getPathLastIndex(fileName, point - 1); if (secondPoint == -1) { return ""; } else { return fileName.substring(0, secondPoint); } } else { return fileName.substring(0, point); } } /** * 得到路徑分隔符在文件路徑中最后出現的位置。 對於DOS或者UNIX風格的分隔符都可以。 * * @param fileName * @return */ public static int getPathLastIndex(String fileName) { int point = fileName.lastIndexOf("/"); if (point == -1) { point = fileName.lastIndexOf(""); } return point; } /** * 得到路徑分隔符在文件路徑中指定位置前最后出現的位置。 對於DOS或者UNIX風格的分隔符都可以。 * * @param fileName * @param fromIndex * @return */ public static int getPathLastIndex(String fileName, int fromIndex) { int point = fileName.lastIndexOf("/", fromIndex); if (point == -1) { point = fileName.lastIndexOf("", fromIndex); } return point; } /** * 得到路徑分隔符在文件路徑中首次出現的位置。 對於DOS或者UNIX風格的分隔符都可以。 * * @param fileName * @return */ public static int getPathIndex(String fileName) { int point = fileName.indexOf("/"); if (point == -1) { point = fileName.indexOf(""); } return point; } /** * 得到路徑分隔符在文件路徑中指定位置后首次出現的位置。 對於DOS或者UNIX風格的分隔符都可以。 * * @param fileName * @param fromIndex * @return */ public static int getPathIndex(String fileName, int fromIndex) { int point = fileName.indexOf("/", fromIndex); if (point == -1) { point = fileName.indexOf("", fromIndex); } return point; } /** * 將文件名中的類型部分去掉。 * * @param filename * @return */ public static String removeFileExt(String filename) { int index = filename.lastIndexOf("."); if (index != -1) { return filename.substring(0, index); } else { return filename; } } /** * 得到相對路徑。 文件名不是目錄名的子節點時返回文件名。 * * @param pathName * @param fileName * @return */ public static String getSubpath(String pathName, String fileName) { int index = fileName.indexOf(pathName); if (index != -1) { return fileName.substring(index + pathName.length() + 1); } else { return fileName; } } /** * 刪除一個文件。 * * @param filename * @throws IOException */ public static void deleteFile(String filename) throws IOException { File file = new File(filename); if (file.isDirectory()) { throw new IOException("IOException -> BadInputException: not a file."); } if (!file.exists()) { throw new IOException("IOException -> BadInputException: file is not exist."); } if (!file.delete()) { throw new IOException("Cannot delete file. filename = " + filename); } } /** * 刪除文件夾及其下面的子文件夾 * * @param dir * @throws IOException */ public static void deleteDir(File dir) throws IOException { if (dir.isFile()) throw new IOException("IOException -> BadInputException: not a directory."); File[] files = dir.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { File file = files[i]; if (file.isFile()) { file.delete(); } else { deleteDir(file); } } } dir.delete(); } /** * 復制文件 * * @param src * @param dst * @throws Exception */ public static void copy(File src, File dst) throws Exception { int BUFFER_SIZE = 4096; InputStream in = null; OutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE); out = new BufferedOutputStream(new FileOutputStream(dst), BUFFER_SIZE); byte[] buffer = new byte[BUFFER_SIZE]; int len = 0; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } } catch (Exception e) { throw e; } finally { if (null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } in = null; } if (null != out) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } out = null; } } } /** * @復制文件,支持把源文件內容追加到目標文件末尾 * @param src * @param dst * @param append * @throws Exception */ public static void copy(File src, File dst, boolean append) throws Exception { int BUFFER_SIZE = 4096; InputStream in = null; OutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE); out = new BufferedOutputStream(new FileOutputStream(dst, append), BUFFER_SIZE); byte[] buffer = new byte[BUFFER_SIZE]; int len = 0; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } } catch (Exception e) { throw e; } finally { if (null != in) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } in = null; } if (null != out) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } out = null; } } } }
運行結果:
Hello FileWriter!
Hello FileWriter!
5.2、文件操作工具類

package com.zhangguo.demo1; import java.io.*; import java.util.StringTokenizer; public class FileUtil2 { private static String message; /** * 讀取文本文件內容 * * @param filePathAndName * 帶有完整絕對路徑的文件名 * @param encoding * 文本文件打開的編碼方式 * @return 返回文本文件的內容 */ public static String readTxt(String filePathAndName, String encoding) throws IOException { encoding = encoding.trim(); StringBuffer str = new StringBuffer(""); String st = ""; try { FileInputStream fs = new FileInputStream(filePathAndName); InputStreamReader isr; if (encoding.equals("")) { isr = new InputStreamReader(fs); } else { isr = new InputStreamReader(fs, encoding); } BufferedReader br = new BufferedReader(isr); try { String data = ""; while ((data = br.readLine()) != null) { str.append(data + " "); } } catch (Exception e) { str.append(e.toString()); } st = str.toString(); } catch (IOException es) { st = ""; } return st; } /** * @description 寫文件 * @param args * @throws UnsupportedEncodingException * @throws IOException */ public static boolean writeTxtFile(String content, File fileName, String encoding) { FileOutputStream o = null; boolean result=false; try { o = new FileOutputStream(fileName); o.write(content.getBytes(encoding)); result=true; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (o != null) { try { o.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } /** * * @param content * @param fileName * @return */ public static boolean writeTxtFile(String content,String fileName) { return writeTxtFile(content,new File(fileName),"UTF-8"); } /** * 新建目錄 * * @param folderPath * 目錄 * @return 返回目錄創建后的路徑 */ public static String createFolder(String folderPath) { String txt = folderPath; try { java.io.File myFilePath = new java.io.File(txt); txt = folderPath; if (!myFilePath.exists()) { myFilePath.mkdir(); } } catch (Exception e) { message = "創建目錄操作出錯"; } return txt; } /** * 多級目錄創建 * * @param folderPath * 准備要在本級目錄下創建新目錄的目錄路徑 例如 c:myf * @param paths * 無限級目錄參數,各級目錄以單數線區分 例如 a|b|c * @return 返回創建文件后的路徑 例如 c:myfac */ public static String createFolders(String folderPath, String paths) { String txts = folderPath; try { String txt; txts = folderPath; StringTokenizer st = new StringTokenizer(paths, "|"); for (int i = 0; st.hasMoreTokens(); i++) { txt = st.nextToken().trim(); if (txts.lastIndexOf("/") != -1) { txts = createFolder(txts + txt); } else { txts = createFolder(txts + txt + "/"); } } } catch (Exception e) { message = "創建目錄操作出錯!"; } return txts; } /** * 新建文件 * * @param filePathAndName * 文本文件完整絕對路徑及文件名 * @param fileContent * 文本文件內容 * @return */ public static void createFile(String filePathAndName, String fileContent) { try { String filePath = filePathAndName; filePath = filePath.toString(); File myFilePath = new File(filePath); if (!myFilePath.exists()) { myFilePath.createNewFile(); } FileWriter resultFile = new FileWriter(myFilePath); PrintWriter myFile = new PrintWriter(resultFile); String strContent = fileContent; myFile.println(strContent); myFile.close(); resultFile.close(); } catch (Exception e) { message = "創建文件操作出錯"; } } /** * 有編碼方式的文件創建 * * @param filePathAndName * 文本文件完整絕對路徑及文件名 * @param fileContent * 文本文件內容 * @param encoding * 編碼方式 例如 GBK 或者 UTF-8 * @return */ public static void createFile(String filePathAndName, String fileContent, String encoding) { try { String filePath = filePathAndName; filePath = filePath.toString(); File myFilePath = new File(filePath); if (!myFilePath.exists()) { myFilePath.createNewFile(); } PrintWriter myFile = new PrintWriter(myFilePath, encoding); String strContent = fileContent; myFile.println(strContent); myFile.close(); } catch (Exception e) { message = "創建文件操作出錯"; } } /** * 刪除文件 * * @param filePathAndName * 文本文件完整絕對路徑及文件名 * @return Boolean 成功刪除返回true遭遇異常返回false */ public static boolean delFile(String filePathAndName) { boolean bea = false; try { String filePath = filePathAndName; File myDelFile = new File(filePath); if (myDelFile.exists()) { myDelFile.delete(); bea = true; } else { bea = false; message = (filePathAndName + "刪除文件操作出錯"); } } catch (Exception e) { message = e.toString(); } return bea; } /** * 刪除文件夾 * * @param folderPath * 文件夾完整絕對路徑 * @return */ public static void delFolder(String folderPath) { try { delAllFile(folderPath); // 刪除完里面所有內容 String filePath = folderPath; filePath = filePath.toString(); java.io.File myFilePath = new java.io.File(filePath); myFilePath.delete(); // 刪除空文件夾 } catch (Exception e) { message = ("刪除文件夾操作出錯"); } } /** * 刪除指定文件夾下所有文件 * * @param path * 文件夾完整絕對路徑 * @return * @return */ public static boolean delAllFile(String path) { boolean bea = false; File file = new File(path); if (!file.exists()) { return bea; } if (!file.isDirectory()) { return bea; } String[] tempList = file.list(); File temp = null; for (int i = 0; i < tempList.length; i++) { if (path.endsWith(File.separator)) { temp = new File(path + tempList[i]); } else { temp = new File(path + File.separator + tempList[i]); } if (temp.isFile()) { temp.delete(); } if (temp.isDirectory()) { delAllFile(path + "/" + tempList[i]);// 先刪除文件夾里面的文件 delFolder(path + "/" + tempList[i]);// 再刪除空文件夾 bea = true; } } return bea; } /** * 復制單個文件 * * @param oldPathFile * 准備復制的文件源 * @param newPathFile * 拷貝到新絕對路徑帶文件名 * @return */ public static void copyFile(String oldPathFile, String newPathFile) { try { int bytesum = 0; int byteread = 0; File oldfile = new File(oldPathFile); if (oldfile.exists()) { // 文件存在時 InputStream inStream = new FileInputStream(oldPathFile); // 讀入原文件 FileOutputStream fs = new FileOutputStream(newPathFile); byte[] buffer = new byte[1444]; while ((byteread = inStream.read(buffer)) != -1) { bytesum += byteread; // 字節數 文件大小 System.out.println(bytesum); fs.write(buffer, 0, byteread); } inStream.close(); } } catch (Exception e) { message = ("復制單個文件操作出錯"); } } /** * 復制整個文件夾的內容 * * @param oldPath * 准備拷貝的目錄 * @param newPath * 指定絕對路徑的新目錄 * @return */ public static void copyFolder(String oldPath, String newPath) { try { new File(newPath).mkdirs(); // 如果文件夾不存在 則建立新文件夾 File a = new File(oldPath); String[] file = a.list(); File temp = null; for (int i = 0; i < file.length; i++) { if (oldPath.endsWith(File.separator)) { temp = new File(oldPath + file[i]); } else { temp = new File(oldPath + File.separator + file[i]); } if (temp.isFile()) { FileInputStream input = new FileInputStream(temp); FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString()); byte[] b = new byte[1024 * 5]; int len; while ((len = input.read(b)) != -1) { output.write(b, 0, len); } output.flush(); output.close(); input.close(); } if (temp.isDirectory()) {// 如果是子文件夾 copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]); } } } catch (Exception e) { message = "復制整個文件夾內容操作出錯"; } } /** * 移動文件 * * @param oldPath * @param newPath * @return */ public static void moveFile(String oldPath, String newPath) { copyFile(oldPath, newPath); delFile(oldPath); } /** * 移動目錄 * * @param oldPath * @param newPath * @return */ public static void moveFolder(String oldPath, String newPath) { copyFolder(oldPath, newPath); delFolder(oldPath); } /** * 得到錯誤信息 */ public static String getMessage() { return message; } }
測試:
package com.zhangguo.demo1; import java.io.File; import java.util.Date; public class FileDemo07 { public static void main(String[] args) throws Exception { String path = "e:" + File.separator + "file07.txt"; if (FileUtil2.writeTxtFile("當前時間:"+new Date().toString(), path)) { System.out.println(FileUtil.readFile(path)); System.out.println(FileUtil2.readTxt(path, "UTF-8")); } } }
結果:
當前時間:Fri Jul 20 10:37:07 CST 2018
當前時間:Fri Jul 20 10:37:07 CST 2018
更多封裝:

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import javax.servlet.http.HttpServletResponse; /** * <p>文件操作工具類<p> * @version 1.0 * @author li_hao * @date 2017年1月18日 */ @SuppressWarnings({"resource","unused"}) public class FileUtils { /** * 獲取windows/linux的項目根目錄 * @return */ public static String getConTextPath(){ String fileUrl = Thread.currentThread().getContextClassLoader().getResource("").getPath(); if("usr".equals(fileUrl.substring(1,4))){ fileUrl = (fileUrl.substring(0,fileUrl.length()-16));//linux }else{ fileUrl = (fileUrl.substring(1,fileUrl.length()-16));//windows } return fileUrl; } /** * 字符串轉數組 * @param str 字符串 * @param splitStr 分隔符 * @return */ public static String[] StringToArray(String str,String splitStr){ String[] arrayStr = null; if(!"".equals(str) && str != null){ if(str.indexOf(splitStr)!=-1){ arrayStr = str.split(splitStr); }else{ arrayStr = new String[1]; arrayStr[0] = str; } } return arrayStr; } /** * 讀取文件 * * @param Path * @return */ public static String ReadFile(String Path) { BufferedReader reader = null; String laststr = ""; try { FileInputStream fileInputStream = new FileInputStream(Path); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); reader = new BufferedReader(inputStreamReader); String tempString = null; while ((tempString = reader.readLine()) != null) { laststr += tempString; } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return laststr; } /** * 獲取文件夾下所有文件的名稱 + 模糊查詢(當不需要模糊查詢時,queryStr傳空或null即可) * 1.當路徑不存在時,map返回retType值為1 * 2.當路徑為文件路徑時,map返回retType值為2,文件名fileName值為文件名 * 3.當路徑下有文件夾時,map返回retType值為3,文件名列表fileNameList,文件夾名列表folderNameList * @param folderPath 路徑 * @param queryStr 模糊查詢字符串 * @return */ public static HashMap<String, Object> getFilesName(String folderPath , String queryStr) { HashMap<String, Object> map = new HashMap<>(); List<String> fileNameList = new ArrayList<>();//文件名列表 List<String> folderNameList = new ArrayList<>();//文件夾名列表 File f = new File(folderPath); if (!f.exists()) { //路徑不存在 map.put("retType", "1"); }else{ boolean flag = f.isDirectory(); if(flag==false){ //路徑為文件 map.put("retType", "2"); map.put("fileName", f.getName()); }else{ //路徑為文件夾 map.put("retType", "3"); File fa[] = f.listFiles(); queryStr = queryStr==null ? "" : queryStr;//若queryStr傳入為null,則替換為空(indexOf匹配值不能為null) for (int i = 0; i < fa.length; i++) { File fs = fa[i]; if(fs.getName().indexOf(queryStr)!=-1){ if (fs.isDirectory()) { folderNameList.add(fs.getName()); } else { fileNameList.add(fs.getName()); } } } map.put("fileNameList", fileNameList); map.put("folderNameList", folderNameList); } } return map; } /** * 以行為單位讀取文件,讀取到最后一行 * @param filePath * @return */ public static List<String> readFileContent(String filePath) { BufferedReader reader = null; List<String> listContent = new ArrayList<>(); try { reader = new BufferedReader(new FileReader(filePath)); String tempString = null; int line = 1; // 一次讀入一行,直到讀入null為文件結束 while ((tempString = reader.readLine()) != null) { listContent.add(tempString); line++; } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } return listContent; } /** * 讀取指定行數據 ,注意:0為開始行 * @param filePath * @param lineNumber * @return */ public static String readLineContent(String filePath,int lineNumber){ BufferedReader reader = null; String lineContent=""; try { reader = new BufferedReader(new FileReader(filePath)); int line=0; while(line<=lineNumber){ lineContent=reader.readLine(); line++; } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } return lineContent; } /** * 讀取從beginLine到endLine數據(包含beginLine和endLine),注意:0為開始行 * @param filePath * @param beginLineNumber 開始行 * @param endLineNumber 結束行 * @return */ public static List<String> readLinesContent(String filePath,int beginLineNumber,int endLineNumber){ List<String> listContent = new ArrayList<>(); try{ int count = 0; BufferedReader reader = new BufferedReader(new FileReader(filePath)); String content = reader.readLine(); while(content !=null){ if(count >= beginLineNumber && count <=endLineNumber){ listContent.add(content); } content = reader.readLine(); count++; } } catch(Exception e){ } return listContent; } /** * 讀取若干文件中所有數據 * @param listFilePath * @return */ public static List<String> readFileContent_list(List<String> listFilePath) { List<String> listContent = new ArrayList<>(); for(String filePath : listFilePath){ File file = new File(filePath); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); String tempString = null; int line = 1; // 一次讀入一行,直到讀入null為文件結束 while ((tempString = reader.readLine()) != null) { listContent.add(tempString); line++; } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } } return listContent; } /** * 文件數據寫入(如果文件夾和文件不存在,則先創建,再寫入) * @param filePath * @param content * @param flag true:如果文件存在且存在內容,則內容換行追加;false:如果文件存在且存在內容,則內容替換 */ public static String fileLinesWrite(String filePath,String content,boolean flag){ String filedo = "write"; FileWriter fw = null; try { File file=new File(filePath); //如果文件夾不存在,則創建文件夾 if (!file.getParentFile().exists()){ file.getParentFile().mkdirs(); } if(!file.exists()){//如果文件不存在,則創建文件,寫入第一行內容 file.createNewFile(); fw = new FileWriter(file); filedo = "create"; }else{//如果文件存在,則追加或替換內容 fw = new FileWriter(file, flag); } } catch (IOException e) { e.printStackTrace(); } PrintWriter pw = new PrintWriter(fw); pw.println(content); pw.flush(); try { fw.flush(); pw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } return filedo; } /** * 寫文件 * @param ins * @param out */ public static void writeIntoOut(InputStream ins, OutputStream out) { byte[] bb = new byte[10 * 1024]; try { int cnt = ins.read(bb); while (cnt > 0) { out.write(bb, 0, cnt); cnt = ins.read(bb); } } catch (IOException e) { e.printStackTrace(); } finally { try { out.flush(); ins.close(); out.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 判斷list中元素是否完全相同(完全相同返回true,否則返回false) * @param list * @return */ private static boolean hasSame(List<? extends Object> list){ if(null == list) return false; return 1 == new HashSet<Object>(list).size(); } /** * 判斷list中是否有重復元素(無重復返回true,否則返回false) * @param list * @return */ private static boolean hasSame2(List<? extends Object> list){ if(null == list) return false; return list.size() == new HashSet<Object>(list).size(); } /** * 增加/減少天數 * @param date * @param num * @return */ public static Date DateAddOrSub(Date date, int num) { Calendar startDT = Calendar.getInstance(); startDT.setTime(date); startDT.add(Calendar.DAY_OF_MONTH, num); return startDT.getTime(); } }
5.2、commons-io
commons-io是一款處理io流的工具,封裝了很多處理io流和文件的方法,可以大大簡化我們處理io流和操作文件的代碼。從common-io的官方使用文檔可以看出,它主要分為工具類、尾端類、行迭代器、文件過濾器、文件比較器和擴展流。
官網:http://commons.apache.org/proper/commons-io/
下載 :http://commons.apache.org/proper/commons-io/download_io.cgi
5.2.1、工具類
工具類包括FileUtils、IOUtils、FilenameUtils和FileSystemUtils,前三者的方法並沒有多大的區別,只是操作的對象不同,故名思議:FileUtils主要操作File類,IOUtils主要操作IO流,FilenameUtils則是操作文件名,FileSystemUtils包含了一些JDK沒有提供的用於訪問文件系統的實用方法。當前,只有一個用於讀取硬盤空余空間的方法可用。實例如下
FileUtils的使用:
import java.io.File; import java.io.IOException; import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; public class FileUtilsTest { private String basePath = null; @Before public void setUp() { basePath = System.getProperty("user.dir") + "\\file\\"; } @After public void tearDown() throws Exception { } /** * 拷貝文件 * @throws IOException */ @Test public void testCopy() throws IOException { File srcFile = new File(basePath + "a.txt"); File destFile = new File(basePath + "b.txt"); FileUtils.copyFile(srcFile, destFile); } /** * 刪除文件 * @throws IOException */ @Test public void testDelete() throws IOException{ File delFile = new File(basePath + "b.txt"); FileUtils.forceDelete(delFile); //FileUtils.forceMkdir(delFile); } /** * 比較文件內容 * @throws IOException */ @Test public void testCompareFile() throws IOException{ File srcFile = new File(basePath + "a.txt"); File destFile = new File(basePath + "b.txt"); boolean result = FileUtils.contentEquals(srcFile, destFile); System.out.println(result); } /** * 移動文件 * @throws IOException */ @Test public void testMoveFile() throws IOException{ File srcFile = new File(basePath + "b.txt"); File destDir = new File(basePath + "move"); FileUtils.moveToDirectory(srcFile, destDir, true); } /** * 讀取文件內容 * @throws IOException */ @Test public void testRead() throws IOException{ File srcFile = new File(basePath + "a.txt"); String content = FileUtils.readFileToString(srcFile); List<String> contents = FileUtils.readLines(srcFile); System.out.println(content); System.out.println("******************"); for (String string : contents) { System.out.println(string); } } /** * 寫入文件內容 * @throws IOException */ @Test public void testWrite() throws IOException{ File srcFile = new File(basePath + "a.txt"); FileUtils.writeStringToFile(srcFile, "\nyes文件", true); } }
測試:
package com.zhangguo.demo1; import java.io.File; import org.apache.commons.io.FileUtils; public class FileDemo07 { public static void main(String[] args) throws Exception { String path = "e:" + File.separator + "file08.txt"; FileUtils.write(new File(path), "org.apache.commons.io\r\n","utf-8", true); String result=FileUtils.readFileToString(new File(path), "utf-8"); System.out.println(result); } }
結果:
org.apache.commons.io
org.apache.commons.io
org.apache.commons.io
六、IO流應用
6.1、下載文件
1. 下載就是向客戶端響應字節數據!
原來我們響應的都是html的字符數據!
把一個文件變成字節數組,使用response.getOutputStream()來各應給瀏覽器。
2. 下載的要求
* 兩個頭一個流!
> Content-Type:你傳遞給客戶端的文件是什么MIME類型,例如:image/pjpeg
通過文件名稱調用ServletContext的getMimeType()方法,得到MIME類型!
> Content-Disposition:它的默認值為inline,表示在瀏覽器窗口中打開!attachment;filename=xxx
在filename=后面跟隨的是顯示在下載框中的文件名稱!
> 流:要下載的文件數據!
自己new一個輸入流即可!
示例一:
Servlet:
package com.zhangguo.controller; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 下載 */ @WebServlet("/Download") public class Download extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = request.getParameter("filename"); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); //獲得要下載的文件路徑 String path=getServletContext().getRealPath(filename); System.out.println(path); //獲得文件名 //H:\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\AjaxResult\images\12.jpg String name=path.substring(path.lastIndexOf("\\")+1); //轉碼 name=URLEncoder.encode(name,"utf-8"); //修改http頭部,設置輸出為附件 response.setHeader("Content-Disposition", "attachment;filename="+name); //輸入流,獲得文件的字節流 InputStream is=new FileInputStream(path); byte[] bytes=new byte[is.available()]; is.read(bytes); //將字節流寫入response中 response.getOutputStream().write(bytes); is.close(); response.flushBuffer(); response.getOutputStream().flush(); } }
HTML:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <p> <a href="Download?filename=images/猴哥.jpg">下載猴哥0</a><br /> <a href="Download?filename=images/12.jpg">下載圖片1</a><br /> <a href="Download?filename=images/11.jpg">下載圖片2</a><br /> <a href="Download?filename=images/10.jpg">下載圖片3</a> </p> <p> <a href="Download?filename=LICENSE.txt">下載文本</a> </p> <P> <a href="DownloadXLS">導出xls</a> </P> </body> </html>
結果:
示例二:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //處理請求 //讀取要下載的文件 File f = new File("E:/好久不見.mp3"); if(f.exists()){ FileInputStream fis = new FileInputStream(f); String filename=URLEncoder.encode(f.getName(),"utf-8"); //解決中文文件名下載后亂碼的問題 byte[] b = new byte[fis.available()]; fis.read(b); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition","attachment; filename="+filename+""); //獲取響應報文輸出流對象 ServletOutputStream out =response.getOutputStream(); //輸出 out.write(b); out.flush(); out.close(); } }
示例三:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //通過路徑得到一個輸入流 String path = this.getServletContext().getRealPath("/WEB-INF/classes/1.jpg"); FileInputStream fis = new FileInputStream(path); //創建字節輸出流 ServletOutputStream sos = response.getOutputStream(); //得到要下載的圖片文件名 String filename = path.substring(path.lastIndexOf("\\"+1)); //告訴客戶端需要下載圖片(通過響應消息頭) response.setHeader("content-disposition", "attachment;filename="+filename); //告訴客戶端下載文件的類型 response.setHeader("content-type", "image/jpeg"); //執行輸出操作 int len = 1; byte[] b = new byte[1024]; while((len=fis.read(b)) != -1){ sos.write(b,0,len); } sos.close(); fis.close(); }
示例四:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 給下載文件命名 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYYMMddHHmmss"); String s = simpleDateFormat.format(new Date()); String fileName = s+".zip"; // 下載必須設置頭 response.setHeader("content-disposition", "attachment;filename="+fileName); // 獲得文件 InputStream is = this.getServletContext().getResourceAsStream("/config/new.zip"); // 輸出流 OutputStream os = response.getOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len=is.read(buffer))!=-1) { os.write(buffer, 0, len); } os.close(); is.close(); }
6.2、導出Excel文件
這里特別需要注意亂碼的問題
示例:
Servlet:
package com.zhangguo.controller; import java.io.IOException; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 下載 */ @WebServlet("/DownloadXLS") public class DownloadXLS extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = request.getParameter("filename"); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); // 寫入bom頭 byte[] uft8bom={(byte)0xef,(byte)0xbb,(byte)0xbf}; String name=URLEncoder.encode("月度收入報表.csv","utf-8"); //修改http頭部,設置輸出為附件 response.setHeader("Content-Disposition", "attachment;filename="+name); String result="日期,收入\r\n"; for (int i = 1; i <=10; i++) { result+="2018-06-"+i+","+(i*10)+"萬\r\n"; } result=new String(result.getBytes(),"utf-8"); //將字節流寫入response中 response.getOutputStream().write(uft8bom); //寫入頭部解決亂碼問題 response.getOutputStream().write(result.getBytes()); response.flushBuffer(); response.getOutputStream().flush(); } }
HTML
<a href="DownloadXLS">導出xls</a>
結果:
七、視頻
https://www.bilibili.com/video/av9219224/
八、作業
8.1、在c:\log目錄下創建一個文件hello.html,存在就重命名為當前年月日.html,不存在就創建。
8.2、遞歸顯示目錄結構下的所有信息,如下圖所示
8.3、請完成一個簡單的新聞發布系統,實現動態頁面的靜態化,要求前端全部使用后台生成,如新聞列表,新聞詳細,數據要求存放到數據庫,至少有10條以上的新聞,每篇至少500字以上。
新聞列表:
新聞詳細:
8.4、在8.3的每一條新聞列表后增加一個下載圖標鏈接,點擊時將html文件下載到本地。
8.5、將項目中的任意一個表的數據顯示在界面上,點擊搜索后可以實現導出功能,導出時要根據搜索條件過濾出要導出的數據,不應該全部導出。
參考:
https://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html
https://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html
https://www.cnblogs.com/pepcod/archive/2013/01/20/2913435.html