前面几篇介绍了java IO的基础部分,现在进入核心内容的学习,如File类、动态读取和序列化等,如下。
一、File类
1、概述
是 java.io 包中唯一代表磁盘文件本身的对象(可以通过 File 类操作文件和目录),定义了一些操作文件的方法,如新建、删除、重命名文件和目录等。
File 类不能访问文件内容本身(访问要使用输入/输出流)
2、构造方法(重载–3个)
构造方法用于创建对象(实例化)
1 2 3
| File(String path):如果 path 是实际存在的路径,则该 File 对象表示的是目录;如果 path 是文件名,则该 File 对象表示的是文件。 File(String path, String name):path 是路径名(目录),name 是文件名。 File(File dir, String name):dir 是路径对象(目录),name 是文件名。
|
3、File类常用方法
不用死记,可通过查看API文档来获取文件属性
1)常用汇总
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| canRead() 测试程序是否能从指定的文件中读取 canWrite() 测试程序是否能写当前文件 delete() 删除指定的文件 exists() 测试当前 File 是否存在 getAbsolutePath() 返回文件的绝对路径名 getName() 返回对象的文件名或路径名(如果是路径,则返回最后一级子路径名) getParent() 返回当前 File 对象所对应目录(最后一级子目录)的父目录名 isAbsolute() 测试文件是否为一个绝对路径名。 isDirectory() 测试文件是否为一个路径(目录) isFile() 测试文件是否为一个“普通”文件 lastModified() 返回文件最后修改的时间 length() 返回文件长度 list() 返回指定的路径文件列表 list(FilenameFilter) 返回指定的目录中满足指定过滤器的文件列表 mkdir() 创建一个目录,它的路径名由当前 File 对象指定 mkdirs() 创建一个目录(多级目录),它的路径名由当前 File 对象指定 renameTo(File) 将文件更名为给定参数 File 指定的路径名
|
2)说明
创建&&删除文件
1 2 3
| 创建:createNewFile() 删除:delete() 注:在创建或删除前都先用exists()方法判断文件是否存在
|
创建&&删除目录
1 2 3 4
| 创建:mkdir() 注:创建多级目录(即目录中还包含目录),用mkdirs 删除:delete() 注:在创建或删除前都先用exists()方法判断目录是否存在
|
遍历目录(list方法–重载)
1 2
| String[] list():返回由 File 对象表示目录中所有文件和子目录名称组成的字符串数组,如果调用的 File 对象不是目录,则返回 null。(list() 方法返回的数组中仅包含文件名称,而不包含路径) String[] list(FilenameFilter filter):返回数组中仅包含符合 filter 过滤器的文件和目录,如果 filter 为 null,则接受所有名称。
|
带过滤器参数的 list() 方法(当希望只列出目录下的某些文件,就需要调用)
1 2
| 首先创建文件过滤器,该过滤器必须实现 java.io.FilenameFilter 接口。 在 accept() 方法中指定允许的文件类型。
|
4、示例
1)获取文件属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import java.io.File; import java.util.Date;
public class FlieDemo { public static void main(String[] args){ String path="D:\\Ultimate JavaCode\\src\\test6"; File f=new File(path,"date1_24.txt"); System.out.println("D:\\Ultimate JavaCode\\src\\test6\\date1_24.txt文件信息如下:"); System.out.println("============================================"); System.out.println("文件名称:"+f.getName()); System.out.println("文件路径:"+f.getPath()); System.out.println("绝对路径:"+f.getAbsoluteFile()); System.out.println("文件长度:"+f.length()+"字节"); System.out.println("文件或者目录:"+(f.isFile()?"是文件":"不是文件")); System.out.println("文件或者目录:" + (f.isDirectory() ? "是目录" : "不是目录")); System.out.println("是否可读:"+(f.canRead()?"可读取":"不可读取")); System.out.println("是否可写:"+(f.canWrite()?"可写入":"不可写入")); System.out.println("是否隐藏:"+(f.isHidden()?"是隐藏文件":"不是隐藏文件")); System.out.println("最后修改日期:"+new Date(f.lastModified())); } }
|
运行结果
1 2 3 4 5 6 7 8 9 10 11 12
| D:\Ultimate JavaCode\src\test6\date1_24.txt文件信息如下: ============================================ 文件名称:date1_24.txt 文件路径:D:\Ultimate JavaCode\src\test6\date1_24.txt 绝对路径:D:\Ultimate JavaCode\src\test6\date1_24.txt 文件长度:72字节 文件或者目录:是文件 文件或者目录:不是目录 是否可读:可读取 是否可写:可写入 是否隐藏:不是隐藏文件 最后修改日期:Tue Jan 24 11:33:48 CST 2023
|
2)在 D:\Ultimate JavaCode\src\test6下创建一个 date1_24_1.txt 文件,程序启动时会检测该文件是否存在,如果不存在则创建;如果存在则删除再创建。
1 2 3 4 5 6 7 8 9 10 11 12 13
| import java.io.File; import java.io.IOException;
public class FileDemo1 { public static void main(String[] args) throws IOException { String path="D:\\Ultimate JavaCode\\src\\test6"; File f1=new File(path,"date1_24_1.txt"); if(f1.exists()){ f1.delete(); } f1.createNewFile(); } }
|
优化:不同操作系统路径的分隔符是不同的。Windows 中用反斜杠\表示目录的分隔符,Linux 则用正斜杠/,
在操作文件时一定要使用 File.separator 表示分隔符(使用符合本地操作系统要求的分隔符),养成良好的开发习惯。
1 2 3 4 5 6 7 8 9 10 11 12 13
| import java.io.File; import java.io.IOException;
public class FileDemo1 { public static void main(String[] args) throws IOException { String path="D:\\Ultimate JavaCode\\src\\test6"+File.separator+"date1_24_1.txt"; File f1=new File(path); if(f1.exists()){ f1.delete(); } f1.createNewFile(); } }
|
3)编写程序判断D盘根目录下是否存在Date1_24目录,若存在则先删除再创建。
1 2 3 4 5 6 7 8 9 10 11 12 13
| import java.io.File;
public class FileDemo2 { public static void main(String[] args){ String path="D:/Date1_24/"; File f=new File(path); if (f.exists()){ f.delete(); } f.mkdir(); } }
|
4)使用 list()方法遍历D盘根目录下的所有文件和目录,并显示文件或目录名称、类型及大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.io.File;
public class FileDemo3 { public static void main(String[] args){ File f=new File("D:/"); System.out.println("文件名称\t\t文件类型\t\t文件大小"); System.out.println("==================================================="); String fileList[]=f.list(); for(int i=0;i<fileList.length;i++){ System.out.print(fileList[i]+"\t\t"); System.out.print((new File("D:/",fileList[i])).isFile()?"文件"+"\t\t":"文件夹"+"\t\t"); System.out.println((new File("D:/",fileList[i])).length()+"字节"); } } }
|
运行结果(展示部分)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 文件名称 文件类型 文件大小 =================================================== $RECYCLE.BIN 文件夹 0字节 360downloads 文件夹 4096字节 360RecycleBin 文件夹 4096字节 360安全浏览器下载 文件夹 0字节 Anaconda 文件夹 24576字节 Android 文件夹 0字节 apache-tomcat-8.5.83 文件夹 4096字节 BaiduNetdiskDownload 文件夹 0字节 centbrowser_4.3.9.248 文件夹 0字节 Date1_24 文件夹 0字节 Dev-Cpp 文件夹 4096字节 HBuilderX.3.3.11.20220209 文件夹 0字节 ideaIU-2021.3.3.win 文件夹 4096字节 Maven 文件夹 0字节 Microsoft Visio 文件夹 0字节 MSOCache 文件夹 0字节 mydrivers 文件夹 0字节 mysql 文件夹 4096字节 Node.js 文件夹 4096字节
|
注:由于 list() 方法返回的字符数组中仅包含文件名称,要获取文件类型和大小,必须先转换为 File 对象再调用其方法。
5)带过滤器参数的 list() 方法示例(自行实现)
1 2 3 4 5 6 7 8
| public class ImageFilter implements FilenameFilter { @Override public boolean accept(File dir, String name) { return name.endsWith(".sys") || name.endsWith(".txt") || name.endsWith(".bak"); } }
|
其他代码与4)中相同。
二、动态读取文件内容
所谓动态读取,就是从文件的任意位置开始访问文件,而不是必须从文件开始位置读取到文件末尾。
1、RandomAccessFile 类
1.1 概述
是 Java 输入/输出流体系中功能最丰富的文件内容访问类,提供了众多方法访问文件内容,既可以读取文件内容,也可以向文件输出数据。
RandomAccessFile 可以从任意位置访问文件,在只需要访问文件部分内容的情况下,可以使用 RandonAccessFile 类。
RandomAccessFile 对象包含了一个记录指针,用以标识当前读写处的位置。当程序新创建一个 RandomAccessFile 对象时,指针位于文件头(也就是 0 处),当读/写了 n 个字节后,文件记录指针将会向后移动 n 个字节。除此之外,RandonAccessFile 可以自由移动该记录指针,既可以向前移动,也可以向后移动。
1.2 RandomAccessFile 类的构造方法(重载)
构造方法用来创建对象(实例化)
1 2
| RandomAccessFile(File file, String mode):访问参数 file 指定的文件,访问形式由参数 mode 指定,mode 参数有两个常用的可选值 r 和 rw( r 表示只读,rw 表示读写) RandomAccessFile(String name, String mode):访问参数 name 指定的文件,mode含义同上。
|
1.3 RandomAccessFile 类的常用方法
会用一些常用的就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| boolean readBoolean() 从文件中读取一个 boolean 值 byte readByte() 从文件中读取一个带符号位的字节 char readChar() 从文件中读取一个字符 int readlnt() 从文件中读取一个带符号位的整数 long readLong() 从文件中读取一个带符号位的 long 值 String readLine() 从文件中读取下一行文本 void seek(long pos) 指定从文件起始位置开始的指针偏移量 void writeBoolean(boolean v) 以字节的形式向文件中写入一个 boolean 值 void writeByte(int v) 以单字节的形式向文件中写入一个 byte 值 void writeChar(int v) 以双字节的形式向文件中写入一个 char 值 void writelnt(int v) 以4字节的形式向文件中写入一个整数 writeLong(long v) 以8字节的形式向文件中写入一个 long 值 void writeBytes(String s) 以字节序列的形式向文件中写入一个字符串 void skipBytes(int n) 以当前文件指针位置为起始点,跳过 n 字节
|
1.4 示例
使用 RandomAccessFileDemo 类创建一个 weather.txt 文件,然后写入一个长中文字符串,再从第 6 个字节开始读取并输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import java.io.File; import java.io.IOException; import java.io.RandomAccessFile;
public class RandomAccessFileDemo { public static void main(String[] args) throws IOException { File file=new File("D:\\Ultimate JavaCode\\src\\test6\\weather.txt"); if(file.exists()){ file.delete(); file.createNewFile(); } file.createNewFile();
RandomAccessFile rf=new RandomAccessFile(file,"rw"); String str1="晴天,阴天,多云,小雨,大风,中雨,小雪,雷阵雨"; String str2=new String(str1.getBytes("GBK"),"ISO_8859_1"); rf.writeBytes(str2);
System.out.println("当前文件指针的位置:"+rf.getFilePointer()); rf.seek(6); System.out.println("从文件头跳过6个字节后,文件的内容如下:"); byte[] b=new byte[2]; int len=0; while ((len=rf.read(b,0,2))!=-1){ System.out.print(new String(b,0,len)); } rf.close(); } }
|
三、转换流
1)概述
用于字节流和字符流之间的转换,有两种
InputStreamReader:
将字节的输入流按指定字符集转换为字符的输入流。即将InputStream转换为Reader(编码:字节—->字符)
OutputStreamWriter:
将字符输出流按指定字符集转换为字节输出流。即将Writer转换为OutputStream(解码:字符—->字节)
2)说明
当文件中含有中文英文数字时,使用字节流将文件内容在内存中显示,英文和数字显示正常,而中文却却显示乱码。这时可以使用转换流将其转化为字符流显示在内存中。
3)何时使用
1 2 3 4 5 6
| 1.当字节和字符之间有转换动作时; 2.流操作的数据需要编码或解码时; - 编码:字节/字节数组---->字符/字符数组 - 解码:字符/字符数组---->字节/字节数组
转换流作用:提供字节流与字符流之间的转换,通常使用转换流来处理文件乱码问题,实现编码和解码的功能。
|
四、序列化
1、对象序列化流(ObjectOutputStream)
1.1 概述
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来完成对象的持久存储。 如果流是网络套接字流,则可以在另一个主机或另一个进程中重新构建对象。
1.2 构造方法
1
| objectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
|
1.3 序列化对象的方法
1
| void writeObject(Object obj):将指定的对象写入ObjectOutputStream
|
注:
一个对象要想被序列化,该对象所属的类必须实现Serializable接口
Serializable是一个标记接口,实现该接口,不需要重写任何方法
1.4 示例
1)创建一个学生类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.io.Serializable;
public class Student implements Serializable { private String name; private int age;
public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
|
2)使用序列化流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream;
public class ObjectOutputStreamDemo { public static void main(String[] args) throws IOException { ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\Ultimate JavaCode\\src\\test8\\oos.txt")); Student s=new Student("林青霞",20); oos.writeObject(s); oos.close(); } }
|
2、对象反序列化流
2.1 说明
1 2 3 4 5 6 7 8 9 10
| ObjectInputStream - ObjectInputStream反序列化前先使用ObjectOutputStream编写的原始数据和对象
构造方法 ObjectInputStream(InputStream in) - 创建从指定的InputStream读取的ObjectInputStream
反序列化对象的方法 Object readObject() - 从ObjectInputStream读取一个对象
|
2.2 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream;
public class ObjectInputStreamDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\Ultimate JavaCode\\src\\test8\\oos.txt")); Object obj = ois.readObject(); Student s=(Student) obj; System.out.println(s.getName()+","+s.getAge()); ois.close(); } }
|
3、java序列化小结
- 将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,即对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。整个过程都是 Java 虚拟机(JVM)独立的,说明在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象。
- 类 ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法。
五、Properties类
1、概述
Properties类是一个Map体系的集合类,父类是Hashtable。Properties可以保存到流中或从流中加载。
2、示例
Properties作为Map集合的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.util.Properties; import java.util.Set;
public class PropertiesDemo { public static void main(String[] args) { Properties prop=new Properties(); prop.put("101","zhangsan"); prop.put("102","lishi"); prop.put("103","wangwu"); Set<Object> keySet=prop.keySet(); for(Object key:keySet){ Object value=prop.get(key); System.out.println(key+","+value); } } }
|
运行结果
1 2 3
| 103,wangwu 102,lishi 101,zhangsan
|
3、Properties作为集合的特有方法
3.1 说明
1 2 3
| Object setProperty(String key,String value):数组集合的键和值,都是String类型,底层调用Hashtable方法 put(设置键值对,可代替父类的put()方法) String getProperty(String key):使用此属性列表中指定的键搜索属性(根据键key获取值value) Set<String> stringPropertyName():从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串(获取得到所有键的集合)
|
3.2 示例
Properties作为集合的特有方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.util.Properties; import java.util.Set;
public class PropertiesDemo1 { public static void main(String[] args) { Properties prop=new Properties();
prop.setProperty("101","zhangsan"); prop.setProperty("102","lishi");
Set<String> names = prop.stringPropertyNames(); for(String key:names){
String value = prop.getProperty(key); System.out.println(key+","+value); } } }
|
运行结果
4、Properties和IO流结合的方法
4.1 方法说明
1 2 3
| void load(InputStream inStream):从输入字节流读取属性列表(键和元素对) void load(Reader reader):从输入字符流读取属性列表(键和元素对) void store(OutputStream out,String comments):将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式写入输入字符串(即将Properties集合数据保存到文件中)
|
4.2 示例
Properties和IO流结合的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Properties;
public class PropertiesDemo2 { public static void main(String[] args) throws IOException{ myStore(); myLoad(); } private static void myLoad() throws IOException{ Properties prop=new Properties(); FileReader fr=new FileReader("D:\\Ultimate JavaCode\\src\\test8\\fw.txt"); prop.load(fr); fr.close(); System.out.println(prop); } private static void myStore() throws IOException { Properties prop=new Properties(); prop.setProperty("101","zhangsan"); prop.setProperty("102","lishi"); prop.setProperty("103","wangwu"); FileWriter fw=new FileWriter("D:\\Ultimate JavaCode\\src\\test8\\fw.txt"); prop.store(fw,null); fw.close(); } }
|
运行结果
1
| {101=zhangsan, 102=lishi, 103=wangwu}
|