计算机硬盘能永久性存储存储数据,因此程序、文件等数据需要保存在硬盘中,加载到内存中中运行。Java从硬盘读数据和往硬盘写数据采用两种流形式:字节流和字符流。数据是通过文件的形式保存,在Linux中更"有一切皆文件”的思想,首先先了解java中的文件类。
File
java.io.File是Java中表示文件的类,通过创建File对象,传入文件的地址,即可表示出指定的文件对象。
File类的构造方法:
方法 | 描述 |
---|---|
public File(String pathname) ; | 通过将给定的路径名字符串转换为抽象路径名来创建新的 File`实例 |
public File(String parent, String child); | 从父路径名字符串和子路径名字符串创建新的 File`实例 |
public File(File parent, String child); | 从父抽象路径名和子路径名字符串创建新的 File`实例 |
public File(URI uri); | 通过将给定的file:URI转换为抽象路径名来创建新的File`实例 |
常用的构造方法为前三种,这里需要补充2点:
- 绝对路径与相对路径:绝对路径指完整的路径(例如:File(C:\Program Files\Adobe),表示C盘下的Adobe文件);相对路径是相对于当前项目下的,(例如:File(Adobe),表示当前项目文件夹下的Adobe文件)。
- 创建的文件可以是文件、也可以是文件夹;可以存在,也可以不存在(不存在可以通过调用方法进行创建)。
使用常用的File构造方法创建3个对象:
public class FileDemo {
public static void main(String[] args) {
File file1 = new File("file1.txt");
File file2 = new File(file1, "file2.txt");
File file3 = new File("c:\\", "file3.txt");
}
}
Java是具有夸平台性的特点,因为各个操作系统的文件分隔符、路径分隔符不同,因此java提供了系统依赖的默认名称分隔符的静态方法。
方法 | 描述 |
---|---|
public static final String pathSeparator | 与系统相关的路径分隔符,为方便起见,表示为字符串 |
public static final String separator | 系统相关的默认名称分隔符,为方便起见,表示为字符串 |
public static final char pathSeparatorChar | 与系统相关的路径分隔符 |
public static final char separatorChar | 系统相关的默认名称分隔符 |
File常用方法:
方法 | 描述 |
---|---|
public String getName(); | 返回文件的名称 |
public String getParent(); | 返回文件上级文件夹的名称字符串,没有则为空 |
public File getParentFile(); | 返回文件上级文件夹的名称文件对象,没有则为空 |
public String getPath(); | 将此抽象路径名转换为路径名字符串 |
public boolean isAbsolute(); | 创建文件对象传入的地址是否为绝对路径 |
public String getAbsolutePath(); | 返回此抽象路径名的绝对路径名字符串 |
public boolean canRead(); | 文件对象是否可读 |
public boolean canWrite(); | 文件对象是否可写 |
public boolean exists(); | 文件对象是否存在 |
public boolean isDirectory(); | 文件对象是否为文件夹 |
public boolean isFile(); | 文件对象是否为文件 |
public long length(); | 文件的大小 |
public boolean createNewFile(); | 文件对象指定的文件不存在可进行创建 |
public boolean delete(); | 删除文件对象指向的文件 |
public void deleteOnExit(); | 虚拟机退出是删除文件对象指定的文件 |
public String[] list(); | 返回一个字符串数组,用于命名此抽象路径名表示的目录中的文件和目录 |
public File[] listFiles(); | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中的文件。 |
public String[] list(FilenameFilter filter); | 返回一个字符串数组,用于命名由此抽象路径名表示的目录中的文件和目录,以满足指定的过滤器 |
public File[] listFiles(FileFilter filter); | 返回一个抽象路径名数组,表示此抽象路径名表示的目录中满足指定过滤器的文件和目录 |
public boolean mkdir(); | 文件表示的文件夹不存在创建文件夹 |
public boolean mkdirs(); | 文件表示的文件夹不存在创建多级文件夹 |
通过一个文件遍历的例子来使用一下这些方法,遍历指定目录下的所有“.pdf”文件
public class FileDemo {
public static void main(String[] args) {
File f = new File("D:\\JavaLearn");
listFileEndWithSuffix(f);
}
private static void listFileEndWithSuffix(File file){
if(file.isDirectory(){//判断是否文件夹
File[] files = file.listFiles((f) -> f.isDirectory() || f.getName().endsWith(".pdf")); //使用了过滤器,过滤掉不是.pdf的文件
for (File file1 : files) {
if (file1.isFile()) {
System.out.println(file1.getParent() + ":" + file1.getName());
} else {
listFileEndWithSuffix(file1); //如果是文件夹,则调用方法
}
}
}else{
//判断是否指定后缀结尾文件
if(file.getName().endsWith(".pdf"))
System.out.println(file1.getParent() + ":" + file1.getName());
}
}
}
对于文件的读写,java中采用字节流和字符流2中方式。
字节流
字节输入流:java.io.InputStream,为所有字节输入流的超类。
字节输出流:java.io.OutputStream,为所有字节输出流的超类。
InputStream
public abstract class InputStream implements Closeable
常用方法:
方法 | 描述 |
---|---|
public abstract int read(); | 从输入流读取数据的下一个字节。值字节以0到255的整数形式返回。 |
public int read(byte b[]) ; | 从输入流中读取一定数量的字节并将它们存储到缓冲区数组b中。实际读取的字节数以整数形式返回。如果由于流位于文件末尾而没有可用的字节,则返回值-1 |
public int read(byte b[], int off, int len); | 从输入流最多读入 len字节的数据到一个起点为下标 off 的字节缓存数组,。如果由于流位于文件末尾而没有可用的字节,则返回值-1 |
public void close(); | 关闭流。 |
由InputStream声明可知其为抽象类,不能直接创建对象。在实际使用中常用其子类:java.io.FileInputStream
FileInputStream构造方法:
public FileInputStream(String name)
public FileInputStream(File file)
OutputStream
public abstract class OutputStream implements Closeable, Flushable
常用方法:
方法 | 描述 |
---|---|
public abstract void write(int b); | 将指定的字节写入输出流 |
public void write(byte b[]); | 从指定的字节数组将b.length字节写入输出流 |
public void write(byte b[], int off, int len); | 从指定的字节数组从offset off开始写入len字节到输出流 |
public void flush(); | 刷新此输出流并强制将所有缓冲的输出字节写入 |
public void close(); | 关闭流 |
由OutputStream声明可知其为抽象类,不能直接创建对象。在实际应用中常使用其子类:java.io.FileOutputStream
FileOutputStream构造方法:
public FileOutputStream(String name)
public FileOutputStream(String name, boolean append)
public FileOutputStream(File file)
public FileOutputStream(File file, boolean append)
应用举例:
public class FileInputStreamAndOutputStreamDemo {
public static void main(String[] args) throws IOException {
File file = new File("demo.txt");
//因为文件对象指向的文件是不存在的,先创建输出流对象,文件不存在可自动创建文件。
FileOutputStream fos = new FileOutputStream(file);
FileInputStream fis = new FileInputStream(file);
fos.write('a');
fos.write('b');
fos.write('c');
fos.write('d');
fos.write('e');
fos.close();
while (true) {
byte b = (byte) fis.read();
if (b == -1) {
break;
}
System.out.println((char) b);
}
fis.close();
}
}
字符流
字节流是按字节读取、存储文件,对于中文这样的字符,用字节流可能会出乱码的显现,因为一个中文是用多个字节编码(在UTF-8编码,一个中文的编码字节数不是定长的),此时选择用字符流进行储存和读取数据。
字符输入流:java.io.Reader
字符输出流:java.io.Writer
Reader
public abstract class Reader
常用方法:
方法 | 描述 |
---|---|
public int read(); | 读取字符,返回读到的字符,读到最后返回-1 |
public int read(char cbuf[]); | 将字符读入数组,返回读取的字符数,如果到达流的末尾,则为-1 |
public abstract int read(char cbuf[], int off, int len); | 将字符读入数组的一部分,读取的字符数,如果到达流的末尾,则为-1 |
public abstract void close(); | 关闭流 |
Reader为抽象类,不能直接创建对象,在实际应用在使用其子类:java.io.FileReader
FileReader构造方法:
public FileReader(String fileName)
public FileReader(File file)
public FileReader(String fileName, Charset charset)
ublic FileReader(File file, Charset charset)
参数Charset charset:可指定编码格式(如"utf-8",GBK"等)
Writer
public abstract class Writer implements Appendable, Closeable, Flushable
常用方法:
方法 | 描述 |
---|---|
public void write(int c); | 只写一个字符。所要写入的字符包含在给定整数值的16个低阶位中;16个高阶位被忽略。 |
public void write(char cbuf[]); | 写入字符数组。 |
public abstract void write(char cbuf[], int off, int len) | 写入字符数组的一部分。起始下标为off,长度为len |
public void write(String str); | 写入字符串 |
public void write(String str, int off, int len); | 写入字符串一部分,起始下标为off,长度为len |
public Writer append(char c); | 将指定的字符追加到写入器。 |
public abstract void flush(); | 刷新流 |
public abstract void flush(); | 关闭流 |
Writer为抽象类,不能直接创建对象,实际应用中使用其子类java.io.FileWriter
FileWriter构造方法:
public FileWriter(String fileName)
public FileWriter(String fileName, boolean append)
public FileWriter(File file)
public FileWriter(File file, boolean append)
public FileWriter(String fileName, Charset charset)
public FileWriter(String fileName, Charset charset, boolean append)
public FileWriter(File file, Charset charset)
public FileWriter(File file, Charset charset)
转换流
将字节流转换为字符流:java.io.InputStreamReader、java.io.OutputStreamWriter
使用了装饰者设计模式。
InputStreamReader构造方法:
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, Charset cs)
OutputStreamWriter构造方法
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, Charset cs)
打印输出流
字节打印输出流,java.io.PrintStream,PrintStream将功能添加到另一个输出流,即方便地打印各种数据值表示的能力。
System.ou.println()方法是向控制台打印,我们可以通过创建PrintStream向指定位置打印信息。
PrintStream常用构造方法:
public PrintStream(String fileName)
public PrintStream(File file)
public PrintStream(OutputStream out)
常用方法:
方法 | 描述 |
---|---|
print(); | 打印 |
println(); | 换行打印 |
printf(); | 按指定格式打印 |
字符打印输出流,java.io.PrintWriter,这个类实现了PrintStream中的所有打印方法。
需注意的是,PrintWriter打印完需调用flush()方法刷新管道,或关闭流,输出的内容才会写入到指定文件内。
缓存流
缓存输入流
java.io.BuffeerReader
public class BufferedReader extends Reader
构造方法:
public BufferedReader(Reader in)
public BufferedReader(Reader in, int sz)
特有的方法:
方法 | 描述 |
---|---|
public String readLine(); | 读取一行文本 |
String readLine(boolean ignoreLF); | 读取一行文本。换行符(’\n’)、回车符(’\r’)、紧接换行符的回车符或到达文件结束符(EOF)时,行被认为终止。 |
缓存输出流
java.io.BufferWriter
public class BufferedWriter extends Writer
构造方法:
public BufferedWriter(Writer out)
public BufferedWriter(Writer out, int sz)
特有方法:
方法 | 描述 |
---|---|
public void newLine(); | 写入行分隔符 |
Properties
java.util.Preperties。Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。 (键值对的方式),保存的文件是配置文件,格式为:.preperties
文件。
class Properties extends Hashtable<Object,Object>
常用构造方法:
public Properties()
常用方法:
方法 | 描述 |
---|---|
public synchronized void load(InputStream inStream); | 从输入字节流中读取属性列表(键和元素对)。 |
public synchronized void load(Reader reader); | 以简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 |
ublic void store(Writer writer, String comments); | 将属性表中的属性列表(键和元素对)以适合使用load(Reader)方法的格式写入输出字符流。 |
public void store(OutputStream out, String comments) | 将属性表中的属性列表(键和元素对)以适合使用load(InputStream)方法加载到属性表的格式写入输出流。 |
public synchronized void loadFromXML(InputStream in); | 将指定输入流上的XML文档表示的所有属性加载到这个属性表中。 |
public void storeToXML(OutputStream os, String comment); | 发出一个表示该表中包含的所有属性的XML文档。 |
public void storeToXML(OutputStream os, String comment, String encoding); | 使用指定的编码发出表示该表中包含的所有属性的XML文档。 |
public String getProperty(String key); | 在此属性列表中搜索具有指定键的属性。如果在此属性列表中未找到键,则递归地检查默认属性列表及其默认值。如果没有找到属性,该方法将返回null。 |
public String getProperty(String key, String defaultValue); | 在此属性列表中搜索具有指定键的属性。如果在此属性列表中未找到键,则递归地检查默认属性列表及其默认值。如果未找到属性,该方法将返回默认值参数。 |
举例使用Properties类的方法:
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
FileOutputStream fos = new FileOutputStream("book.properties");
properties.put("name", "你好");
properties.put("author", "Noname");
properties.store(fos, "书的信息");
fos.close();
FileInputStream fis = new FileInputStream("book.properties");
properties.load(fis);
System.out.println(properties.getProperty("name"));
System.out.println(properties.getProperty("author"));
}
}
序列化
java可通过序列化的方式将对象直接存储在文件中。
Serializable
实现java.io.Serializable接口的类启用了类的可序列化。
用法就是将要序列化的类实现Serializable接口。
public class Person implents Serializable
在序列化和反序列化过程中需要特殊处理的类必须实现具有以下精确签名的特殊方法:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
在使用序列化进行存储对象是,需要使用ObjectOutputStream,反序列化从文件中读取对象时,需要使用ObjectInputStream。
ObjectOutputStream:Java对象的原始数据类型和图形写入OutputStream。
构造方法:
public ObjectOutputStream(OutputStream out)
特有方法:
方法 | 名称 |
---|---|
public final void writeObject(Object obj); | 将指定的对象写入ObjectOutputStream |
ObjectInputStream:对先前使用ObjectOutputStream编写的原始数据和对象进行反序列化。
构造方法:
public ObjectInputStream(InputStream in)
特有方法:
方法 | 名称 |
---|---|
public final Object readObject(); | 从ObjectInputStream读取对象。读取对象的类、类的签名、类及其所有超类型的非瞬态和非静态字段的值。 |
如果一个类的一些属性不想序列化,那么可以通过使用关键字transient或static进行修饰。也可以重写以下方法
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
Externalizable
另一种实现序列化和反序列化是实现Externalizable接口。只有Externalizable实例的类的标识才会写入序列化流中,并且该类负责保存和恢复其实例的内容
public interface Externalizable extends java.io.Serializable
通过声明可以看到Externalizable是继承了Serializable接口的,实现Externalizable接口需实现方
法:
void writeExternal(ObjectOutput out) throws IOException
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
try -with-resources
对于流,使用完后需要关闭,在处理异常时需要使用try—catch,对于实现类Closeable接口的资源对象,可采用如下格式创建对象,可自动关闭:
try(FileInputStream fis = new FileInputStream("demo.txt")){
}catch(IOException e){
}
-------------------------------------------------------------------------------------
public class FileInputStream extends InputStream
public abstract class InputStream implements Closeable
最后,如果觉得有用,还请点赞支持,给与笔者鼓励。