File类
- File能新建、删除、重命名文件和目录,但File不能访问文件内容本身。如果需要访问文件内容本身,则需要使用IO流
- 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录
- File对象可以作为参数传递给流的构造器
常用构造器
public File(String pathname)
:以pathname为路径创建File对象,可以是绝对路径或者相对路径
public File(String parent, String child)
:以parent为父路径,child为子路径创建File对象(例:File file3 = new File("D:\\workspace_idea1","JavaSenior");
,在parent路径下创建了一个child)
public File(File parent, String child)
:在父File的路径下创建一个child
- Java支持跨平台运行,所以路径格式要格外注意。为了解决这个隐患,File类提供了一个常量
public static final String separator
,可根据操作系统,动态匹配对应的格式。如下:
File file1 = new File("d:\\coding\\info.txt")
File file2 = new File("d:" + File.separator + "coding" + File.separator + "info.txt");
常用方法
方法 | 功能 |
---|---|
String getAbsolutePath() | 获取绝对路径 |
String getPath() | 获取构造参数输入的路径 |
String getName() | 获取名称 |
String getParent() | 获取上层文件目录路径,若无返回null |
long length() | 获取文件长度(即字节数)。不能获取目录的长度 |
long lastModified() | 获取最后一次修改时间,毫秒值 |
String[] list() | 获取指定目录下所有文件或者文件目录的名称数组 |
File[] listFiles() | 获取指定目录下所有文件或者文件目录的File数组 |
boolean renameTo(File dest) | 把文件重命名为指定的文件路径 |
boolean isDirectory() | 判断是否是文件目录 |
boolean isFile() | 判断是否是文件 |
boolean exists() | 判断是否存在 |
boolean canRead() | 判断是否可读 |
boolean canWrite() | 判断是否可写 |
boolean isHidden() | 判断是否隐藏 |
boolean createNewFile() | 创建文件,若已存在,则不创建并返回false |
boolean mkdir() | 创建文件目录,若已存在就不创建;若上层目录不存在,则不创建 |
boolean mkdirs() | 创建文件目录,若上层文件目录不存在,则一并创建 |
boolean delete() | 删除文件或文件夹 |
如果创建文件或文件夹没有写盘符路径,那么默认在项目路径下
Java中的删除不走回收站
要删除一个文件夹,请注意该文件夹内不能包含文件或子文件夹
IO流
java.io包下提供了各种“流”类和接口,用于获取不同种类的数据,处理设备之间的数据传输,并通过标准的方法输入或输出数据
流的分类
- 按数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据的流向不同分为:输入流,输出流
- 按流的作用不同分为:节点流(数据、文件的流形式本身),处理流(处理节点流或处理流的流,一个节点流可以有多层处理流)
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
- Java的IO流共涉及40多个类,实际上非常规则,都是从上面4个抽象基类派生的
- 派生出来的子类名称都是以其父类名作为后缀
- 节点流:直接从数据源或目的地读写数据
- 处理流:不直接连接到数据源或目的地,而是“包裹”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写能力
流的体系结构
抽象基类 | 节点流(文件流) | 缓冲流(处理流的一种) |
---|---|---|
InputStream | FileInputStream | BufferInputStream |
OutputStream | FileOutputStream | BufferInputStream |
Reader | FileReader | BufferInputStream |
Writer | FileWriter | BufferInputStream |
数据的读入
//1.实例化File类对象,指明要操作的文件
File file = new File("hello.txt");
//2.提供具体的流
FileReader fr = new FileReader(file);//往往会有异常需要处理。一般都用try-catch处理
//3.数据的读入
int data = fr.read();//read()返回读入的一个字符,如果达到文件末尾,返回-1
while(data != -1){
System.out.println((char)data);
data = fr.read();
}
//4.流的关闭操作
//因为垃圾回收机制只回收JVM堆内存里的对象空间,对于其他物理连接,比如数据库连接、IO流、Socket连接无能为力,所以这些连接用完后要手动关闭,否则会导致内存泄露
fr.close();//要用finally包一下
异常的处理:为了保证流资源一定可以执行关闭操作,需要使用try-catch-finally
上面的3步可以改进成:
//read(char[] cbuf)返回每次读入cbuf数组中的字符个数。如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(sbuf)) != -1){
for(int i = 0; i < len; i++){
System.out.print(cbuf[i]);
}
//这里也可以替换成
//String str = new String(cbuf, 0, len);
//System.out.print(str);
};
数据的写出
//1.提供File类的对象,指明写出到的文件
File file = new File("hello.txt");
//2.提供FileWriter的对象,用于数据的写出
FileWriter fw = new FileWriter(file);
//3.写出的操作
fw.write("I have a dream!");
//4.流资源的关闭
fw.close();
说明:
- 输出操作对应的File若不存在,会自动创建此文件
- 如果存在,且流使用的构造器是FileWriter(file, false)/FileWriter(file),则对原有文件覆盖
若流构造器是FileWriter(file, true),不会覆盖原文件,会在其后追加内容
数据的读入和写出
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File destFile = new File("hey.txt");
//2.创建输入流和输出流的对象
FileReader fr = new FileReader(srcFile);
FileWriter fw = new FileWriter(destFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while((len = fr.read(cbuf)) != -1){
fw.write(cbuf, o, len);
}
//4.关闭流资源
fw.close();
fr.close();
不能使用字符流处理字节文件
- 对于文本文件,一般使用字符流处理
- 对于非文本文件,只能使用字节流处理
若用字节流处理字符流,如果只是复制,是不会出现乱码的,因为它只是在“搬运”;但如果在控制台进行打印,可能会出现乱码,因为打印输出牵扯到字符编码的问题。
//1.造文件
File file = new File("hello.txt");
//2.造流
FileInputStream fis = new FileInputStream(file);
//3.读数据
byte[] buffer = new byte[5];
int len;//记录每次读取的字节个数
while((len = fis.read(buffer)) != -1){
String str = new String(buffer, 0, len);
System.out.print(str);
}
//4.关闭资源
fis.close();
缓冲流
真正应用中,节点流由于效率比较低,很少单独使用,一般配合缓冲流使用
主要有四种:
- BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
作用就是提高流的读取、写入速度
原因:内部提供了一个缓冲区,大小为8192字节,内容存够8192后就一次性输出
有一个方法是flush(),刷新缓冲区,即缓冲区还没存满,就把内容输出。一般不用
处理字节
//1.造文件
File srcFile = new File("hello.jpg");
File destFile = new File("hey.jpg");
//2.1 造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileInputStream fos = new FileOutputStream(destFile);
//2.2 造缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//其实以上三步可以通过匿名类嵌套写成一步
//3.数据的操作
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
//4.资源关闭:要关4个,并且注意先后顺序
//要求:先关闭外层的流,再关闭内层的流
bos.close();
bis.close();
//其实关闭外层流的时候内层流会自动关闭,所以下面两个内层流关闭操作可以省略
fos.close();
fis.close();
以上可看出,处理流就是套接在已有流的基础上
处理字符
BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("hey.txt")));
//方式一:使用char[]
char[] cbuf = new char[1024];
int len;
while((len = br.read(cbuf)) != -1){
bw.writer(cbuf, 0, len);
}
//方式二:使用String
Stirng data;
while((data = br.readLine()) != null){//readLine()一次读一行,不包含换行符
bw.write(data + "\n");//也可以用bw.newLine()实现换行
}
bw.close();
br.close();
转换流
转换流主要有:(属于字符流)
- InputStreamReader:将一个字节的输入流转换为字符的输入流,解码过程
- OutputStreamWriter:将一个字符的输出流转户为字节的输出流,编码过程
转换流提供了在字节流和字符流之间的转换
InputStreamReader的使用示例:
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);//它还有一个参数2,可以指明字符集。不指明就默认UTF-8
char cbuf = new char[20];
int len;
while((len = isr.read(cbugf)) != -1){
String str = new String(cbuf, 0, len);
System.out.print(str);
}
isr.close();
综合使用InputStreamReader、OutputStreamWriter示例:
File file1 = new File("hello.txt");
File file2 = new File("hey.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis);
OutputStreamWriter osw = new OutputStreamWriter(fos);
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf, 0, len);
}
isr.close();
osw.close();
标准IO流、打印流、数据流
//输入字符串,变为大写输出,直到“e”或“exit”退出
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
while(true){
String data = br.readLine();
if("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println(upperCase);
}
br.close();
打印流其实就是常用的print、println
PrintStream ps = null;
try{
FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
//创建打印输出流,设置为自动刷新模式(写入换行符或字节\n时都会刷新输出缓冲区)
ps = new PrintStream(fos, true);
if(ps != null){
System.setOut(ps);
}
for(int i = 0; i <= 255; i++){
System.out.print((char) i);
if(i % 50 == 0){//每50个数据一行
System.out.println();//换行
}
}catch(FileNotFoundException e){
e.printStackTrace();
}finally{
if(ps != null){
ps.close();
}
}
}
数据流
读取不同类型数据的顺序要和写入文件时保存数据的顺序一致
对象流(比如,把联系人数据从一个手机迁移到另一个手机)
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello.dat"));
oos.writeObject(new String("我爱中国"));
oos.flush();//刷新操作
oos.close();
//反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello.dat"));
Object obj = ois.readObejct();
String str = (String) obj;
ois.close();
自定义类需要满足以下要求方可实现序列化:
- 需要实现接口:Serializable
- 类中提供一个全局常量:static final long serialVersionUID。其值可以随便设一个
- 除了当前类需要实现Serializable之外,还必须保证其内部所有属性都是可序列化的(默认情况下,基本数据类型都可以序列化)
static和transient修饰的成员变量不能序列化
随机存取文件流
RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。如果文件存在,则会对原有文件内容进行覆盖(默认情况下从头覆盖)
这一章内容太多太杂,每好好做记录。以后遇到再整理吧