File类
文件可能存在也可能存在
File实例既可以是文件,又可以是文件夹
路径可以是绝对路径:包含盘符 相对路径:不包含盘符
构造方法:
1.构造方法 pathname
2.构造方法 两个参数,父目录 文件名
文件操作
//创建
File file=new File("d:\\bb.txt");
File file1=new File("d:\\","aaa.txt");
if(!file1.exists()){
boolean newFile = file1.createNewFile();
System.out.println("创建成功");
}
else {
System.out.println("文件已存在");
}
//文件删除
//直接删除
file1.delete();
//jvm删除
file1.deleteOnExit();
//获取信息
System.out.println("文件长度"+ file1.length());
System.out.println("文件名称"+ file1.getName());
System.out.println("文件绝对路径"+ file1.getAbsolutePath());
System.out.println("规范路径"+file1.getCanonicalPath());
System.out.println("文件路径"+file1.getPath());
System.out.println("文件父目录"+file1.getParent());
System.out.println("文件最后一次修改时间"+new Date(file1.lastModified()).toLocaleString());
//判断
System.out.println("是否存在"+file1.exists());
System.out.println("是否只读"+file1.canWrite());
System.out.println("是否隐藏"+file1.isHidden());
System.out.println("是不是文件"+file1.isFile());
System.out.println("是不是绝对路径"+file1.isAbsolute());
//修改名称
file1.renameTo(new File("d:\\chichi.txt"));
文件夹操作
//1.创建
File dir=new File("d:\\aa\\bb\\cc");
if(!dir.exists()){
dir.mkdirs();//创建多级目录
System.out.println("文件删除成功");
}else{
System.out.println("目录已存在");
}
//2.删除
//直接删除 只能删除最里层的空目录
dir.delete();
//JVM 删除
dir.deleteOnExit();
//3.信息获取
System.out.println("获取路径"+dir.getPath());
System.out.println("获取绝对路径"+dir.getAbsolutePath());
System.out.println("获取名称"+dir.getName());
System.out.println("规范名称"+dir.getCanonicalPath());
//4.判断
System.out.println("是否是文件夹"+dir.isDirectory());
System.out.println("是否隐藏"+dir.isHidden());
System.out.println("是否存在"+dir.exists());
//5.重命名 具有剪切功能
dir.renameTo(new File("d:\\aa\\bb\\hello"));
//获取目录的子目录和文件
File dir2=new File("d:\\aa");
String[] list = dir2.list();//返回String数组
for (String s : list) {
System.out.println(s.toString());
}
File[] files = dir2.listFiles();
for (File file : files) {
System.out.println(file.toString());
}
//获取根目录
File[] files1 = File.listRoots();
for (File file : files1) {
System.out.println(file.toString());
}
FileFilter接口
//对获取文件进行过滤
String[] txts = dir2.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {//文件和文件名
if (name.endsWith("txt")) {
return true;
}
return false;
}
});
for (String txt : txts) {
System.out.println(txt);
}
流
硬盘中所有数据都是二进制的
按照方向划分
输入流(读取):将存储设备中的内存读入到内存中
输出流(写入):将内存中的内容写到储存设备中
以内存为参照,进内存输入流,出内存输出流
读取,从外到内 写入 从内到外
流的分类
按单位: 字节流 字符流
按功能: 节点流 过滤流
通常用前两个
流使用后要close(方法)及时关闭
字节流
字节流的父类(抽象类):
输入流InputStream read方法
输出流OutputStream write方法
文件字节流
FileInputStream 文件字节输入流
FileOutputStream 文件字节输出流
文件不存在,会抛出异常,所以需要声明异常或者try catch
文件输入流
流下方法大部分需要抛出异常IOException
read方法
1.无参的 read 方法返回值为int类型,表示读入的一个字节的值,到流末尾时返回-1;
2. int read(byte[] bs)方法返回值表示读入的字节数,到流末尾时返回-1,参数表示读入的数据存放的位置。
3.int read(byte[] bs, int offset, int len)方法返回值表示读入的字节数,到流末尾时返回-1,参数分别表示读入的数据存放的位置,从哪个下表开始,最大
长度多少。
public static void main(String[] args) throws IOException {
FileInputStream input=new FileInputStream("chichi.txt");
//读取多个字节
byte[] buf=new byte[5];
while (input.read(buf)!=-1){
System.out.print(new String(buf));
}
input.close();
}
文件输出流
构造方法
public FileOutputStream(String name,boolean append)
true表示追加,默认为false,覆盖
当多次添加时,请使append属性为true
write方法的对象文件:有则覆盖,无则创建
FileOutputStream fileOutputStream = new FileOutputStream("chichi.txt", true);
String s="赤赤,永远滴神,永远的300K\r\n";
for (int i = 0; i < 10; i++) {
fileOutputStream.write(s.getBytes());
}
fileOutputStream.close();
字节缓冲流
缓冲区大小默认为8k。
缓冲流把数据放入缓冲区中,靠文件字节流写入到硬盘中
调用write时,会把数据写入缓冲区,使用flush方法,可以刷新缓冲,或者使用close方法时,会自动关闭字节流并刷新缓冲
关闭缓冲流,自动关闭文件字节流
字节缓冲输入流
FileInputStream fileInputStream=new FileInputStream("chichi.txt");
BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream);
//读取
//读取单个字节
int data=0;
while ((data=bufferedInputStream.read())!=-1){
System.out.print((char) data);
}
//读取多个字节
byte[] bytes = new byte[20];
int len=0;
while ((len=bufferedInputStream.read(bytes))!=-1){
System.out.print(new String(bytes));
}
字节缓冲输出流
FileOutputStream outputStream=new FileOutputStream("chichi.txt");
BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(outputStream);
String s="chichi ssssssssssss";
for (int i = 0; i < 10; i++) {
bufferedOutputStream.write(s.getBytes());
}
bufferedOutputStream.flush();
bufferedOutputStream.close();
try-with-resources 语句,自动释放资源,多个资源间用;隔开,释放时倒序释放,资源类要实现java.lang.AutoCloseable或java.io.Closeable接口,并重写close方法,否则会报错
public class Tryresourse {
public static void main(String[] args) throws IOException {
try (Person p=new Person();Chichi chi=new Chichi()){
}
}
}
class Person implements Closeable {
@Override
public void close() throws IOException {
System.out.println("1关闭了");
}
}
class Chichi implements Closeable{
@Override
public void close() throws IOException {
System.out.println("2关闭了");
}
}
输出:
对象流
ObjectOutputStream ObjectInputStream
需要靠文件字节输出流对硬盘读写
序列化:把对象写入到硬盘或网络的过程
反序列化:把硬盘或网络的二进制文件兑取到内存中形成对象的过程
student类实现标记接口Serializable list是student的集合
//创建对象流
ObjectOutputStream o=new ObjectOutputStream(new FileOutputStream("chichi.bin"));
//序列化
o.writeObject(list);
System.out.println("序列化成功");
o.close();
//反序列化
ObjectInputStream i=new ObjectInputStream(new FileInputStream("chichi.bin"));
ArrayList<Student> list1=(ArrayList) i.readObject();//读出的是Object类型,需要强制类型转换
要求
1.序列化的类必须实现Serializable(自动序列化接口,标记接口,内部无方法),Externalizable(手动序列化接口,内部两个方法需要重写)
2.序列化的类要添加一个私有的long类型常量:serialVersionUID,保证序列化的类和反序列的类是同一个类 ,不同报错
private static final longserialVersionUID 会自动生成,也可手动添加
注意实现
不会调用构造方法
1.使用transient修饰的属性,不会被序列化(反序列化时属性名还在,但值不在)
2.静态属性不能序列化(反序列化时值还在,因为静态属性是类的属性)
读到文件尾部的标志:java.io.EOFException
面试题:使用transient的属性一定不能序列化吗?
能,实现Externalizable接口并重写方法
class Student implements Externalizable{
transient String name;
static int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// ObjectOutput时对象流的父接口
out.writeObject(name);//写入
out.writeObject(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name =(String) in.readObject();//强制转换读出
age=(int)in.readObject();
}
----------------------------------------------------------------------------
字符编码
UTF-8可能是1或2,或3个字节
一个中文UTF-8 是三个字节 在JAVA内部内存中是两个字节
字符流
Reader Writer(抽象类)
使用char数组读取
文件字符流
FileReader FileWriter
字符缓冲流
不能直接对硬盘读写功能,要借助文件字符流()
BufferedReader BufferedWriter
支持输入换行符,可一次写一行,读一行
写:特有newLine()方法,可以实现跨平台换行,写完后必须加上这句话,并flush刷新
读:readline() 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
public static void main(String[] args) throws IOException {
//缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("chichi.txt"));
for (int i = 0; i < 5; i++) {
bw.write("chichi yyds");
bw.newLine();//特有方法,实现换行
bw.flush();
}
bw.close();
//缓冲输出流
BufferedReader br = new BufferedReader(new FileReader("chichi.txt"));
String data=null;
while ((data=br.readLine())!=null){
System.out.println(data);//返回字符串,末尾反null
}
br.close();
}
转换流
文件字符流父类
第一个参数构造函数均为字节流
InputStreamReader:字节流通向字符流的桥梁 (硬盘->内存)
//1创建输入转换流
FileInputStream fis=new FileInputStream("d:\\trans.txt");
InputStreamReader isr=new InputStreamReader(fis,"utf-8");
OutputStreamWriter:字符流通向字节流的桥梁 (内存->硬盘)
//创建输出转换流
FileOutputStream fos=new FileOutputStream("d:\\trans.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"GBK");
通过charsetName可设置字符的编码方式
打印流
永远不会抛出 IOException,有缓冲区
PrinterStream 字节打印流
PrinterWriter 字符打印流
print方法与write方法的区别
print方法原样打印,看到的是什么,打印出来的就是什么
PrintStream ps=new PrintStream("chichi.txt");
ps.println(97);//写入97 原样打印
PrintWriter pr=new PrintWriter("chichi.txt");
pr.write(97);//写入a,
pr.close();
重定向标准输出流
setOut参数 为 字节打印流
out是一个字节打印流
in是一个字节输入流
//简单实现Scanner
InputStreamReader iSR = new InputStreamReader(System.in);//转字符流
BufferedReader br = new BufferedReader(iSR);
String data=br.readLine();
br.close();
System.out.println(data);
RandomAccessFile随机流
又能写又能读各种常见类型
//写入
RandomAccessFile file=new RandomAccessFile("chichi.txt","rw");
file.writeUTF("chichi");
file.writeInt(19);
file.writeDouble(130.0);
file.close();
//读取 还是要创建两个对象的
RandomAccessFile file1=new RandomAccessFile("chichi.txt","rw");
file1.seek(8);//从开头位置设置文件指针的偏移量
// System.out.println(file1.readUTF());
// file1.skipBytes(8);//跳过字节个数,从当前位置跳
System.out.println(file1.readInt());
System.out.println(file1.readDouble());
file1.close();
一个字符一字节,
00 06(UTF的固定开头) 63 c 68 h 69 i
int型4字节
00 00 00 13 19
double 8字节 40 60 40 00 00 00 00 00
Properties集合
1.list()遍历,输出到流中,用于打印信息
2.store()保存 到把文件 要求不用中文用字节输出流,可以中文用字符输出流
3.load() 加载文件
Properties properties1 = new Properties();
Properties properties = properties1;
properties.setProperty("name","zhang");
properties.setProperty("password","123");
//list遍历,输出到流
properties.list(System.out);
PrintStream writer = new PrintStream("chichi.txt");
properties.list(writer);
writer.close();
//store 保存文件 汉字会存储为编码
FileWriter file = new FileWriter("chichi.txt");
properties.store(file,"用户信息");
//load 加载文件
Properties properties2 = new Properties();
FileReader fileReader = new FileReader("chichi.txt");
properties2.load(fileReader);
fileReader.close();
properties2.list(System.out);
总结
本质上说没有字符流,字符流内部用的都是字节流,不过采用了特定编码转换
除了文件字节流其他流都有缓存,所以这些有缓冲的流如果不用flush或close方法刷新缓冲,将会无法写入(可通过flush方法测试,有此方法的都有缓冲)
read返回读取的字符数,如果已到达流的末尾,则返回 -1
BufferedReader的readLine,到达末尾的返回值是null,遇到换行符才会返回,没有换行符会卡死,不在继续向进行