1、 文件操作
File 类:文件和目录路径名的抽象表示。只能操作文件的属性,文件的内容是不能操作的。
(1)File类基本操作
- 4个static方法
System.out.println(File.pathSeparator); //路径分割符字符:;
System.out.println(File.pathSeparatorChar); //路径分割符:;
System.out.println(File.separator); //名称分割符字符:\
System.out.println(File.separatorChar); //名称分割符:\
(2)File类构造方法
//1、从父路径名字符串和子路径名字符串创建新的 File实例
// File(String parent ,String child)
File f6 = new File("D:","IO\\a.txt");
//2、通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
//File(String pathname)
File f5 = new File("D:"+File.separator+"IO"+File.separator+"a.txt");
//3、从父抽象路径名和子路径名字符串创建新的 File实例
// File(File parent ,String child)
File f3 = new File("D:");
File f4 = new File(f3,"IO");
//4、将给定的file:URI转换为抽象路径来创建新的 File实例
//File(URI uri);
(3)File类操作深入
- 创建方法
boolean createNewFile(); //不存在返回true 存在返回false
boolean mkdir(); //创建目录,如果上一级目录不存在,则会创建失败
boolean mkdirs(); //创建多级目录,如果上一级目录不存在也会自动创建
- 删除方法
boolean delete(); //删除文件或目录,如果表示目录,则目录下必须为空才能删除
boolean deleteOnExit(); //文件使用完成后删除
- 判断方法
boolean canExecute(); //判断文件是否可执行
boolean canRead(); //判断文件是否可读
boolean canWrite(); //判断文件是否可写
boolean exists(); //判断文件或目录是否存在
boolean isDirectory(); //判断此路径是否为一个目录
boolean isFile(); //判断是否为一个文件
boolean isHidden(); //判断是否为隐藏文件
boolean isAbsolute(); //判断是否是绝对路径 文件不存在也能判断
- 获取方法
String getName(); //获取此路径表示的文件或目录名称
String getPath(); //将此路径名转换为路径名字符串
String getAbsolutePath(); //返回此抽象路径名的绝对形式
String getParent(); //如果没有父目录返回null
long lastModified(); //获取最后一次修改的时间
long length(); //返回由此抽象路径名表示的文件的长度。
boolean renameTo(File f); //重命名由此抽象路径名表示的文件。
File[] liseRoots();//获取机器盘符
String[] list(); //返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。
String[] list(FilenameFilter filter); //返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。
(4)操作练习
- 创建一个指定文件的文件
//从父抽象路径名和子路径名字符串创建新的 File实例。
File dir = new File("D:"+File.separator+"IO");
File file = new File(dir,"a.txt");
//判断dir 是否存在且表示一个目录
if(!(dir.exists()||dir.isDirectory())){
//不存在,则创建
dir.mkdirs();
//创建 a.txt文件
file.createNewFile(); //抛出异常
}
//返回由此抽象路径名表示的文件或目录的名称。
System.out.println(file.getName()); //a.txt
//返回此抽象路径名的父null的路径名字符串,如果此路径名未命名为父目录,则返回null。
System.out.println(file.getParent());//D:\IO
//将此抽象路径名转换为路径名字符串。
System.out.println(file.getPath()); //D:\IO\a.txt
- 给定目录下的所有文件夹和文件夹里面的内容
public static void getFileList(File file){
//第一级子目录
File[] files = file.listFiles();
for(File f:files){
//打印目录和文件
System.out.println(f);
if(f.isDirectory()){
getFileList(f);
}
}
}
public static void main(String[] args) throws Exception {
File f = new File("D:"+File.separator+"WebStormFile");
getFileList(f);
}
2、字符流与字节流
(1)流的基本概念
-
IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式。
-
按方向分为输入流和输出流。以内存为参照,数据从数据源中读取到内存为输入流,反之为输出流。
-
流按照类型分,分为字节流、字符流和对象流。数据的传输都是以字节为单位传输。所以其本质都是字节流。
(2)OutputStream字节输出流
- OutputStream类是Java IO API中所有输出流的基类。子类包括以下内容。
OutputStream //以字节为单位的输出流的超类,提供了write()函数从输出流中读取字节数据。
ByteArrayOutputStream //字节数组输出流,写入ByteArrayOutputStream的数据被写入到一个byte数组,缓冲区会随着数据的不断写入而自动增长,可使用toByteArray()和toString()获取数据。
PipedOutputStream //管道输出流,和PipedInputStream一起使用,能实现多线程间的管道通信。
FilterOutputStream //过滤输出流,是DataOutputStream,BufferedOutputStream和PrintStream的超类
DataOutputStream //数据输出流,用来装饰其他的输出流,允许应用程序以与机器无关方式向底层写入基本Java数据类型。
BufferedOutputStream //缓冲输出流,它的作用是为另一个输出流添加缓冲功能。
PrintStream //打印输出流,用来装饰其他输出流,为其他输出流添加功能,方便的打印各种数据值
FileOutputStream //文件输出流,通常用于向文件进行写入操作。
ObjectOutputStream //对象输出流,它和ObjectInputStream一起对基本数据或者对象的持久存储。
总结
-
OutputStream是一个典型的装饰者模式,使用的时候直接new子类。
-
OutputStream可以输出到console,文件,磁盘等目标媒介中。
示例
public static void main(String args[]) throws Exception
{
// 第1步、使用File类找到一个文件
File f = new File("d:\\51gjie.txt"); // 声明File对象
// 第2步、通过子类实例化父类对象
OutputStream out = null; // 准备好一个输出的对象
try
{
out = new FileOutputStream(f); // 通过对象多态性,进行实例化
// 第3步、进行写操作
String str = "欢迎来到www.51gjie.com"; // 准备一个字符串
byte b[] = str.getBytes(); // 只能输出byte数组,所以将字符串变为byte数组
out.write(b); // 将内容输出,保存文件
}
catch(IOException e)
{}
finally
{
out.close(); // 关闭输出流
}
}
(3)InputStream字节输入流
此抽象类是表示字节输入流的所有类的超类。需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法。
BufferedInputStream // 提供了缓冲功能。
DataInputStream // 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
PipedInputStream // 允许以管道的方式来处理流。当连接到一个PipedOutputStream后,它会读取后者输出到管道的数据。
PushbackInputStream // 允许放回已经读取的数据。
SequenceInputStream // 能对多个inputstream进行顺序处理。
示例
public class InputStreamDemo01{
public static void main(String args[]) throws Exception{ // 异常抛出,不处理
// 第1步、使用File类找到一个文件
File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象
// 第2步、通过子类实例化父类对象
InputStream input = null ; // 准备好一个输入的对象
input = new FileInputStream(f) ; // 通过对象多态性,进行实例化
// 第3步、进行读操作
byte b[] = new byte[1024] ; // 所有的内容都读到此数组之中
input.read(b) ; // 读取内容 网络编程中 read 方法会阻塞
// 第4步、关闭输出流
input.close() ; // 关闭输出流
System.out.println("内容为:" + new String(b)) ; // 把byte数组变为字符串输出
}
};
总结
-
一个从流中读取数据的组件尝试用InputStream替代任何它的子类(比如FileInputStream)进行开发。能够让兼容任何类型而非某种确定类型的输入流。
-
Java中的Inputstream是不能重复读取的,读取是单向的。有一个pos指针指示每次读取之后下一次要读取的起始位置,当读到最后一个字符的时候,pos指针不会重置。
*
(4)Writer字符输出流
- Writer类是Java IO中所有Writer的基类。
BufferedWriter //字符缓冲输出流
FileWriter //用来写入字符串到文件
OutputStreamWriter //转换流:写入字符,同时可以设置编码集。
- 例子
public class WriterDemo01{
public static void main(String args[]) throws Exception{ // 异常抛出,不处理
// 第1步、使用File类找到一个文件
File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象
// 第2步、通过子类实例化父类对象
Writer out = null ; // 准备好一个输出的对象
out = new FileWriter(f) ; // 通过对象多态性,进行实例化
// 第3步、进行写操作
String str = "Hello World!!!" ; // 准备一个字符串
out.write(str) ; // 将内容输出,保存文件
// 第4步、关闭输出流
out.close() ; // 关闭输出流
//public class FileWriter extends OutputStreamWriter
//public class OutputStreamWriter extends Writer FileWriter实际上继承自 OutputStreamWriter
}
};
(5)Reader字符输入流
- Reader是一个抽象类,它是以字符为单位的输入流的公共父类。
BufferedReader //从流里面读取文本,通过缓存的方式提高效率,读取的内容包括字符、数组和行。缓存的大小可以指定,也可以用默认的大小,大部分情况下,默认大小就够了。
InputStreamReader //转换流:把字节翻译成字符的,可以处理乱码问题。
FileReader //方便读取字符文件的。
- 使用read()读取单个字符并输出
import java.io.*;
class FileReaderDemo
{
public static void sop(Object obj)
{
System.out.print(obj);
}
public static void main(String[] args)throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联起来。
//要保证该文件是已经存在的。如果不存在,会发生异常,即FileNotFoundException
FileReader fr = new FileReader("F:\\myfile\\test.txt");
//调用读取流对象的read方法。
//read方法:一次读取一次字符,而且会自动往后面读取字符。
int ch = 0;
while((ch=fr.read())!=-1)
{
sop((char)ch);
}
/*
while(true)
{
int ch = fr.read();
if(ch==-1)
break;
sop((char)ch); //读取文件中的一个字符
}
*/
fr.close();
}
}
(6)字节流与字符流的区别
- 字符流使用了缓冲区,而字节流没有使用缓冲区;
详细API学习路径:http://www.51gjie.com/java/695.html
3、序列化与反序列化
- Java 对象序列化就是把对象写入到输出流中,用来存储或传输;反序列化就是从输入流中读取对象;
- 序列化是基于字节的,不能使用基于字符的流;
(1)实现
- 枚举类型对象都是默认可以被序列化的
// Gender类,表示性别
// 每个枚举类型都会默认继承类java.lang.Enum,而Enum类实现了Serializable接口,所以
public enum Gender {
MALE, FEMALE
}
- 实现了 java.io.Serializable 接口序列化
// Person 类实现了 Serializable 接口,它包含三个字段。另外,它还重写了该类的 toString() 方法,以方便打印 Person 实例中的内容。
public class Person implements Serializable {
private String name = null;
private Integer age = null;
private Gender gender = null;
public Person() {
System.out.println("none-arg constructor");
}
public Person(String name, Integer age, Gender gender) {
System.out.println("arg constructor");
this.name = name;
this.age = age;
this.gender = gender;
}
// 省略 set get 方法
@Override
public String toString() {
return "[" + name + ", " + age + ", " + gender + "]";
}
}
- 序列化程序示例
// SimpleSerial类,是一个简单的序列化程序,它先将Person对象保存到文件person.out中,然后再从该文件中读出被存储的Person对象,并打印该对象。
public class SimpleSerial {
public static void main(String[] args) throws Exception {
File file = new File("person.out");
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file)); // 注意这里使用的是 ObjectOutputStream 对象输出流封装其他的输出流
Person person = new Person("John", 101, Gender.MALE);
oout.writeObject(person);
oout.close();
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file)); // 使用对象输入流读取序列化的对象
Object newPerson = oin.readObject(); // 没有强制转换到Person类型
oin.close();
System.out.println(newPerson);
//arg constructor
//[John, 31, MALE]
}
}
-
序列化一个对象首先要创造某些OutputStream对象(如FileOutputStream、ByteArrayOutputStream等),然后将其封装在一个ObjectOutputStream对象中,在调用writeObject()方法即可序列化一个对象;
-
反序列化的过程需要创造InputStream对象(如FileInputstream、ByteArrayInputStream等),然后将其封装在ObjectInputStream中,在调用readObject()即可;
-
String类型的对象、枚举类型的对象、数组对象,都是默认可以被序列化的;
(2)transient关键字
- 有些时候不能使用默认序列化机制。当类的某个字段被 transient 修饰,默认序列化机制就会忽略该字段。此处将Person类中的age字段声明为transient,如下所示:
public class Person implements Serializable {
...
transient private Integer age = null;
...
}
// 再执行SimpleSerial应用程序,会有如下输出:
//arg constructor
//[John, null, MALE]