一、简介
在实际工作中,基本上每个项目难免都会有文件相关的操作,比如文件上传、文件下载等,这些操作都是使用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操作方法的一些总结,仅供大家学习参考,大家可以进行进一步优化,一起学习一起进步。