文件管理
Java中的对文件的管理,通过java.io包中的File类实现。
Java中文件的管理,主要是针对文件或是目录路径名的管理:
文件的属性信息;
文件的检查:
文件的删除等:
不包括文件的访问。
就像我们看文件时一样,不能读写里面的内容,只有一些属性,像windows的资源管理器。
File类
构造方法
-
构造方法:
File 变量名 = new File(String pathname);
通过将给定路径名字符串转换成抽象路径名来创建一个新File实例:
File f1 = new File("d:/temp/test.txt");
路径名用反斜杠“/”或转义字符“\”
-
构造方法:
File 变量名 = new File(String parent, String child);
根据parent路径名字符串和child路径名字符串创建一个新File实例:
File f2 = new File("d:/temp", "test.txt");
parent为路径,child为文件名。
用于:无论哪个文件夹,都是同一个名的文件“test.txt”。 -
构造方法:
File 变量名 = new File(File parent, String child);
根据parent抽象路径名和child路径名字符串创建一个新File实例:
File f = new File("d:/temp"); File f3 = new File(f, "test.txt");
其他方法
方法 | 含义 |
---|---|
boolean createNewFile() | 当且仅当不存在具有此抽象路径名指定的名称的文件时,创建由此抽象路径名指定的一个新的空文件 |
static File createTempFile(String prefix, String suffix) | (创建临时文件)在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称 |
static File createTempFile(String prefix, String suffix, File directory) | 在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称 |
boolean exits() | 测试此抽象路径名表示的文件或目录是否存在 |
boolean delete() | 删除此抽象路径名表示的文件或目录 |
boolean equals(Object obj) | 测试此抽象路径名与给定对象是否相等 |
boolean canRead() | 测试应用程序是否可以读取此抽象路径名表示的文件 |
boolean canWrite() | 测试应用程序是否可以修改此抽象路径名表示的文件 |
String[] list() | 返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组 |
String getAbsolutePath() | 返回抽象路径名的绝对路径名字符串 |
String getName() | 返回由此对象路径名表示的文件或目录的名称,不包括路径名称 |
String getPath() | 将此抽象路径名转换为一个路径名字符串 |
File[] listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件 |
boolean renameTo(File dest) | 重新命名此抽象路径名表示的文件 |
long length() | 返回由此对象路径名表示的文件的大小,以byte为单位 |
我们自己写类时,相似功能、相同功能的参照官方API的命名来写,那些大家约定俗成的…
如定义boolean的方法时,习惯用canRead或isRead。
流
(读写文件里的内容)
流(Stream)的概念代表的是程序中数据的流通。
数据流是一串连续不断的数据的集合。
在Java程序中,对于数据的输入/输出操作是以流的方式进行的:
输入流——流入程序的数据
输出流——流出程序的数据
在Java程序中,从输入流读取数据(读到内存中),从输出流输出数据(从内存存储到文件或显示到屏幕上)
流的分类:
按流的方向不同:输入流、输出流;
按处理数据的单位不同:字节流、字符流;
按功能不同:节点流、处理流。
Java语言中,控制数据流的类都放在java.io包中。
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
java.io包中有两大继承体系:
以byte处理为主的Stream类,他们的命名方式是XXStream;
以字符处理为主的Reader/Writer类,他们的命名方式为XXReader或XXWriter。
InputStream、OutputStream、Reader、Writer这四个类,是这两大继承体系的父类。
字节流
字节输入流InputStream
层次结构图:
InputStream常用的方法:
方法 | 含义 |
---|---|
int read() | 一次读取一个byte的数据,并以int类型把数据返回来,如果没有数据可以读,返回-1 |
int read(byte[] buffer) | 把所读取到的数据放在这个byte数组中,返回一个int型的数据,这个int型数据存储了返回的真正读取到的数据byte数(读到的长度) |
int read(byte[] buffer, int offset, int length) | 读取length个字节,并存查到一个字节数组buffer中,并从offset位置开始返回实际读取的字节数 |
void close() | 关闭此输入流并释放与该流关联的所有系统资源。 |
所有的流都有close方法。
用read写入内存,flush刷新内存(缓冲区),缓存区写出去,清理掉,再close。
字节输出流OutputStream
层次结构图:
OutputStream常用方法:
方法 | 含义 |
---|---|
void write(byte[] buffer) | 将要输出的数组先放在一个byte数组中,然后用这个方法一次把一组数据输出出去 |
void write(byte[] buffer, int off, int len) | 将指定字节数组中从偏移量off开始的len个字节写入此输出流 |
abstract void write(int b) | 将指定的字节写入此输出流 |
void close() | 关闭此输出流并释放与此流有关的所有系统资源 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节 |
字符流
字符输入流Reader
层次结构图:
Reader常用方法:
方法 | 含义 |
---|---|
int read() | 一次读取一个char的数据,并以int类型把数据返回来,如果没有数据可以读了,返回-1 |
int read(char[] cbuffer) | 把所读取到的数据放在这个char数组中,返回一个int型的数据,这个int型数据存储了返回的真正读取到的数据char数 |
int read(char[] cbuffer, int offset, int length) | 读取length个字符,并存储到一个字节数组cbuffer中,并从offset位置开始返回实际读取的字符数 |
void close() | 关闭此Reader并释放与其关联的所有系统资源 |
读时不用flush,但要close
字符输出流Writer
层次结构图:
Writer常用的方法:
方法 | 含义 |
---|---|
void write(char[] cbuffer) | 将要输出的数组先放在一个char数组中,然后用这个方法一次把一组数据输出出去 |
void write(char[] cbuffer, int off, int len) | 将指定字符数组中从偏移量off开始的len个字符写入此输出流 |
int write(int b) | 将指定的字符写入此输出流 |
void write(String str) | 写入字符串 |
void write(String str, int off, int len) | 将指定字符串中从偏移量off开始的len个字符写入此输出流 |
void close() | 关闭此输出流并释放与此流有关的所有系统资源 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节 |
写入就要flush。
字符流写字符串很方便,字节流写字符串不方便。
字节流
从一个特定(给定)的数据源(节点)读写数据(如:文件、内存)的类,叫做节点流类。(术业有专攻)
节点类是跟数据源或数据目的地做直接连接用的。
在java.io包中,字节继承体系有三种节点类,而字符继承体系有四种节点类:
类型 | 字节流 | 字符流 |
---|---|---|
File | FileInputStream、FileOutputStream | FileReader、FileWriter |
Memory Array | ByteArrayInputStream、ByteArrayOutputStream | CharArrayReader、CharArrayWriter |
Memory String | StringReader、StringWriter | |
Piped | PipedInputStream、PipedOutputStream | PipedReader、PipedWriter |
交互(网络传输)用Memory Array
节点流的方法-InputStream
增加了一些方法
方法 | 含义 |
---|---|
void close() | 关闭此输入流并释放与该流关联的所有系统资源 |
int available() | 获取这个流中还有多少个byte的数据可以读取。返回值告诉我们还有多少个byte的数据可以读取。 注:这个方法会产生IOException异常,另外如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有作用 |
long skip(long n) | 跳过和放弃此输入流中的n个数据字节。返回值返回真正跳过的字节数 |
节点流的方法-OutputStream
方法 | 含义 |
---|---|
void write(byte[] b) | 将要输出的数组先放在一个byte数组中,然后用这个方法一次把一组数据输出出去 |
void write(byte[] b, int off, int len) | 将指定字节数组中从偏移量off开始的len个字节写入此输出流 |
void write(int b) | 将要输出的byte数据传给这个方法就可 |
void close() | 关闭此输入流并释放与该流关联的所有系统资源 |
void flush() | 刷新此输出流并强制写出所有缓冲的输出字节 |
使用write方法输出数据时,有些数据并不会马上输出到我们指定的目的地,通常会在内存中有个暂存区,有些输出的数据会暂时存放在这里,如果我们想要立刻把数据输出到目的地,不要放在暂存区中时,可以调用flush方法来对暂存区做清除的动作。
同样,数据输出完后,记得把它close,在调用close方法时,会先调用flush方法,以确保所有的数据都已经输出到目的地。
节点流的方法-Reader
Reader是输入字符数据用的类,它所提供的方法和InputStream类一样,差别在于InputStream类中用的是byte类型,而Reader类中用的是char类型。
Reader类中没有available方法,取而代之的是ready方法,这个方法会去检查Reader对象是否已经准备好输入数据了,如果是返回true,反之返回false。
节点流的方法-Writer
Writer类是输出字符数据的类,同样滴,提供的方法和OutputStream类中的方法类似,将OutputStream类中用到的byte类型,换成char类型。
Writer类另外提供了两个writer方法,所以Writer类有5个writer方法,多出来的两个只是把char数据换成String对象而已,方便输出字符的数据。
文件的访问
已经了解了流操作的方法和File类的使用…如何访问一个文件中的数据。
在java.io包中,可以用四种节点类来进行文件的访问:
FileInputStream
FileOutputStream
FileReader
FileWriter
FileInputStream
构造方法:
方法 | 含义 |
---|---|
FileInputStream(String fileurl) | 通过打开一个到实际文件的链接来创建一个FileInputStream,该文件通过文件系统中的路径名指定 |
FileInputStream(File fileobj) | 通过打开一个到实际文件的链接来创建一个FileInputStream,该文件通过文件系统中的File对象fileobj指定 |
File f = new File("d/io/a.txt");
FileInputStream fin1 = new FileInputStream(f);
FileInputStream fin2 = new FileInputStream("d/io/b.txt");
FileOutputStream
构造方法:
方法 | 含义 |
---|---|
FileOutputStream(String fileurl) | 创建一个向路径为fileurl的文件中写入数据的输出文件流 |
FileOutputStream(String fileurl, boolean append) | 创建一个向路径为fileurl的文件中写入数据的输出文件流,append为true为将字节写在文件尾处 |
FileOutputStream(File fileobj) | 创建一个向指定File对象fileobj表示的文件中写入数据的文件输出流 |
FileOutputStream(File fileobj, boolean append) | 创建一个向指定File对象fileobj表示的文件中写入数据的文件输出流,append为true为将字节写在文件尾处 |
我们在操作数据时,一定要及时备份…不然不小心覆盖掉了…就不是美好的故事了。
有写入数据操作的,提示给用户是追加写入还是覆盖。
FileReader
构造方法:
方法 | 含义 |
---|---|
FileReader(String fileurl) | 通过打开一个到实际文件的链接来创建一个FileReader,该文件通过文件系统中的路径名指定 |
FileReader(File fileobj) | 通过打开一个到实际文件的链接来创建一个FileReader,该文件通过文件系统中的File对象fileobj指定 |
File f = new File("d/io/a.txt");
FileReader fin1 = new FileReader(f);
FileReader fin2 = new FileReader("d/io/a.txt");
FileWriter
构造方法:
方法 | 含义 |
---|---|
FileWriter(String fileurl) | 创建一个向路径为fileurl的文件中写入数据的输出文件流 |
FileWriter(String fileurl, boolean append) | 创建一个向路径为fileurl的文件中写入数据的输出文件流,append为true为将字节写在文件尾处 |
FileWriter(File fileobj) | 创建一个向指定File对象fileobj表示的文件中写入数据的文件输出流 |
FileWriter(File fileobj, boolean append) | 创建一个向指定File对象fileobj表示的文件中写入数据的文件输出流,append为true为将字节写在文件尾处 |
处理流
只有字节或是字符为单位来对数据做输入输出是不够的,有时候需要一行一行的读数据,有时需要读取特定格式的数据,因此Java提供机制:能把数据流作连接(chain),让原本没有特殊访问方法的流,通过链接到特殊的流后,变成可以用特定的方法来访问数据。
“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
处理流类的构造函数中,都必须接收另外一个流对象作为参数。
一个流作为另一个流的对象参数。
种类/继承体系 | 字节 | 字符 |
---|---|---|
缓冲(Buffered) | BufferedInputStream,BufferedOutputStream | BufferedReader,BufferedWriter |
字符和字节转换 | InputStreamReader,OutputStreamWriter | |
对象序列化 | ObjectInputStream,ObjectOutputStream | |
特定数据类型访问 | DataInputStream,DataOutputStream | |
计数 | LineNumberInputStream | |
重复 | PushbackInputStream | |
打印 | PrintStream | PrintWriter |
常见处理流类-缓冲流(Buffered)
缓冲流对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。
Java提供了四种缓冲流:
构造方法 | 含义 |
---|---|
BufferedInputStream(InputStream in) | 创建了一个带有32字节缓冲区的缓冲输入流 |
BufferedInputStream(InputStream in, int size) | 创建了一个带有size大小缓冲区的缓冲输入流 |
BufferedOutputStream(OutputStream out) | 创建了一个带有32字节缓冲区的缓冲输出流 |
BufferedOutputStream(OutputStream out, int size) | 创建了一个带有size大小缓冲区的缓冲输流 |
BufferedReader(Reader in) | 创建一个使用默认大小输入缓冲区的缓冲字符输入流 |
BufferedReader(Reader in, int size) | 创建一个使用size大小输入缓冲区的缓冲字符输入流 |
BufferedWriter(Writer out) | 创建一个使用默认大小输出缓冲区的缓冲字符输出流 |
BufferedWriter(Writer out, int size) | 创建一个使用size大小输出缓冲区的缓冲字符输出流 |
缓冲流中的方法:
BufferedInputStream支持其父类的mark和reset方法。
BufferedReader提供了readLine方法用于读取一行字符串(以\r或\n分隔)。
BufferedWriter提供了newLine方法用于写入一个行分隔符(一行一行写数据,方便)。
对于BufferedOutputStream和BufferedWriter,写出的数据会先在内存中缓存,使用flush()方法将使内存中的数据立刻写出。
特定的,读、取用一样的流。
InputStream都能做BufferedInputStream的参数,一层套一层,里外的流要一样。
对象序列化
通过使用ObjectInputStream和ObjectOutputStream类保存和读取对象的机制,叫做序列化机制。
对象(Object)序列化是指将对象转换为字节序列的过程。
反序列化则是根据字节序列恢复对象的过程。
(转换了别人就看不懂了,加密安全性处理)
序列化一般用于:
永久性保存对象,保存对象的字节序列到本地文件中。
通过序列化对象在网络中传递对象。
通过序列化在进程间传递对象。
Serializable接口
只有一个实现Serializable接口的对象可以被序列化工具存储和恢复。
Serializable接口没有定义任何属性或方法。它只用来表示一个类可以被序列化。如果一个类可以序列化,它的所有子类都可以序列化。
一般用这个就可以了…
Externalizable接口
可以让需要序列化的类实现Serializable接口的子接口Externalizable。
Externalizable接口表示实现该接口的类在序列化中由该类本身来控制信息的写出和读入。
ObjectInputStream类
ObjectInputStream类继承InputStream类,并实现了ObjectInput接口。它负责从流中读取对象。
构造方法:ObjectInputStream(InputStream in)
主要方法:readObject(Object obj) 从指定的InputStream中读取对象
ObjectOutputStream类
ObjectOutputStream类继承OutputStream类,并实现了ObjectOutput接口。它负责向流写入对象。
构造方法:ObjectOutputStream(OutputStream out)
主要方法:writeObject(Object obj) 向指定的OutputStream中写入对象obj
对象序列化的条件
-
该对象类必须实现Serializable接口
-
如果该类有直接或者间接的不可序列化的基类,那么该基类必须有一个默认的构造器(构造函数)。该派生类需要负责将其基类中的数据写入流中。
-
建议所有可序列化类都显示声明serialVersionUID值:
- serialVersionUID在反序列化过程中用于验证序列化对象的发送者和接受者是否为该对象加载了与序列化兼容的类。
- 如果接收者加载的该对象的类的serialVersionUID与对应的发送者的类的版本号不同,则反序列化将会导致InvalidClassException。
- serialVersionUID值是long类型的。
序列化前后,验证加载的是同一个对象。
transient关键字
transient修饰的属性不进行序列化的操作,起到一定消息屏蔽的效果。
被transient修饰的属性可以正确的创建,但被系统赋为默认值。即int类型为0,String类型为null。
注:ObjectInputStream和ObjectOutputStream类不会保存和读写对象中的transient和static类型的成员变量。