File 文件操作类
- File类使用-准备
方法 | 解释 |
---|---|
public File(String pathname) | 创建指定路径文件对象 |
public File(String parent, String child) | 同上,但可指明父路径和子路径 |
- File类常用方法-基本文件操作
方法 | 说明 |
---|---|
public boolean exists() | 测试指定路径中文件或者目录是否存在 |
public boolean isDirectory() | 判定一个文件是目录 |
public boolean isFile() | 判定是否是文件 |
public boolean delete() | 删除文件 |
public boolean createNewFile() throws IOException | 创建一个新文件 |
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
String path="E:\\java_code\\file\\";
String name="demo.txt";
String pathname=path+name;
File file=new File(pathname);
if(file.exists()){
file.delete();
System.out.println("文件"+pathname+"存在,删除之");
}else{
try{
file.createNewFile();
System.out.println("文件"+pathname+"不存在,创建之");
} catch (IOException e) {
System.out.println("文件"+pathname+"创建失败");
e.printStackTrace();
}
}
}
}
- File类常用方法-目录操作
方法 | 解释 |
---|---|
public boolean mkdir() | 创建一个空目录 |
public boolean mkdirs() | 创建目录(无论有多少级父目录,都会创建) |
public String getParent() | 取得父路径 |
public File getParentFile() | 取得父File对象 |
- File类常用方法-文件属性操作操作
方法 | 解释 |
---|---|
public long length() | 取得文件大小(字节) |
public long lastModified() | 最后一次修改日期 |
- 绝对路径与相对路径
绝对路径:
是指目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径。完整的描述文件位置的路径就是绝对路径 。如: E:\javacode\Java8\Test.java 。
相对路径:
相对与某个基准目录的路径 。如当前路径为E:\javacode ,要描述上述路径( E:\javacode\Java8\Test.java ),只需输入: Java8\Test.java 。此时的路径是相对 E:\javacode 来说的。 - File类常用方法-其他操作
方法 | 解释 |
---|---|
public File[] listFiles() | 列出一个目录指定的全部组成 |
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
File file=new File("C:\\users\\whb\\");
listAllFiles(file);
}
private static void listAllFiles(File file) {
if(file.isDirectory()){
File[] result=file.listFiles();
if(result!=null){
for(File file2:result){
listAllFiles(file2);
}
}
}else{
System.out.println(file);
}
}
}
流
- 流:
数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。 - 输入就是将数据从各种输入设备(包括文件、键盘等)中读取到内存中。
输出则正好相反,是将数据写入到各种输出设备(比如文件、显示器、磁盘等)。 - 字节流:数据流中最小的数据单元是字节 InputStream、OutputStream
字符流:数据流中最小的数据单元是字符 Reader、Writer
1. 字节流(FileInputStream 和 FileOutputStream)
FileInputStream:从文件系统中的某个文件中获得输入字节
FileOutputStream:是用于将数据写入到输出流 File 或一个 FileDescriptor 。
public static void main(String[] args) throws IOException{
FileInputStream fin=new FileInputStream("E:\\bit\\bit.jpg");
FileOutputStream fout=new FileOutputStream("E:\\bit\\bit\\BitCopy.jpg");
int len=0;
byte[] buff=new byte[1024];
while((len=fin.read(buff))!=-1){
fout.write(buff,0,len);
}
fin.close();
fout.close();
}
2. 字节缓冲流(BufferedInputStream 和 BufferedOutputStream)
为什么需要缓冲流?当我们用read()读取文件时,每读一个字节,访问一次硬盘,效率很低。文件过大时,操作起来也不是很方便。因此我们需要用到buffer缓存流动,当创建buffer对象时,会创建一个缓冲区数组。当我们读一个文件时,先从硬盘中读到缓冲区,然后直接从缓冲区输出即可,效率会更高。
public static void main(String[] args) throws IOException {
File file=new File("bit.txt");
if(!file.isFile()){
return;
}
BufferedInputStream bfis=new BufferedInputStream(new FileInputStream(file));
// copy到src目录下
BufferedOutputStream bfos=new BufferedOutputStream(new FileOutputStream("src\\"+file.getName()));
byte[] bytes=new byte[1024];
int temp=0;
while((temp=bfis.read())!=-1){ // 读
bfos.write(bytes,0,temp); // 写
}
bfos.flush();
bfos.close();
bfis.close();
System.out.println("copy成功!");
}
3. 字符流(FileReader 和 FileReader)
FileReader:从文件中读取内容。FileReader 是用于读取字符流。 要读取原始字节流,请考虑使用 FileInputStream。
FileWriter:向文件中写入内容。FileWriter 是用于写入字符流。 要编写原始字节流,请考虑使用 FileOutputStream。
方法 | 解释 |
---|---|
FileReader(File file) | 创建一个新的FileReader,给出 File 读取。 |
FileReader(String fileName) | 创建一个新的FileReader ,给定要读取的文件的名称。 |
public static void main(String[] args) throws IOException {
// 创建输入流对象
FileReader fr=new FileReader("E:\\bit\\bitSrc.java");
// 创建输出流对象
FileWriter fw=new FileWriter("E:\\bit\\bitCopy.java");
// 读写数据
int ch;
while((ch=fr.read())!=-1){
fw.write(ch);
}
// 释放资源
fr.close();
fw.close();
}
4. 字符缓冲流(BufferedReader 和 BufferedWriter)
BufferedReader 用于加快读取字符的速度
BufferedWriter 用于加快写入的速度
当 BufferedReader在读取文本文件时,会先尽量从文件中读入字符数据并放满缓冲区,而之后若使用read()方法,会先从缓冲区中进行读取。如果缓冲区数据不足,才会再从文件中读取,使用 BufferedWriter 时,写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出。
- 从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取
- 将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入
方法 | 解释 |
---|---|
BufferedReader(Reader in) | 创建使用默认大小的输入缓冲区的缓冲字符输入流。 |
BufferedReader(Reader in, int sz) | 创建使用指定大小的输入缓冲区的缓冲字符输入流。 |
BufferedWriter(Writer out) | 创建使用默认大小的输出缓冲区的缓冲字符输出流。 |
BufferedWriter(Writer out, int sz) | 创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。 |
5. 字节流对比字符流
- 字节流操作的基本单元是字节;
字符流操作的基本单元为Unicode码元。 - 字节流在操作的时候本身不会用到缓冲区的,是与文件本身直接操作的;
而字符流在操作的时候使用到缓冲区的。 - 所有文件的存储都是字节(byte)的存储,在磁盘上保留的是字节。
- 在使用字节流操作中,即使没有关闭资源(close方法),也能输出;而字符流不使用close方法的话,不会输出任何内容。
6. 字符字节转换流(InputStreamReader 和 OutputStreamWriter)
InputStreamReader:将输入的字节流转换成字符流
OutputStreamWriter:将输出的字符流转换成字节流
// InputStreamReader
public static void main(String[] args) {
// 创建字节流对象 System.in 代表从控制台输入
InputStream in=System.in;
// 创建字符流对象
BufferedReader br=null;
BufferedWriter bw=null;
try{
// 实例化字符流对象,通过InputStreamReader将字节输入流转换成字符输入流
br=new BufferedReader(new InputStreamReader(in));
bw=new BufferedWriter(new FileWriter("a.txt"));
// 定义读取数据的行
String line=null;
// 读取数据
while((line=br.readLine())!=null){
// 如果输入的是 exit 就退出
if("exit".equals(line)){
break;
}
// 将数据写入文件
bw.write(line);
// 写入新的一行
bw.newLine();
// 刷新数据缓冲
bw.flush();
}
}catch(Exception e){
e.printStackTrace();
}finally {
// 释放资源
try{
if(bw!=null)
bw.close();
if(br!=null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// OutputStreamWriter
public static void main(String[] args) {
// 定义字节输出流的对象 System.out
OutputStream out=System.out;
// 定义字符流的对象
BufferedWriter bw=null;
BufferedReader br=null;
try{
// 通过OutputStreamWriter将字符流转换成字节流对象
bw=new BufferedWriter(new OutputStreamWriter(out));
br=new BufferedReader(new FileReader("a.txt"));
String line=null;
// 读取数据
while((line=br.readLine())!=null){
// 输出到控制台
bw.write(line);
// 新的一行
bw.newLine();
// 刷新缓冲
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
// 释放资源
try{
if(bw!=null)
bw.close();
if(br!=null)
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
IO过程:
单纯站在数据角度:CPU直接从内存里读取数据,不会和外设打交道,为什么呢?因为硬盘太慢了…
所以数据要能够被CPU处理,就必须先被拿到内存,才能够被CPU处理!
将数据从输入设备拿到内存,我们称之为 input,将数据从内存输出到外设,我们称之为 output,简称这个过程为IO。
文件读写:硬盘
硬盘既可以充当输入设备(input),又可以充当输出设备(output)
序列化与反序列化
序列化:把内存里面的这些对象给变成一连串的字节描述的过程。
(序列化本身与语言无关)
什么时候需要序列化?
1、把内存中的对象状态保存到一个文件中或者数据库中的时候;
2、用套接字在网络上传送对象的时候。
静态变量的值是不会被进行序列化的
transient 修饰的变量,是不能被序列化的
import java.io.*;
public class Test2 {
public static void main(String[] args) throws Exception {
serializePerson();
Person person=deserializePerson();
System.out.println(person.toString());
}
// 序列化
private static void serializePerson() throws IOException {
Person person=new Person();
person.setName("bit");
person.setAge(10);
person.setSex("男");
person.setStuId(100);
// ObjectOutputStream 对象输出流,将person对象存储到E盘的 person.txt 文件中,完成对 person 对象的序列化操作
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("E:/person.txt")));
oos.writeObject(person);
System.out.println("person对象序列化成功!");
oos.close();
}
// 反序列化
private static Person deserializePerson() throws Exception {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("E:/person.txt")));
Person person=(Person)ois.readObject();
System.out.println("person对象反序列化成功!");
return person;
}
}
ObjectOutputStream 代表对象输出流:它的 writeObject(Object obj) 方法可对参数指定的 obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。
ObjectInputStream 代表对象输入流:它的 readObject() 方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
小结:
- 一个类如果想被序列化,那么需要实现一个Serializable接口。
- 类中的静态变量的值是不会被进行序列化的,transient 修饰的属性,是不会被序列化的,内置类型为对应0值,引用类型为null。
- 在实现这个Serializable 接口的时候,一定要给这个 serialVersionUID 赋值,最好设置为1L,这个L最好大写来区分,不然小写看起来像是1,不同的 serialVersionUID 的值,会影响到反序列化。