File类
File类可以用来新建、删除、重命名文件和目录,但它不能访问文件内容本身,访问文件内容需要使用输入输出流
访问文件名相关的方法
- String getName():返回File对象所表示的文件名或路径名
- String getPath():返回File对象所对应的路径名
- String getAbsolutePath():返回次Fille对象所对应的绝对路径
- boolean renameTo(File newName):重命名此File对象所对应的文件或目录,重命名成功返回true
文件检测相关的方法
- boolean exists():判断File对象对应的文件或目录是否存在
- boolean canWrite(): 判断File对象对应的文件或目录是否可写
- boolean canRead():判断File对象对应的文件或目录是否可读
- boolean isFile():判断File对象对应的是否为文件
- boolean isDirectory():判断File对象对应的是否为目录
文件操作相关方法
- long length():返回文件内容长度
- boolean createNewFile():当此File对象所对应的文件不存在时,该方法将新建一个该File对象所指定的新文件,创建成功返回true
- boolean delete():删除File对应的文件
目录操作相关的方法
- boolean mkdir():创建一个File对象所对应的目录
- String[] list():列出File对象的所以子文件名和路径名
- File[] listFiles():列出File对象的所有子文件
- getParentFile():得到文件的父级目录
文件过滤器
File类的list方法了一返回File对象的所有子文件名,该方法中可以接收一个FilenameFilter参数,通过该参数可以只列出符合条件的文件
public static void main(String[] args) {
--------以当前路径来创建一个file对象
File file = new File(".");
--------如果文件名以.java结尾或文件对应一个路径,则返回true
file.list((dir,name)-> name.endsWith(".java") || new File(name).isDirectory());
System.out.println(file);
}
字节流和字符流
InputStream和Reader是所有输入流的抽象基类,本身不能创建实例来执行输入,但可以使用FileInputStream和FileReader来读取文件
public static void main(String[] args) {
try {
//准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
File f =new File("d:/lol.txt");
//创建基于文件的输入流
FileInputStream fis =new FileInputStream(f);
//创建字节数组,其长度就是文件的长度
byte[] all =new byte[(int) f.length()];
//以字节流的形式读取文件所有内容
fis.read(all);
for (byte b : all) {
//打印出来是65 66
System.out.println(b);
}
//每次使用完流,都应该进行关闭
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
OutputStream和Writer是所有输出流的抽象基类,本身不能创建实例来执行输出,但可以使用FileOutputStream和FileWriter来读取文件,如果用来输出字符串内容使用FileWriter会更好些
处理流的用法
使用处理流的优势:输入输出更简单;执行效率更高
使用PrintStream来包装OutputStream
FileOutputStream fileOutputStream = new FileOutputStream("F://tcp.txt");
PrintStream printStream = new PrintStream(fileOutputStream);
字符流
FileReader:用来读取访问文件
FileWriter:用来写入文件
StringReader:用字符流来读取字符串,该对象传入的是字符串节点
StringWriter:用字符流来写入字符串,该对象实际上是以一个StringBuffer作为输出节点,字符串的长度是可变的
StringWriter stringWriter = new StringWriter();
stringWriter.write("你好");
转换流
InputStreamReader:将字节输入流转换成字符输入流
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
OutputStringWriter:将字节输出流转换成字符输出流
BufferedReader: 用来将Reader再次包装变成BufferedReader ,可以利用 bufferedReader.readLine()来读取一行,BufferedReader 具有缓冲功能,它一次读取一行文本,以换行符为标志,如果没有读取到换行符,则程序阻塞,等待读取到换行符为止,这也是在控制台只有按下回车才会打印出内容的原因
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
bufferedReader.readLine();
关闭流的方法
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
在try的作用域里关闭文件流
在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用
在finally中关闭
这是标准的关闭流的方式
1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
2. 在finally关闭之前,要先判断该引用是否为空
3. 关闭的时候,需要再一次进行try catch处理
这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~
public static void main(String[] args) {
File f = new File("d:/lol.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally 里关闭流
if (null != fis)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
字符编码问题
FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:
new InputStreamReader(new FileInputStream(f),Charset.forName(“UTF-8”));
public class TestStream {
-----为什么中字前面有一个?
如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,
叫做BOM用来标志这个文件是用UTF-8来编码的
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
File f = new File("E:\\project\\j2se\\src\\test.txt");
System.out.println("默认编码方式:"+Charset.defaultCharset());
//FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
//而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
try (FileReader fr = new FileReader(f)) {
char[] cs = new char[(int) f.length()];
fr.read(cs);
System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替
//并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
char[] cs = new char[(int) f.length()];
isr.read(cs);
System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
序列化
序列化机制允许将实现序列化的java对象转换成字节序列,也可使用反序列化将从二进制流中恢复Java对象;一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口;web应用中需要保存到HttpSession或ServletContext属性的java对象都应该实现序列化
使用对象流实现序列化
ObjectOutputStream,是一个处理流,必须建立在其它节点流之上,使用ObjectOutputStream对象的writeObject可以将一个对象写入输出流```
public class ScannerSerizable implements Serializable {
String name;
int age;
public ScannerSerizable(String name,int age)
{
this.name=name;
this.age=age;
}
}
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream(new File("F://java.txt"));
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
ScannerSerizable person = new ScannerSerizable("张三",20);
objectOutputStream.writeObject(person);
}
使用 ObjectInputStream进行反序列化
FileInputStream fileInputStream = new FileInputStream("F://java.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream );
ScannerSerizable person2 =(ScannerSerizable) objectInputStream.readObject();
使用引用的序列化
如果某个类的成员变量的类型不是基本类型而是引用类型,那么这个引用类型必须也是可序列化的,否则拥有该引用类型的类也不可序列化,如下面代码,如果student对象的类没有可序列化,不管ScannerSerizable 有没有实现Serializable接口,ScannerSerizable 都是不可序列化的
public class ScannerSerizable implements Serializable
{
String name;
int age;
private ScannerSerizable student;
}
练习:准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组
然后把该数组序列化到一个文件heros.lol
接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样
public static void main(String[] args) throws IOException, ClassNotFoundException
{
ScannerSerizable scannerSerizable1 = new ScannerSerizable("张1",20);
ScannerSerizable scannerSerizable2 = new ScannerSerizable("张2",20);
ScannerSerizable scannerSerizable3 = new ScannerSerizable("张3",20);
ScannerSerizable scannerSerizable4 = new ScannerSerizable("张4",20);
ScannerSerizable scannerSerizable5 = new ScannerSerizable("张5",20);
ScannerSerizable scannerSerizable6 = new ScannerSerizable("张6",20);
ScannerSerizable scannerSerizable7 = new ScannerSerizable("张7",20);
ScannerSerizable scannerSerizable8 = new ScannerSerizable("张8",20);
ScannerSerizable scannerSerizable9 = new ScannerSerizable("张9",20);
ScannerSerizable scannerSerizable10 = new ScannerSerizable("张10",20);
ScannerSerizable[] scannerSerizables = new ScannerSerizable[10];
scannerSerizables[0] = scannerSerizable1;
scannerSerizables[1] = scannerSerizable2;
scannerSerizables[2] = scannerSerizable3;
scannerSerizables[3] = scannerSerizable4;
scannerSerizables[4] = scannerSerizable5;
scannerSerizables[5] = scannerSerizable6;
scannerSerizables[6] = scannerSerizable7;
scannerSerizables[7] = scannerSerizable8;
scannerSerizables[8] = scannerSerizable9;
scannerSerizables[9] = scannerSerizable10;
FileOutputStream fileOutputStream = new FileOutputStream("F://heros.lol");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
for(int i =0;i<10;i++)
{
objectOutputStream.writeObject(scannerSerizables[i]);
}
FileInputStream fileInputStream = new FileInputStream("F://heros.lol");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
for(int i =0;i<10;i++)
{
ScannerSerizable scannerSerizable = (ScannerSerizable) objectInputStream.readObject();
System.out.println("姓名:"+scannerSerizable.getName()+";age:"+scannerSerizable.getAge());
}
}