Java IO流学习指南:从小白到入门
Java的IO(Input/Output)流是处理数据输入和输出的基础。无论是读取文件、写入文件,还是通过网络传输数据,IO流都无处不在。对于刚接触Java的新手,理解IO流可能会有些困惑,但别担心,今天我们将一步步走过它,让你从一个小白变成IO流的小达人!
一、什么是IO流?
在Java中,IO流是指数据流向的方向,它包括了输入流(InputStream)和输出流(OutputStream)两大类。
-
输入流(InputStream):用于读取数据的流,例如从文件、键盘或网络中读取数据。
-
输出流(OutputStream):用于向目标写入数据的流,比如将数据写入文件、控制台或网络中。
IO流的核心概念就是“数据流向”,可以理解为你从某个地方读取数据,或者将数据写入到某个地方。
二、IO流的分类
Java中的IO流有很多种,按用途大致可以分为两大类:
-
字节流(Byte Stream):处理所有类型的I/O,适用于所有类型的数据(包括图片、音频、视频等二进制数据)。字节流的父类是
InputStream
和OutputStream
。 -
字符流(Character Stream):专门用于处理文本数据(即字符数据),它是对字节流的封装,采用字符编码方式来读取和写入文本数据。字符流的父类是
Reader
和Writer
。
详细解释
所谓这些流就是一个链接文件的管道,字节,字符流,就是代表在管道里面流转的数据不一样输入流就是将文件内容通过管道发送到程序。输出流就是从程序写入到文件里面。流的分类按照流的方向:输入流、输出流按照流的内容:字节流、字符流
字节流:适合操作所有类型的文件 字符流:适合操作纯文本文件
他们之间组合形成了四个类
字节输入流 FileInputStream
字符输出流 FileOutputStream
字符输入流 FileReader
字符输出流 FileWriter他们都继承两个基类 InputStream OutputStream他们本质就是一些对象,拥有一些操作数据的方法。
创建对象
字节输入流为例
FileOutputStream fos = new FileOutputStream("文件路径");
其他就是替换类名就行了。也可以利用多态写法,换成基类
注意:绝对路径和相对路径的差别,在开发多人项目的时候一般使用相对路径,就是在你的项目中的路径。
绝对路径就是存放在磁盘的路径,但当你拿别人的项目的时候一旦文件存放的磁盘不一样就会抛出异常。方法:字符和字节一样都有方法
读入方法,单个字节读入int b = fos.read();int b;while((b=is.read())!=-1){System.out.print((char)b);}
这样效率非常慢,而且不能存放汉字,因为一个汉字的字节占位不是一,
我们一般利用数组传入,一次性传多个byte[] buffer = new byte[5];
int len;//定义一个变量记住每次读取了多少个字节,因为有可能都不满数组。
while((len=is.read(buffer))!=-1){ System.out.print(new String(buffer,0,len));//解释一下,len是每次读取的字节数,//即从0开始,截取len个字节,转换成字符串输出//String s = new String(buffer);// System.out.println(s);//这样写的话,每次都会将buffer中的字节全部转换成字符串,如果源文件只有4个字节,那么就会将buffer中多余的字节转换成乱码 //但是无法解决乱码问题。//解决方法,一次读完所以的字节,只适合小文件,大文件可能会造成内存溢出//readAllBytes()//读取文件所有字节//byte[] bytes = is.readAllBytes();//System.out.println(new String(bytes));
文件字节输出流 FileOutputStream作用:将数据写入文件覆盖管道,会覆盖原来的数据FileOutputStream fos = new FileOutputStream("路径");//与字节输入流一样,也有一个字节输出流管道与源文件路径接通//FileOutputStream(File file)//与源文件路径接通(一般用)//FileOutputStream(String path)//写数据文件会自动创建文件FileOutputStream fos = new FileOutputStream("file_io_stream\\src\\text02.txt");//同样的文件字节输出流也有将读到文件里面的方法,但是和输入流也存在乱码问题,解决方式也一样//一个字节写入一个字节 write()fos.write('9');//也有数组方式byte[] bytess = {97,98,99,100};//将文字编码成字节byte[] bytesss = "我爱中国".getBytes();fos.write(bytesss);fos.write(bytess);//也能写一部分字节数组出去//将字节1-2写出去//但是在写汉字的时候依然会有乱码问题//write(字节数组,起始位置,写多少个字节出去)fos.write(bytesss,0,9);//但是这样写是将文件清空在写的,所以不能重复写入。//要追加添加文件,需要使用带参数的构造方法//追加参数,追加数据FileOutputStream fos1 = new FileOutputStream("file_io_stream\\src\\text02.txt",true);//注意在这些流用完后一定要关闭流fos.close();fos1.close();
但是我们流在使用后必须关闭,但是一定程序在流关闭之前就抛出异常,导致流没有关闭,造成内存泄漏所以我们规定了流的写法格式
try(){
}catch()
{
}
try(只能放置资源对象,用完后最终会自动调用close方法FileInputStream fis=new FileInputStream(src);FileOutputStream fos=new FileOutputStream(dest,true);){byte[] buf=new byte[1024];int len;while((len=fis.read(buf))!=-1){fos.write(buf,0,len);//读取多少字节就写多少字节}}catch (Exception e){e.printStackTrace();}}
字符和字节完全一样,只是方法的名称有些不一样
读入
try( FileReader fr = new FileReader("file_io_stream\\src\\zi_fu_stream\\zi_fu_text");){char [] cbuf = new char[1024];//不建议单个字符读入,会拖累程序int b;while((b = fr.read(cbuf)) != -1){//打印出来System.out.print(new String(cbuf,0,b));}//字符没有全部读入方式//拓展:文件字符输入流每次读多个字符,性能较好,而且读中文没有乱码}catch (Exception e){e.printStackTrace();}
输出
//五个方法//write(char c)//写入一个字符//write(String str)//写入一个字符串//write(char[] cbuf)//写入一个字符数组//write(char[] cbuf,int off,int len)//写入一个字符数组的一部分//flush()//刷新缓冲区,将数据写入文件
我们一般就使用字符串
缓冲流
认识缓冲流缓冲字节输入流 BufferedInputStream缓冲字节输出流BufferedOutputStream缓冲字符输入流 BufferedReader缓冲字符输出流 BufferedWriter
其实就是提高性能而且,在外面套了一层壳使用方法一模一样就是换了类名
字符缓冲输入流新增功能:按照行读取字符
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {String line;while ((line = reader.readLine()) != null) {// 处理每一行}} catch (IOException e) {e.printStackTrace();}
三、简单的字节流示例
先从一个最基础的例子开始:用字节流读取和写入文件。
1. 读取文件内容
import java.io.FileInputStream;
import java.io.IOException;
public class FileReaderExample {public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("input.txt")) {int byteData;while ((byteData = fis.read()) != -1) {System.out.print((char) byteData);}} catch (IOException e) {e.printStackTrace();}}
}
解释:
-
FileInputStream
是字节流的一个例子,用来读取文件数据。 -
fis.read()
方法逐个字节读取文件的内容。 -
try-with-resources
语法可以自动关闭资源,避免手动关闭。
2. 写入文件内容
import java.io.FileOutputStream;
import java.io.IOException;
public class FileWriterExample {public static void main(String[] args) {try (FileOutputStream fos = new FileOutputStream("output.txt")) {String message = "Hello, Java IO!";fos.write(message.getBytes()); // 将字符串转换为字节数组并写入文件} catch (IOException e) {e.printStackTrace();}}
}
解释:
-
FileOutputStream
用于将数据写入文件。 -
write()
方法将字节数据写入文件。
四、简单的字符流示例
字符流适用于文本文件的读取和写入,它会自动进行字符编码的转换。
1. 读取文本文件
import java.io.FileReader;
import java.io.IOException;
public class FileReaderExample {public static void main(String[] args) {try (FileReader fr = new FileReader("input.txt")) {int charData;while ((charData = fr.read()) != -1) {System.out.print((char) charData); // 输出每个字符}} catch (IOException e) {e.printStackTrace();}}
}
2. 写入文本文件
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterExample {public static void main(String[] args) {try (FileWriter fw = new FileWriter("output.txt")) {String message = "Hello, Java IO with Character Streams!";fw.write(message); // 直接写入字符串} catch (IOException e) {e.printStackTrace();}}
}
五、常用的IO流类和方法
-
FileInputStream/FileOutputStream:用于字节流读写文件。
-
FileReader/FileWriter:用于字符流读写文件。
-
BufferedReader/BufferedWriter:用于高效地读取和写入字符数据,适合处理大量文本数据。
1. 使用 BufferedReader
读取文件
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderExample {public static void main(String[] args) {try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {String line;while ((line = br.readLine()) != null) {System.out.println(line); // 逐行读取文件内容}} catch (IOException e) {e.printStackTrace();}}
}
2. 使用 BufferedWriter
写入文件
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterExample {public static void main(String[] args) {try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {String message = "Buffered Writer Example";bw.write(message); // 写入内容} catch (IOException e) {e.printStackTrace();}}
}
六、IO流的实际应用场景
-
读取和写入文件:最常见的应用,比如读取配置文件、写入日志文件等。
-
网络通信:通过Socket连接进行网络数据的发送和接收。
-
数据加密与解密:处理加密文件的读取和写入。
-
多线程并发访问文件:使用IO流结合多线程技术,处理并发文件操作。
最后介绍一下io框架
commons-io.jar
为了简化上面的方法,io框架将上面的内容封装成了一个个内容,方便我们直接调用,说白了上面学了都没用,直接用框架就行,但是我们还是要掌握数据流动的方式。
1. IOUtils
处理输入/输出流的工具类。
方法列表与作用
方法 | 作用 |
---|---|
copy(InputStream, OutputStream) | 复制输入流到输出流(自动缓冲) |
toString(InputStream, Charset) | 将输入流内容转为字符串 |
readLines(InputStream, Charset) | 按行读取输入流为字符串列表 |
示例代码
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class IOUtilsExample {public static void main(String[] args) throws IOException {// 1. 复制流try (InputStream in = new FileInputStream("input.txt");OutputStream out = new FileOutputStream("output.txt")) {IOUtils.copy(in, out); // 将 input.txt 内容复制到 output.txt}
// 2. 输入流转字符串try (InputStream in = new FileInputStream("input.txt")) {String content = IOUtils.toString(in, StandardCharsets.UTF_8);System.out.println(content); // 输出文件内容}
// 3. 按行读取try (InputStream in = new FileInputStream("input.txt")) {List<String> lines = IOUtils.readLines(in, StandardCharsets.UTF_8);lines.forEach(System.out::println); // 逐行打印}}
}
2. FileUtils
文件操作工具类。
方法列表与作用
方法 | 作用 |
---|---|
readFileToString(File, Charset) | 读取文件内容为字符串 |
writeStringToFile(File, String, Charset) | 将字符串写入文件 |
copyFile(File, File) | 复制文件 |
copyDirectory(File, File) | 复制整个目录 |
deleteDirectory(File) | 递归删除目录 |
cleanDirectory(File) | 清空目录内容 |
示例代码
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
public class FileUtilsExample {public static void main(String[] args) throws IOException {// 1. 读取文件为字符串String content = FileUtils.readFileToString(new File("test.txt"), StandardCharsets.UTF_8);System.out.println(content);
// 2. 写入字符串到文件FileUtils.writeStringToFile(new File("output.txt"), "Hello Commons IO", StandardCharsets.UTF_8);
// 3. 复制文件FileUtils.copyFile(new File("source.txt"), new File("dest.txt"));
// 4. 复制目录FileUtils.copyDirectory(new File("srcDir"), new File("destDir"));
// 5. 删除目录FileUtils.deleteDirectory(new File("oldDir"));
// 6. 清空目录FileUtils.cleanDirectory(new File("tempDir"));}
}
3. FilenameUtils
文件路径处理工具类。
方法列表与作用
方法 | 作用 |
---|---|
getExtension(String) | 获取文件扩展名 |
removeExtension(String) | 移除文件扩展名 |
concat(String, String) | 安全拼接路径 |
示例代码
import org.apache.commons.io.FilenameUtils;
public class FilenameUtilsExample {public static void main(String[] args) {// 1. 获取扩展名String ext = FilenameUtils.getExtension("data.json"); // 返回 "json"
// 2. 移除扩展名String name = FilenameUtils.removeExtension("image.jpg"); // 返回 "image"
// 3. 路径拼接String fullPath = FilenameUtils.concat("/home/user", "docs/file.txt"); // 返回 "/home/user/docs/file.txt"
System.out.println(ext + ", " + name + ", " + fullPath);}
}
4. FileAlterationObserver
监控文件/目录变化的工具。
方法作用
-
监听文件创建、修改、删除事件。
示例代码
import org.apache.commons.io.monitor.*;
import java.io.File;
public class FileMonitorExample {public static void main(String[] args) throws Exception {File dir = new File("monitored_dir");FileAlterationObserver observer = new FileAlterationObserver(dir);observer.addListener(new FileAlterationListenerAdaptor() {@Overridepublic void onFileCreate(File file) {System.out.println("文件创建: " + file.getName());}@Overridepublic void onFileDelete(File file) {System.out.println("文件删除: " + file.getName());}});
FileAlterationMonitor monitor = new FileAlterationMonitor(1000); // 轮询间隔1秒monitor.addObserver(observer);monitor.start();
// 保持程序运行(实际应用可能需要线程管理)Thread.sleep(60_000);monitor.stop();}
}
关键说明
//这里涉及到Maven工程管理,意思就是在idea里面下载这个jar包,方便自己使用,可以在我的博客里面找有关于Maven工程的介绍
-
依赖引入:需在项目中添加 Commons IO 依赖(如 Maven):
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.13.0</version> </dependency>
-
异常处理:所有示例需处理
IOException
(此处简化为throws
)。 -
资源释放:使用
try-with-resources
确保流自动关闭。
通过这些示例,可以快速实现文件操作、流处理及目录监控功能。
七、总结
Java的IO流非常强大且灵活,掌握了它,你就能轻松地处理文件、网络等数据输入输出操作。虽然刚开始可能有些晦涩,但通过不断的实践和理解,你会逐步熟悉并掌握这些技术。
如果你有其他问题或需要更详细的案例,随时留言!希望这篇博客能帮助你顺利入门Java IO流。