17 File
含义:
-
file是文件和目录路径的抽象表示 -
File只关注文件本身的信息,而不能操作文件里面的内容 -
File类 – 表示文件或文件夹,不能对文件里的数据进行操作 对文件里的数据进行操作的是:IO流
17.1 File对象
绝对路径:
File file = new File("D:\\A\\1.txt");
相对路径:
File file = new File("file01\\test.txt");
浅显来看,绝对路径是有C:这样的硬盘路径,而相对路径则没有。
绝对路径是基于整个操作系统来说的,而相对路径则是要相对于某个绝对路径来说(项目的路径)。
注:
17.2 获取文件信息
简单示例:
File file = new File("D:\\A\\1.txt");
System.out.println("获取文件绝对路径:"+file.getAbsolutePath());
System.out.println("获取文件名:"+file.getName());
System.out.println("文件是否可读:"+file.canRead());
System.out.println("文件是否可写:"+file.canWrite());
System.out.println("文件是否隐藏:"+file.isHidden());
System.out.println("获取文件长度:"+file.length());
System.out.println("判断是否是文件:"+file.isFile());
System.out.println("判断是否是文件夹:"+file.isDirectory());
System.out.println("判断文件是否存在:"+file.exists());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("文件最后修改的时间:"+sdf.format(file.lastModified()));
如果相对路径下的文件不存在,可以使用createNewFile();方法创建文件。
File file = new File("file01\\test.txt");
System.out.println("获取文件绝对路径:"+file.getAbsolutePath());
if(!file.exists()){
file.createNewFile();
}
17.3 创建文件夹和文件
创建文件夹:mkdirs();
创建文件:createNewFile();
示例:(通过路径判断是否存在文件,如果不存在就创建。)
File file = new File("file01\\file02\\test1.txt");
File parentFile = file.getParentFile();
if(!parentFile.exists()){
parentFile.mkdirs();
}
if(!file.exists()){
file.createNewFile();
}
17.4 检索文件目录
17.4.1 遍历文件夹(不考虑子文件夹)
获取当前文件夹下的所有文件(包括文件夹):listFiles();
File file = new File("D:\\Test");
File[] files = file.listFiles();
for (File f : files) {
System.out.println(f.getName()+" -- "+f.canRead());
}
拓展:使用过滤器检索遍历(查询当前文件夹下的txt文件)
File file = new File("D:\\Test");
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File f = new File(dir,name);
if(f.isFile()&&f.getName().endsWith(".txt"))
return true;
else
return false;
}
});
for (File f : files) {
System.out.println(f.getName()+" -- "+f.canRead());
}
17.4.2 检索文件(考虑子文件夹)
使用检索文件时,常常需要遍历整个文件夹下的文件(包括子文件目录),此时需要使用递归的方法。
public class Test {
public static void main(String[] args) {
File file = new File("file01");
method(file, ".txt");
}
public static void method(File file,String str){
File[] files = file.listFiles();
for (File f : files) {
if(f.isDirectory()){
method(f,str);
}
else if(f.getName().endsWith(".txt")){
System.out.println(f.getName());
}
}
}
}
17.4 删除文件夹
注:在删除文件夹时,不能直接删除,因为当文件夹中含有其他文件时,无法直接删除,必须要先将文件夹内部的文件逐步删除,使用的递归思想和检索文件类似。
public class Test {
public static void main(String[] args) {
File file = new File("D:\\Test");
method(file);
}
public static void method(File file){
File[] listFiles = file.listFiles();
for (File f : listFiles) {
if(f.isDirectory()){
method(f);
f.delete();
}else if(f.isFile()){
f.delete();
}
}
}
}
18 IO流
18.1 IO流的含义
注:站在程序的角度
I:In ,输入流,read读取(读取文件中的数据)
O:Out,输出流,writer写入(向文件里写入数据)
流:一点点的读取或者写入
单位:
1024KB = 1MB
1024MB= 1GB
1024GB = 1TB
1024TB = 1PB
进制:1024
18.2 分流
按照方向分:输入流、输出流
按照单位分:字节流、字符流
按照功能分:节点流/基础流、处理流
18.3 字节流
InputStream 字节输入流的基类(抽象类)
OutputStream 字节输出流的基类(抽象类)
FileInputStream extends InputStream 文件字节输入流
FileOutputStream extends OutputStream 文件字节输出流
示例:
- 使用文件字节输入流(FileInputStream )向文件中添加数据。
FileOutputStream fos = new FileOutputStream("io.txt",true);
fos.write(97);
fos.write("123abc".getBytes());
fos.write("123abc".getBytes(),2,3);
fos.close();
- 使用文件字节输出流(FileOutputStream )从文件中读取数据。
FileInputStream fis = new FileInputStream("io.txt");
byte[] bs = new byte[1024];
int len;
while((len = fis.read(bs)) != -1){
System.out.println(new String(bs, 0, len));
}
fis.close();
3.使用字节流复制字节文件。
FileInputStream fis = new FileInputStream("test1.txt");
FileOutputStream fos = new FileOutputStream("copy.txt");
byte [] bs=new byte [1024];
int len;
while((len=fis.read(bs))!=-1){
fos.write(bs, 0, len);
}
fis.close();
fos.close();
}
FilterInputStream extends InputStream 过滤器字节输入流
FilterOutputStream extends OutputStream 过滤器字节输出流
BufferedInputStream extends InputStream 带有缓冲区的字节输入流
BufferedOutputStream extends OutputStream 带有缓冲区的字节输出流
默认缓冲区大小:8192字节
示例:
- 使用带有缓冲区的字节输出流BufferedOutputStream 向文件中添加数据
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test1.txt",true));
bos.write("12345".getBytes());
bos.write("12345".getBytes(),2,3);
bos.close();
- 使用带有缓冲区的字节输入流BufferedInputStream 从文件中读取数据
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test1.txt"));
byte[] bs=new byte[1024];
int len;
while((len=bis.read(bs))!=-1){
System.out.println(new String(bs, 0, len));
}
bis.close();
}
- 复制视频(.mp4)文件
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream("test1.mp4"));
bos = new BufferedOutputStream(new FileOutputStream("copy.mp4"));
byte[] bs = new byte[4];
int len;
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
finally{
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:1.在向文件中添加数据时,若路径下没有文件,将会默认创建文件。
? 2.使用字节流时,不能出现文字等字符,若需操作含有字符的文件,可以使用字符流。
使用区别:
18.4 字符流
Reader 字符输入流的基类(抽象类)
Writer 字符输出流的基类(抽象类)
InputStreamReader extends Reader 字符输入转换流(字节流转换字符流)
OutputStreamWriter extends Writer 字符输出转换流(字节流转换字符流)
应用场景:获取到的流是字节流,但是要去做字符操作
注意:使用转换流一般都加上编码格式
示例:
- 使用 字符输出转换流(OutputStreamWriter )向文件中添加数据。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test1.txt"),"UTF-8");
osw.write(97);
osw.write("晚风依旧很温柔~~~".toCharArray(), 2, 5);
osw.write("晚风依旧很温柔~~~");
osw.write("晚风依旧很温柔~~~",7,3);
osw.close();
- 使用 字符输入转换流(InputStreamWriter )从文件中读取数据。
InputStreamReader isr = new InputStreamReader(new FileInputStream("test1.txt"));
int read;
while((read = isr.read()) != -1){
System.out.println((char)read);
}
char [] read=new char [1024];
int len;
while((len = isr.read(read)) != -1){
System.out.println(new String(read,0,len));
}
isr.close();
3.复制文本文件
InputStreamReader isr = new InputStreamReader(new FileInputStream("test1.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("copy.txt"));
char[] cs =new char[1024];
int len;
while((len=isr.read(cs))!=-1){
osw.write(cs,0,len);
}
isr.close();
osw.close();
FileReader extends InputStreamReader 文件字符输入流
FileWriter extends OutputStreamWriter 文件字符输出流
示例:
- 使用文件字符输出流(FileWriter )向文件中添加字符数据
FileWriter fw = new FileWriter("test1.txt");
fw.write("晚风依旧很温柔~~~");
fw.close();
- 使用文件字符输入流(FileReader )从文件中获取字符数据
FileReader fr = new FileReader("test1.txt");
char[] cs =new char[1024];
int len;
while((len=fr.read(cs))!=-1){
System.out.println(new String(cs,0,len));
}
fr.close();
- 复制文件
FileReader fr = new FileReader("test1.txt");
FileWriter fw = new FileWriter("copy.txt");
char[] cs =new char[1024];
int len;
while((len=fr.read(cs))!=-1){
fw.write(cs,0,len);
}
fr.close();
fw.close();
BufferedReader extends Reader 带有缓冲区的字符输入流
BufferedWriter extends Writer 带有缓冲区的字符输出流
默认缓冲区大小:8192字符
示例:
- 使用带有缓冲区的字符输出流(BufferedWriter)向文件中添加字符数据
BufferedWriter bw = new BufferedWriter(new FileWriter("test1.txt"));
bw.write("BufferedWriter 晚风依旧很温柔~~~");
bw.close();
- 使用带有缓冲区的字符输入流(BufferedReader )从文件中获取字符数据
BufferedReader br = new BufferedReader(new FileReader("test1.txt"));
char [] cs =new char[1024];
int len;
while((len=br.read(cs))!=-1){
System.out.println(new String(cs,0,len));
}
String line;
while((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
- 复制文件1(依次复制会失去原有格式)
BufferedReader br = new BufferedReader(new FileReader("test1.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
char[] cs =new char[1024];
int len;
while((len=br.read(cs))!=-1){
bw.write(cs,0,len);
}
br.close();
bw.close();
- 复制文件2(单行的复制)
BufferedReader br = new BufferedReader(new FileReader("test1.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
char[] cs =new char[1024];
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
注:1.使用字符的输入输出转换流时,一般手动加上编码格式,以免读出的字符乱码。
? 2.在复制文本文件时,如果直接依照字符数组复制,会导致复制后的文件失去原有的格式,所有的字符都在文件第一行中,而显示异常。所有需要单行读取和单行添加,并且要在每次添加之后手动再添加一个换行。(复制的文件会比原来的文件多上一行)
使用区别:
拓展:
以上流的复制文件都是针对单个文件,而对整个文件夹的复制可见java例题 复制整个文件夹到指定文件夹下
18.5 各种流
18.5.1 对象流
ObjectInputStream 对象输入流
ObjectOutputStream 对象输出流
序列化概念:
序列化:将程序中的对象写入到文件中 — 钝化
反序列化:将文件中的对象读取到程序中 — 活化
注:
-
一个类的对象要想通过对象流写入到文件中,该类就必须实现序列化接口(Serializable) -
Serializable叫做序列化接口,该接口没有让我们去实现任何的方法,这种接口叫做标记型接口
-
transient修饰属性后,该属性不会随着对象写入到文件中 -
static静态属性也不会随着对象写入到文件中 -
对象写入文件之后,会特殊编码,只能够通过对象输出流获取,且获取的顺序要和写入一致。
示例1:
写入常见类对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
oos.writeInt(500);
oos.writeDouble(20.2);
oos.writeObject(new Date());
oos.close();
获取写入的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
int readInt = ois.readInt();
double readDouble = ois.readDouble();
Date date = (Date)ois.readObject();
System.out.println(readInt);
System.out.println(readDouble);
System.out.println(date);
示例2:
自定义对象类
import java.io.Serializable;
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private String carldId;
public Student() {
}
public Student(String name, String carldId) {
this.name = name;
this.carldId = carldId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCarldId() {
return carldId;
}
public void setCarldId(String carldId) {
this.carldId = carldId;
}
@Override
public String toString() {
return "Student [name=" + name + ", carldId=" + carldId + "]";
}
}
写入自定义对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
oos.writeObject(new Student("小红","001"));
oos.writeObject(new Student("小张","002"));
oos.writeObject(new Student("小明","003"));
oos.writeObject(null);
oos.close();
读取自定义对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
Student stu;
while((stu=(Student)ois.readObject())!=null){
System.out.println(stu);
}
ois.close();
写入自定义对象注意:
- 在自定义类中必须需要实现序列化接口(implements Serializable)。
- 手动设置序列化版本号(非必须,但若是不手动设置,在写入对象之后,一旦自定义类发生结构发生变化(如增加成员方法…等)都会导致默认的序列化版本号发生变化,从而无法被读出。)
- 小技巧:在写入对象时,可以在末尾写入一个null对象,这样在循环依次获取这个文件中的对象时,可以使用null对象为结束标志。
18.5.2 打印流
18.5.2.1 PrintStream
字节打印流
示例:
PrintStream ps = new PrintStream(new FileOutputStream("test1.txt",true));
ps.println("输了你,赢了世界又如何~~~~");
ps.close();
18.5.2.2 PrintWriter
字符打印流
示例:
PrintWriter pw = new PrintWriter(new FileWriter("test1.txt",true));
pw.println("我想我永远不会懂~~~");
pw.close();
18.5.2.3 重定向
获取系统标准的输入流(方向:控制台->程序): InputStream in = System.in;
获取系统标准的输出流:(方向:程序->控制台): PrintStream out = System.out;
知识点:重定向 System.in
System.setIn(new FileInputStream("test1.txt"));
InputStream in = System.in;
Scanner scan = new Scanner(in);
String next = scan.next();
System.out.println(next);
scan.close();
知识点:重定向 System.out
System.setOut(new PrintStream(new FileOutputStream("test1.txt")));
PrintStream out = System.out;
out.println("晚风依旧很温柔~~");
18.5.3 随机访问流(RandomAccessFile)
new RandomAccessFile(file, mode);
file:文件对象
mode:操作模式(“r”,“rw”,“rws”,“rwd”)
r | 以只读方式打开 |
---|
rw | 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件 | rws | 打开以便读取和写入,对于 “rw”,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 | rwd | 打开以便读取和写入,对于 “rw”,还要求对文件内容的每个更新都同步写入到底层存储设备。 |
- 使用随机访问流向文件添加数据
RandomAccessFile w = new RandomAccessFile("test2.txt", "rw");
w.write("美丽的泡沫~~".getBytes());
w.close();
- 使用随机访问流在文件末尾添加数据
File file = new File("test2.txt");
RandomAccessFile w = new RandomAccessFile(file, "rw");
w.seek(file.length());
w.write("你所有承诺~~~".getBytes());
w.close();
- 使用随机访问流在文件内容指定处开始添加数据
File file = new File("test1.txt");
RandomAccessFile w = new RandomAccessFile(file, "rw");
w.seek(6);
w.write("aaa".getBytes());
w.close();
- 使用随机访问流从文件中读取数据
RandomAccessFile r = new RandomAccessFile("test1.txt", "r");
byte[] bs = new byte[1024];
int len;
while((len = r.read(bs)) != -1){
System.out.println(new String(bs, 0, len));
}
r.close();
- 使用随机访问流从文件指定位置开始中读取数据
RandomAccessFile r = new RandomAccessFile("test2.txt", "r");
r.seek(5);
byte[] bs = new byte[1024];
int len;
while((len = r.read(bs)) != -1){
System.out.println(new String(bs, 0, len));
}
r.close();
注:使用随机访问流在文件内容指定处开始添加数据时会从指针位置依次覆盖,直到添加完。
- 使用随机访问流复制文件,完成断点续传的功能
RandomAccessFile r = new RandomAccessFile("1.mp4", "r");
File file = new File("copy.mp4");
RandomAccessFile w = new RandomAccessFile(file, "rw");
int len=file.length();
r.seek(len);
w.seek(len);
byte[] bs = new byte[1024];
int len;
while((len = r.read(bs)) != -1){
w.write(bs, 0, len);
}
r.close();
w.close();
注:
- 随机访问流并不是随机访问,而是通过seek指针开始读写,而我们可以手动修改seek指针,让文件的读写更加“随机”。
- 通过随机访问流向文件中写入时,文件不可能变小(因为写入的方式为覆盖写入)。
18.5.4 内存流
内存流是建立在程序和内存之间的流,而程序也是运行在内存中,所以内存流一旦创建,将无法关闭。(无法关闭程序和内存的交互)
18.5.4.1 内存输出流
示例:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("java入门基础13".getBytes());
System.out.println(baos.toString());
System.out.println(new String(baos.toByteArray()));
18.5.4.2 内存输入流
示例:
ByteArrayInputStream bis = new ByteArrayInputStream("java入门基础13".getBytes());
byte[] bs = new byte[1024];
int len;
while((len = bis.read(bs)) != -1){
System.out.println(new String(bs, 0, len));
}
18.5.4.3 内存流的使用场景
? 内存流是在内存中存取数据,所以效率会远高于其他需要和硬盘交互的流,但数据不能持久化(因为是在内存中存放,持久化需要存入硬盘(文件)中),所有当我们不需要持久化存储数据,而仅仅是需要进行数据中转的时候,就可以使用内存流,来提高效率。
|