参考:JAVA开发从入门到精通
一、File类
package com.test.file;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
public class FileDemo {
public static void main(String[] args) throws IOException {
// 输出File类中属性的值,常量值,
String str = File.separator;
System.out.println(File.separator); //输出结果:\ -->字符串形式
System.out.println(File.separatorChar); //输出结果:\ -->字符形式
System.out.println(File.pathSeparator); //输出结果:;
System.out.println(File.pathSeparatorChar); //输出结果:;
// File类的构造器,三种构造方式
//第一种构造方式
File file = new File("E:/test.txt"); // 或者File file = new File("E:\\test.txt");
System.out.println(file); // 输出结果: E:\test.txt
//第二种构造方式
File file2 = new File("E:", "test.txt"); //或者File file2 = new File("E:\\", "test.txt");
System.out.println(file2); // 输出结果: E:\test.txt
//第三种构造方式
File file3 = new File("E:"); //或者File file3 = new File("E:\\");
File file4 = new File(file3, "test.txt");
System.out.println(file4); // 输出结果: E:\test.txt
System.out.println(file.length()); //输出字节长度,中文占3个字符,中文标点符号也是3个字符,英文占用一个字符
//比如test.txt里面的内容为:您好 file.length()为:6
//比如test.txt里面的内容为:您好! file.length()为:9
//比如test.txt里面的内容为:aaa file.length()为:3
System.out.println(file.canRead()); //文件是否可读
System.out.println(file.canWrite()); //文件是否可写
File createFile = new File("E:\\test2.txt");
if (! createFile.exists()) {// exists()判断文件是否存在
boolean createNewFile = createFile.createNewFile(); //创建新文件
System.out.println(createNewFile);
}
if(createFile.exists()) {
boolean delete = createFile.delete(); //删除文件
System.out.println(delete);
}
System.out.println(file.isFile()); //是否为文件
System.out.println(file.isAbsolute()); //是否为绝对路径
System.out.println(file.isDirectory()); //是否为目录
System.out.println(file.isHidden()); //是否隐藏
System.out.println(new Date(file.lastModified())); //最后一次修改的时间秒数 输出结果为:Wed May 19 12:58:40 CST 2021
File file5 = new File("E:\\360Downloads");
if (file5.isDirectory()) {
File[] listFiles = file5.listFiles(); //获取列表的文件对象
System.out.println(listFiles.length);
/**
* 输出结果:
* E:\360Downloads\Software
* E:\360Downloads\wpcache
*/
for (File f : listFiles) {
System.out.println(f);
}
}
if (file5.isDirectory()) {
String[] strList = file5.list(); //获取列表的名称
/*
*第一种输出,一个个输出
* 输出结果:
* Software
wpcache
*/
for(String s : strList) {
System.out.println(s);
}
/*第二种输出,直接全部输出
* 输出结果:
* [Software, wpcache]
*/
System.out.println(Arrays.toString(strList));
}
if (file5.isDirectory()) {
File[] rootFile = file5.listRoots(); //获取磁盘的根目录对象
/**
* 输出结果:
* C:\
* D:\
* E:\
*/
for (File root : rootFile) {
System.out.println(root);
}
}
File f6 = new File("E:\\aa");
if (!f6.exists()) {
System.out.println(f6.mkdir()); // 创建单层文件夹
}
File f7 = new File("E:\\aa\\bb");
if (!f7.exists()) {
System.out.println(f7.mkdirs()); // 创建多层文件夹
}
String name = f7.getName(); //获取文件名称
System.out.println(name); //输出结果为:bb
}
}
二、 I/O流
三、文件字节输入输出流
InputStream、OutputStream这两个类是抽象类。
package com.test.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class FileInputStreamDemo {
public static void main(String[] args) {
try {
// 创建FileInputStream对象
FileInputStream in = new FileInputStream("E:\\test.txt");
// 通过文件对象进行创建
File file = new File("E:\\test.txt");
FileInputStream in2 = new FileInputStream(file);
//读取文件 test.txt的内容为:hello world!
int i = in.read();
System.out.println(i); //输出结果:104
System.out.println((char)i); //输出结果:h
byte[] b = new byte[1024];
int read = in.read(b);
System.out.println(read + " : " + new String(b)); //输出结果:11 : ello world!,因为流是顺序读取,上面执行in.read()操作读了一个字节"h"
in.close(); //关闭流操作,不然会造成内存泄露
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.test.file;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class FileOutputStreamDemo {
public static void main(String[] args) {
try {
// 创建文件输出流对象
//FileOutputStream out = new FileOutputStream("E:\\test.txt");
FileOutputStream out = new FileOutputStream("E:\\test.txt", true); //后面的参数true表示是否在文件尾部追加内容
//往文件中写入内容
out.write(97); //往test.txt文件中写入一个字节a
out.write("hello world!".getBytes()); //往test.txt文件中写入"hello world!"
out.close(); //关闭输出流
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、对象字节输入输出流
谈谈实现Serializable接口的作用和必要性
对象的序列化:
把对象转换成二进制的形式,成为对象的序列化
对象序列化的实现方式: 在定义实体类的时候实现序列化接口即可。
反序列化:
把二进制转换成对象的形式
字节流:针对二进制的处理
ObjectInputStream:对象字节流入流
读取对象:把文件中的数据以二进制的形式进行读取,然后转换成Object对象进行输入到程序。
ObjectOutputStream:对象字节输出流
把程序中的实体类对象的值输入到文件中。
创建一个类必须要实现Serializable序列化接口
QQ.java
package com.test.file;
import java.io.Serializable;
public class QQ implements Serializable {
private int QQ;
private String nickName;
// transient瞬时态,添加该关键字的变量是不会被序列化出去的
//private transient String nickName;
private String sex;
private String note;
public int getQQ() {
return QQ;
}
public void setQQ(int QQ) {
this.QQ = QQ;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "QQ{" +
"QQ=" + QQ +
", nickName='" + nickName + '\'' +
", sex='" + sex + '\'' +
", note='" + note + '\'' +
'}';
}
}
ObjectInOutputStremDemo.java
package com.test.file;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class ObjectInOutputStremDemo {
public static void main(String[] args) {
try {
//序列化
OutputStream out = new FileOutputStream("E:\\test.txt");
//创建对象字节输出流对象
ObjectOutputStream oos = new ObjectOutputStream(out);
QQ qq = new QQ();
qq.setQQ(111111);
qq.setNickName("test");
qq.setSex("男");
qq.setNote("备注");
oos.writeObject(qq);
oos.writeBoolean(true);
oos.writeLong(1000);
oos.writeByte('a');
oos.writeBytes("hello world!");
oos.flush();
oos.close();
out.close();
//反序列化
//创建对象字节输入流对象
InputStream in = new FileInputStream("E:\\test.txt");
ObjectInputStream ois = new ObjectInputStream(in);
Object obj = ois.readObject();
/**
* 特别注意,write写入的类型顺序与read读取的类型顺序需要一致,否则读取的数据会出错
*/
System.out.println(obj); //输出结果:QQ{QQ=111111, nickName='test', sex='男', note='备注'}
/**
* 如果nickName字段属性被设置为transient,则该字段是不会被序列化的
* private transient String nickName;
*/
//System.out.println(obj); //输出结果:QQ{QQ=111111, nickName='null', sex='男', note='备注'}
System.out.println(ois.readBoolean()); //输出结果:true
System.out.println(ois.readLong()); //输出结果:1000
//System.out.println(ois.readByte()); //输出结果:97
System.out.println((char)ois.readByte());//输出结果:a
byte[] b = new byte[1024];
int len = 0;
while ((len = ois.read(b)) != -1) {
System.out.println(new String(b, 0, len)); //输出结果:hello world!
}
in.close();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
五、 文件字符输入输出流
Reader、Writer这两个类为抽象类
package com.test.file;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class FileReaderDemo {
public static void main(String[] args) {
try {
// 创建字符输入流对象
FileReader fr = new FileReader("E:\\test.txt");
// test.txt文件中的内容为:aaabbbccc
int read = fr.read();
System.out.println((char)read); //输出结果:a
int read2 = fr.read();
System.out.println((char)read2); //输出结果:a
char[] chars = new char[1024];
int len = fr.read(chars);
while (len != -1) {
System.out.println(new String(chars)); //输出结果:abbbccc
len = fr.read(chars);
}
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.test.file;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) {
try {
// 创建文件写入对象
// FileWriter fw = new FileWriter("E:\\test.txt");
FileWriter fw = new FileWriter("E:\\test.txt", true);
fw.write("hello world!");
fw.flush(); //刷新缓存流
fw.close(); //关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
六、文件复制
1、通过文件字节流进行复制
2、通过字符流进行复制
package com.test.file;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/*
* 文件复制:
* 1. 通过文件字节流进行复制
* 2. 通过字符流进行复制
* 要求:把test.txt文件中的内容复制到test2.txt中
*/
public class FileCopy {
public static void main(String[] args) throws IOException {
/*
* 1.创建test2.txt文件
* 2.读取test.txt文件中的内容
* 3.把读取的内容写入到test2.txt文件中
*/
File file = new File("E:\\test2.txt");
if (!file.exists()) {
file.createNewFile();
}
FileReader fr = new FileReader("E:\\test.txt");
FileWriter fw = new FileWriter(file);
char[] chars = new char[1024];
int len = fr.read(chars);
while (len != -1) {
fw.write(chars, 0, chars.length);
len = fr.read(chars);
}
fw.flush();
fw.close();
fr.close();
}
}
七、RandomAccessFile
RandomAccessFile 很重要的功能用于多线程中分段下载
构造方法
RandomAccessFile raf = new RandomAccessFile(File file, String mode);
其中参数mode的值可选“r”:可读,“w”:可写,“rw”:可读写
成员方法:
seek(int index):可以将指针移动到某个位置开始读写
setLength(long len):给写入文件预留空间
RandomAccessFile特点和优势
-
既可以读也可以写
RandomAccessFile不属于InputStream和OutputStream类系的,它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是自己从头开始规定的,这里面包含读写两种操作 -
可以指定位置读写
RandomAccessFile能在文件里面前后移动,在文件里移动用seek(),所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继续Object的独立的类。只有RandomAccessFile才有seek搜索方法,而这个方法也只适用于文件。
8、NIO——FileChannel
Channel是对I/O操作的封装
FileChannel配合着ByteBuffer,将读写的数据缓存到内存中,然后以批量/缓存的方式read/write,省去了非批量操作时的重复中间操作,操作大文件时可以显著提高效率(和Steam以byte数组方式有什么区别?经过测试,效率上几乎无区别)
问题1:字节流和字符流的区别?
答:FileOutputStream: 字节流输出,它是一个字节一个字节向外边送数据
OutputStreamWriter:字符流,它是一个字符一个字符的向外边送数据
因为计算机是外国人发明,它们的英文字符占一个字节,而我们的中文是一个字符,至少占两个字节,如果用stream,你读出来的英文是正常的,但是如果读出来的中文就会出现乱码或者一个个“???”,如果用Writer,就不会有乱码
问题2:BufferedWriter buffer是一个缓冲区,为什么要用Buffer呢?
答:如果你直接使用stream或者writer,你的硬盘可能就是读一个字符或者一个字节,就去读写硬盘一次,IO负担巨大。可能你用了buffer,你的硬盘就是读了一堆数据之后,读写一下硬盘。这样对硬盘有好处。