Java IO流常用操作方法總結
一、簡介
在實際工作中,基本上每個專案難免都會有檔案相關的操作,比如檔案上傳、檔案下載等,這些操作都是使用IO流進行操作的,本文將通過簡單的示例對常用的一些IO流進行總結。
二、使用詳解
【a】FileInputStream與FileOutputStream
首先通過檢視jdk文件,瞭解下FileInputStream與FileOutputStream的操作方法:
FileInputStream:
FileOutputStream:
輸入流主要是通過read讀取檔案,輸出流主要是通過write寫出到檔案。
下面以檔案拷貝的示例說明FileinputStream與FileOutputStream的使用方法:
public class CopyFileUtils { /** * * @param sourceFile * @param destFile * @throws IOException */ public static void copyFile(File sourceFile, File destFile) throws IOException { //1. 原始檔必須存在並且是檔案 if (!sourceFile.exists() || !sourceFile.isFile()) { System.out.println("原始檔必須存在並且是檔案"); return; } if (destFile.isDirectory()) { return; } //2. 建立與檔案的聯絡 InputStream is = new FileInputStream(sourceFile); OutputStream os = new FileOutputStream(destFile); //實際接收長度 int len = 0; //緩衝位元組陣列 byte[] buffer = new byte[1024]; //3. 迴圈讀取檔案 while ((len = is.read(buffer)) != -1) { //4. 通過OutputStream寫出到檔案 os.write(buffer, 0, len); } // 5. 關閉流 os.flush(); os.close(); is.close(); } public static void copyFile(String sourcePath, String destPath) throws IOException { //1. 原始檔、目標檔案建立聯絡 File sourceFile = new File(sourcePath); File destFile = new File(destPath); copyFile(sourceFile, destFile); } }
測試:
public class TestCopyFileUtils {
public static void main(String[] args) {
try {
CopyFileUtils.copyFile("d:/aaa/a.txt", "d:/aaa/b.txt");
} catch (IOException e) {
System.out.println("檔案拷貝失敗!");
e.printStackTrace();
}
}
}
執行結果:
下面以資料夾拷貝的示例來鞏固FileinputStream與FileOutputStream的使用方法:
public class CopyDirUtils {
public static void copyDir(String sourcePath, String destPath) throws IOException {
//1. 建立與檔案的聯絡
File sourceFile = new File(sourcePath);
File destFile = new File(destPath);
//如果原始檔是一個資料夾
if (sourceFile.isDirectory()) {
destFile = new File(destFile, sourceFile.getName());
}
copyDirDetail(sourceFile, destFile);
}
private static void copyDirDetail(File sourceFile, File destFile) throws IOException {
//2. 如果原始檔是一個檔案,則直接拷貝即可
if (sourceFile.isFile()) {
//拷貝檔案
CopyFileUtils.copyFile(sourceFile, destFile);
} else if (sourceFile.isDirectory()) {
//3. 如果原始檔是一個資料夾,那麼需要確保目標資料夾存在
destFile.mkdirs();
//4. 使用listFiles遞迴呼叫copyDirDetail拷貝資料夾以及子檔案
for (File subFile : sourceFile.listFiles()) {
copyDirDetail(subFile, new File(destFile, subFile.getName()));
}
}
}
}
測試:
public class TestCopyDirUtils {
public static void main(String[] args) throws IOException {
String sourcePath = "d:/aaa";
String destPath = "d:/bbb";
CopyDirUtils.copyDir(sourcePath, destPath);
}
}
執行結果:
【b】FileReader與FileWriter
FileReader與FileWriter並沒有新增的方法,跟上面的用法基本類似,只是FileReader與FileWriter只能讀取純文字的檔案。
下面分別講解FileReader與FileWriter的基礎用法:
/**
* @Description: 純文字讀取
* @Author: weishihuai
* @Date: 2018/11/1 20:40
*/
public class FileReaderAndFileWriter {
public static void main(String[] args) {
//先寫內容到檔案
writeFile();
//再讀取出來
readFile();
}
/**
* 把內容輸出到檔案
*/
public static void writeFile() {
//1. 需要寫出的目標檔案路徑
File file = new File("d:/aaa/b.txt");
Writer writer = null;
try {
//2. 建立與目標檔案的聯絡
writer = new FileWriter(file);
//3. 使用write()直接寫出字串(只能寫出純文字內容)
writer.write("hello world!!!!!!!!!");
//4. 重新整理流
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
//5. 關閉流
if (null != writer) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 讀取檔案中的內容
*/
public static void readFile() {
//1. 定義原始檔路徑
File file = new File("d:/aaa/b.txt");
Reader reader = null;
try {
//2. 建立與原始檔的聯絡
reader = new FileReader(file);
//3. 字元快取陣列
char[] buffer = new char[1024];
//4. 定義實際接收長度
int len = 0;
//5. 迴圈讀取檔案內容
while (-1 != (len = reader.read(buffer))) {
System.out.println(new String(buffer));
}
} catch (java.io.IOException e) {
e.printStackTrace();
System.out.println("原始檔讀取失敗");
} finally {
//6. 關閉流
if (null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("關閉流失敗");
}
}
}
}
}
執行結果:
【c】BufferedInputStream與BufferedOutStream
BufferedInputStream與BufferedOutStream是位元組處理流,起到增強功能, 提高效能的作用。(推薦使用)
BufferedInputStream與BufferedOutStream的使用方法並沒有太大區別,只是在原來FileInputStream與FileOutputStream的外層包裹一個處理流BufferInputStream與BufferOutStream而已,使用方法如下:
/**
* @Description: 位元組處理流(增強功能, 提高效能, 處理流一定要在節點流之上)
* @Author: weishihuai
* @Date: 2018/11/1 20:56
*/
public class BufferInputStreamAndBufferOutStream {
public static void main(String[] args) {
//1.建立與原始檔、目標檔案的聯絡
File sourceFile = new File("d:/aaa/a.txt");
File destFile = new File("d:/aaa/aa.txt");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
//在外層包裹一層處理流,加強功能
inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
outputStream = new BufferedOutputStream(new FileOutputStream(destFile));
//2. 定義緩衝位元組陣列以及實際接收長度len
byte[] buffer = new byte[1024];
int len = 0;
//3. 迴圈讀取檔案中的內容
while (-1 != (len = inputStream.read(buffer))) {
//4.通過write將讀取的內容寫出到檔案中
outputStream.write(buffer, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//5. 關閉流
if (null != outputStream) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
執行結果:
【d】BufferedReader與BufferedWriter
新增方法如下,其他方法都是從Reader或者Writer繼承過來
BufferedReader:readLine() 讀取一個文字行。
BufferedWriter:newLine() 寫入一個行分隔符。
下面還是通過一個簡單的示例講解BufferedReader與BufferedWriter的使用方法:
public class BufferReaderAndBufferWriter {
public static void main(String[] args) {
//1. 建立與原始檔、目標檔案的聯絡
File sourceFile = new File("d:/aaa/a.txt");
File destFile = new File("d:/aaa/c.txt");
BufferedReader reader = null;
BufferedWriter writer = null;
try {
//2. 使用BufferedReader和BufferedWriter包裹FileReader和FileWriter
//注意: 只能讀取純文字檔案
reader = new BufferedReader(new FileReader(sourceFile));
writer = new BufferedWriter(new FileWriter(destFile));
//3. 定義實際接收的字串
String str;
//4. 使用reader.readLine()一行一行迴圈讀取
while (null != (str = reader.readLine())) {
//5. 使用write()直接寫出字串到檔案c.txt
writer.write(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6. 關閉流
if (null != writer) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
執行結果:
【e】InputStreamReader與OutputStreamWriter
轉換流,主要用於解決檔案讀取或者寫入出現的亂碼問題。
出現亂碼的問題一般有兩種:
(1) 編碼與解碼的字符集不統一
(2) 位元組數不夠,長度丟失
下面我們通過示例講解怎麼解決亂碼問題:
/**
* @Description: 轉換流(位元組流 轉換為 字元流)
* @Author: weishihuai
* @Date: 2018/11/1 21:22
* <p>
* 轉換流: 主要用於解決亂碼問題(保證原始檔的編碼集已知)
*/
public class InputStreamReaderAndOutputStreamWriter {
public static void main(String[] args) throws IOException {
//1. 指定解碼字符集
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("d:/aaa/c.txt")), "utf-8"));
//2. 定義實際接收字串
String string;
//3. 一行一行讀取純文字檔案內容
while (null != (string = reader.readLine())) {
System.out.println(string);
}
}
}
如圖,我們檔案的編碼為ANSI編碼,我們指定的解碼字符集為UTF-8,執行結果:
下面我們修改一下c.txt的編碼字符集為UTF-8,再次執行程式,
如圖,通過指定相同的編碼與解碼字符集,亂碼問題就解決了。
【f】ByteArrayInputStream與ByteArrayOutputStream
ByteArrayInputStream與ByteArrayOutputStream是位元組陣列輸入輸出流,主要是將位元組陣列輸出到檔案中,再通過讀取檔案中的位元組陣列將內容讀取出來。
/**
* @Description: 位元組陣列流 位元組流
* @Author: weishihuai
* @Date: 2018/11/2 20:43
*/
public class ByteArrayInputStreamAndByteArrayOutputStream {
public static void read(byte[] bytes) {
ByteArrayInputStream bis = null;
//1. 實際接收長度
int len = 0;
//位元組陣列
byte[] bytes1 = new byte[1024];
try {
//2. 建立位元組陣列輸入流
bis = new ByteArrayInputStream(bytes);
//3. 迴圈將檔案中的位元組陣列讀取出來
while (-1 != (len = bis.read(bytes1))) {
System.out.println(new String(bytes1));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 關閉流
if (null != bis) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static byte[] write() {
//位元組陣列
byte[] dest;
String string = "位元組陣列流 位元組流 節點流";
//需要寫入檔案的位元組陣列
byte[] bytes = string.getBytes();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//使用write將位元組陣列寫入到檔案中
bos.write(bytes, 0, bytes.length);
//使用toByteArray()將輸出流轉化為位元組陣列
dest = bos.toByteArray();
return dest;
}
public static void main(String[] args) {
// read();
read(write());
}
}
執行結果:
下面通過示例講解位元組陣列流與檔案流對接:
/**
* @Description: 位元組陣列流與檔案流對接
* @Author: weishihuai
* @Date: 2018/11/2 20:57
*/
public class ByteArrayToStream {
public static void main(String[] args) {
byte[] bytes = getBytesFromFile("d:aaa/a.txt");
System.out.println(new String(bytes));
toFileFromByteArray(bytes, "d:/aaa/t.txt");
}
/**
* 從檔案中讀取到位元組陣列流中(檔案輸入流讀取檔案/位元組陣列輸出流將檔案寫出到位元組陣列)
*
* @param sourcePath 原始檔路徑
* @return
*/
public static byte[] getBytesFromFile(String sourcePath) {
File sourceFile = new File(sourcePath);
byte[] dest;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
is = new BufferedInputStream(new FileInputStream(sourceFile));
bos = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte[1024];
while (-1 != (len = is.read(buffer))) {
bos.write(buffer, 0, buffer.length);
}
bos.flush();
dest = bos.toByteArray();
return dest;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != bos) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* 位元組陣列輸出到檔案(位元組陣列輸入流將位元組陣列讀取出來/檔案輸出流將位元組陣列寫出到檔案儲存)
*
* @param bytes 位元組陣列
*/
public static void toFileFromByteArray(byte[] bytes, String destPath) {
OutputStream os = null;
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
int len = 0;
byte[] buffer = new byte[1024];
try {
os = new FileOutputStream(new File(destPath));
while (-1 != (len = bis.read(buffer))) {
os.write(buffer, 0, len);
}
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != bis) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != os) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
執行結果:
三、總結
以上是工作中常用的IO流操作檔案的方法,具體可以根據實際情況進行調整,本文是筆者在複習IO操作方法的一些總結,僅供大家學習參考,大家可以進行進一步優化,一起學習一起進步。