文章有点长,大概需要阅读20分钟
IO
File类
构造函数
- File(File parent, String child)
- File(String pathname)
- File(String parent, String child)
方法
获取属性
public boolean isDirectory() 判断是否为文件夹
public boolean isFile() 判断是否为文件
public boolean exists() 判断File对象对应的文件或文件夹是否存在
操作方法
public boolean delete() 如果此路径名表示一个目录,则该目录必须为空才能删除
mkdirs() 创建多级目录,也可以创建单个目录.
获取目录中的文件或文件夹
常用listFiles
文件过滤器
继承FilenameFilter接口,实现accept方法.使用listFiles方法时传入FilenameFilter过滤器的实现类.listFiles会将list中的元素交给过滤器,过滤器返回true则保留元素,否则不保留元素.
例:
//获取path路径下所有文件夹
public class FileDemo {
public static void main(String[] args) {
//创建File对象
File file = new File(path);
//获取指定目录下的文件夹
File[] files = file.listFiles(new FileFileterByDir());
//遍历获取到的所有符合条件的文件
for (File f : files) {
System.out.println(f);
}
}
}
//过滤器类
class FileFileterByDir implements FileFilter{
public boolean accept(File pathname) {
return pathname.isDirectory();
}
}
IO流
IO流的分类
- 字节流
- 字节输入流 InputStream 抽象类
- FileInputStream 操作文件的字节输入流
- BufferedInputStream高效的字节输入流
- 字节输出流 OuputStream抽象类
- FileOutputStream 操作文件的字节输出流
- BufferedOutputStream 高效的字节输出流
- 字节输入流 InputStream 抽象类
- 字符流
- 字符输入流 Reader抽象类
- InputStreamReader 输入操作的转换流(把字节流封装成字符流)
- FileReader 用来操作文件的字符输入流(简便的流)
- BufferedReader 高效的字符输入流
- 字符输出流 Writer抽象类
- OutputStreamWriter 输出操作的转换流(把字节流封装成字符流)
- FileWriter 用来操作文件的字符输出流(简便的流)
- BufferedWriter 高效的字符输出流
- 字符输入流 Reader抽象类
字节流
字节输出流 OuputStream续写、换行、异常处理
public class FileOutputStreamDemo {
public static void main(String[] args) {
File file = new File(path);
//定义FileOutputStream的引用
FileOutputStream fos = null;
try {
//创建FileOutputStream对象,选择续写模式
fos = new FileOutputStream(file, true);
//写出数据,加入换行
fos.write("abcde/r/n".getBytes());
} catch (IOException e) {
System.out.println(e.toString() + "----");
} finally {
//一定要判断fos是否为null,只有不为null时,才可以关闭资源
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("");
}
}
}
}
}
字节输入流 InputStream 缓冲区
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
File file = new File(path);
// 创建一个字节输入流对象,明确数据源。
FileInputStream fis = new FileInputStream(file);
//创建一个字节数组,长度可以定义成1024的整数倍。
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
fis.close();
}
}
使用缓冲区复制文件
public class CopyFileByBufferTest {
public static void main(String[] args) throws IOException {
File srcFile = new File(srcpath);
File destFile = new File(destpath);
// 明确字节流和数据源相关联,输出流和目的源关联。
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//缓冲区
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
// 将数组中的指定长度的数据写入到输出流中。
fos.write(buf, 0, len);
}
// 关闭资源。
fos.close();
fis.close();
}
}
字符流
FileWriter类
字符输出流写数据的时候,必须要运行一个功能,刷新功能 flush(),刷新缓冲区
close方法在关闭流释放资源之前会执行flush()方法
FileReader类
/*
* 字符流复制文本文件,必须是文本文件
* 字符流查询本机默认的编码表,简体中文GBK
* FileReader读取数据源
* FileWriter写入到数据目的
*/
public class Copy {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader(srcpath);
fw = new FileWriter(destpath);
char[] cbuf = new char[1024];
int len = 0 ;
while(( len = fr.read(cbuf))!=-1){
fw.write(cbuf, 0, len);
fw.flush();
}
}catch(IOException ex){
System.out.println(ex);
throw new RuntimeException("复制失败");
}finally{
try{
if(fw!=null)
fw.close();
}catch(IOException ex){
throw new RuntimeException("释放资源失败");
}finally{
try{
if(fr!=null)
fr.close();
}catch(IOException ex){
throw new RuntimeException("释放资源失败");
}
}
}
}
}
字符流用法和字节流大同小异,字符流是针对字符的,也就是文本文件,注意字符流的输出要调用flush()函数进行刷新
转换流
OutputStreamWriter
public static void OutputStreamWriterDemo() throws Exception {
//创建与文件关联的字节输出流对象
FileOutputStream fos = new FileOutputStream(destpath);
//创建可以把字符转成字节的转换流对象,并指定编码
OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
//调用转换流,把文字写出去,其实是写到转换流的缓冲区中
osw.write("你好");//写入缓冲区。
osw.close();
}
InputStreamReader
public static void InputStreamReaderDemo() throws IOException{
//创建读取文件的字节流对象
InputStream in = new FileInputStream(srcpath);
//创建转换流对象
//InputStreamReader isr = new InputStreamReader(in);会用本地默认码表读取,将会发生错误解码的错误
InputStreamReader isr = new InputStreamReader(in,"utf-8");
//使用转换流去读字节流中的字节
int ch = 0;
while((ch = isr.read())!=-1){
System.out.println((char)ch);
}
//关闭流
isr.close();
}
有如下继承关系:
OutputStreamWriter是FileWriter的父类
InputStreamReader是FileReader的父类
当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类
例如:
使用 FileReader fr = new FileReader("a.txt”);
替代 InputStreamReader isr = new InputStreamReader(new FileInputStream(“a.txt”));
缓冲流
字节缓冲流
//字节缓冲输出流BufferedOutputStream
private static void write() throws IOException {
//创建基本的字节输出流
FileOutputStream fileOut = new FileOutputStream("abc.txt");
//使用高效的流,把基本的流进行封装,实现速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//2,写数据
out.write("hello".getBytes());
//3,关闭流
out.close();
}
//字节缓冲输入流BufferedInputStream
private static void read() throws IOException {
//1,创建缓冲流对象
FileInputStream fileIn = new FileInputStream("abc.txt");
//把基本的流包装成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
//2,读数据
int ch = -1;
while ( (ch = in.read()) != -1 ) {
//打印
System.out.print((char)ch);
}
//3,关闭
in.close();
}
高效复制文件
private static void method4(String src, String dest) throws IOException {
//1,指定数据源
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//2,指定目的地
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//3,读数据
byte[] buffer = new byte[1024];
int len = -1;
while ( (len = in.read(buffer)) != -1) {
//4,写数据
out.write(buffer, 0, len);
}
//5,关闭流
in.close();
out.close();
}
字符缓冲流
//字节缓冲输出流BufferedOutputStream
private static void write() throws IOException {
//创建基本的字节输出流
FileWriter fileOut = new FileWriter("abc.txt");
//使用高效的流,把基本的流进行封装,实现速度的提升
BufferedWriter out = new BufferedWriter(fileOut);
//2,写数据
out.write("hello");
out.newLine();
//3,关闭流
out.close();
}
//字节缓冲输入流BufferedInputStream
private static void read() throws IOException {
//1,创建缓冲流对象
FileReader fileIn = new FileReader("abc.txt");
//把基本的流包装成高效的流
BufferedReader in = new BufferedReader(fileIn);
//2,读数据
String line = null;
while ( (line = in.readLine()) != null ) {
//打印
System.out.print(line);
}
//3,关闭
in.close();
}
例子:文本复制
public class CopyTextFile {
public static void main(String[] args) throws IOException {
//1,指定数据源, 是数据源中读数据,采用输入流
BufferedReader in = new BufferedReader(new FileReader("file.txt"));
//2,指定目的地,是把数据写入目的地,采用输出流
BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt"));
//3,读数据
String line = null;
while ( (line = in.readLine()) != null ) {
//4,写数据
out.write(line);
//写入换行符号
out.newLine();
}
//5,关闭流
out.close();
in.close();
}
}
总结
IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?
- 首先确定选择哪个抽象类
读 | 写 | |
---|---|---|
字节 | InputStream | OutputStream |
文本 | Reader | Writer |
- 明确数据所在的具体设备。
- 硬盘:文件 File开头。
- 内存:数组,字符串。
- 键盘、屏幕:System.in; System.out;
- 网络:Socket
- 是否需要额外功能
- 转换流。InputStreamReader OutputStreamWriter
- 缓冲区对象。BufferedXXX
方法:
- 读数据方法:
read() 一次读一个字节或字符的方法
read(byte[] char[]) 一次读一个数组数据的方法
readLine() 一次读一行字符串的方法(BufferedReader类特有方法)
readObject() 从流中读取对象(ObjectInputStream特有方法)
- 写数据方法:
write(int) 一次写一个字节或字符到文件中
write(byte[] char[]) 一次写一个数组数据到文件中
write(String) 一次写一个字符串内容到文件中
writeObject(Object ) 写对象到流中(ObjectOutputStream类特有方法)
newLine() 写一个换行符号(BufferedWriter类特有方法)
应用
Properties类
Properties
类表示了一个持久的属性集。Properties
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
特点:
1、Hashtable的子类,map集合中的方法都可以用。
2、该集合没有泛型。键值都是字符串。
3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。
4、有和流技术相结合的方法,是唯一一个能与IO流交互的集合。
方法:
public Object setProperty(String key, String value)调用 Hashtable 的方法 put。
public Set stringPropertyNames()返回此属性列表中的键集,
public String getProperty(String key)用指定的键在此属性列表中搜索属性方法:
public Object setProperty(String key, String value)调用 Hashtable 的方法 put。
public Set stringPropertyNames()返回此属性列表中的键集,
public String getProperty(String key)用指定的键在此属性列表中搜索属性
将集合内容存到文件中
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
//1,创建Properties集合
Properties prop = new Properties();
//2,添加元素到集合
prop.setProperty("周迅", "张学友");
prop.setProperty("李小璐", "贾乃亮");
prop.setProperty("杨幂", "刘恺威");
//3,创建流
FileWriter out = new FileWriter("prop.properties");
//4,把集合中的数据存储到流所对应的文件中
prop.store(out, "save data");
//5,关闭流
out.close();
}
}
读取文件中的数据,保存到集合
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
//1,创建集合
Properties prop = new Properties();
//2,创建流对象
FileInputStream in = new FileInputStream("prop.properties");
//FileReader in = new FileReader("prop.properties");
//3,把流所对应文件中的数据 读取到集合中
prop.load(in);
//4,关闭流
in.close();
System.out.print(prop);
}
}
序列化流于反序列化流
用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流
用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。
对象序列化流ObjectOutputStream
注意:只能将支持 java.io.Serializable 接口的对象写入流中
public static void writeObj() throws IOException {
//1,明确存储对象的文件。
FileOutputStream fos = new FileOutputStream("tempfile\\obj.object");
//2,给操作文件对象加入写入对象功能。
ObjectOutputStream oos = new ObjectOutputStream(fos);
//3,调用了写入对象的方法。
oos.writeObject(new Person("wangcai",20));
//关闭资源。
oos.close();
}
//Serializable标记型接口
public class Person implements Serializable {
//给类显示声明一个序列版本号。
//在修改源码后,依然可以反序列化
private static final long serialVersionUID = 1L;
...
Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
对象反序列化流ObjectInputStream
public static void readObj() throws IOException, ClassNotFoundException {
//1,定义流对象关联存储了对象文件。
FileInputStream fis = new FileInputStream("tempfile\\obj.object");
//2,建立用于读取对象的功能对象。
ObjectInputStream ois = new ObjectInputStream(fis);
Person obj = (Person)ois.readObject();
System.out.println(obj.toString());
}
当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会琲序列化了。
同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
打印流
字节打印流 PrintStream
字符打印流 PrintWriter(用这个)
除了构造方法,其他方法完全一致
构造方法就是打印流的输出目的端
PrintStream接收File类型,字符串文件名,字节输出流OutputStream
PrintWriter接收File类型,字符串文件名,字节输出流OutputStream,字符输出流Wtiter
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
//创建流
//PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"));
PrintWriter out = new PrintWriter("printFile.txt");
//2,写数据
for (int i=0; i<5; i++) {
out.println("helloWorld");
}
//3,关闭流
out.close();
}
}
public class PrintWriterDemo2 {
public static void main(String[] args) throws IOException {
//创建流
PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"), true);
//2,写数据
for (int i=0; i<5; i++) {
out.println("helloWorld");
}
//3,关闭流
out.close();
}
}
print println 都是原样输出
write 要经过编码表
自动刷新
满足两个条件:
1.输出的数据目的必须是流对象 OutputStream、Writer
2.必须调用print、printf、format方法其中一个
public static void main(String[] args) throws IOException {
//创建流
FileOutputStream fos = new FileOutputStream(path);
PrintWriter pw = new PrintWriter(fos, true);
//2,写数据
for (int i=0; i<5; i++) {
pw.println("helloWorld");
}
//3,关闭流
//没关闭之前也可以看到数据,因为自刷新
pw.close();
}
自动刷新的文本复制
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader(srcpath));
PrintWriter pw = new PrintWriter(new FileWrite(destpath),true);
String line = null;
while((line = bfr.readLine()) != null){
pw.println(line);
}
pw.close();
bfr.close();
}
Commons-IO工具类
FilenameUtils
这个工具类是用来处理文件名(译者注:包含文件路径)的,他可以轻松解决不同操作系统文件名称规范不同的问题;常用方法:
getExtension(String path):获取文件的扩展名;
getName():获取文件名;
isExtension(String fileName,String ext):判断fileName是否是ext后缀名;
FileUtils
提供文件操作(移动文件,读取文件,检查文件是否存在等等)的方法。常用方法:
readFileToString(File file):读取文件内容,并返回一个String;
writeStringToFile(File file,String content):将内容content写入到file中;
copyDirectoryToDirectory(File srcDir,File destDir);文件夹复制
copyFile(File srcFile,File destFile);文件复制
总结
- 实现文件内容的自动追加
FileOutputStream(File file, boolean append)
FileOutputStream(String fileName, boolean append)
FileWriter(File, boolean append)
FileWriter(String fileName, boolean append) - 实现文件内容的自动刷新
PrintStream(OutputStream out, boolean autoFlush)
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(Writer out, boolean autoFlush)