文件与IO流
储存和读取数据的解决方案
File类:路径
File对象就表示一个路径,可以是文件的路径、也可以是文件夹的路径
这个路径可以是存在的,也允许是不存在的
构造方法
public File(String pathname) 根据文件路径创建文件对象
//1.根据字符串表示的路径,变成File对象
String str = "C: \\Users\lalienware\ \Desktoplla. txt" ;
File f1 = new File(str);
public File(String parent, String child) 根据父路径名字符串和子路径名字符串创建文件对象
//2.父级路径: C: \Users\alienware \Desktop
//子级路径: a.txt
String parent = "C: \\Users\\alienware\\Desktop";
String child = "a.txt";
File f2 = new File(parent, child);
//或
File f3 = new File(parent + "\\" + child); //直接拼接,较少用
public File(File parent, String child) 根据父路径对应文件对象和子路径名字符串创建文件对象
//3.把一个File表示的路径和String表示路径进行拼接
File parent2 = new File("C: \\Usersllalienware\lDesktop");
String child2 = "a.txt";
File f4 = new File(parent2, child2);
绝对路径与相对路径
绝对路径是带盘符的。
相对路径是不带盘符的,默认到当前项目下去找。
File的常见成员方法
判断和获取
public boolean isDirectory() 判断此路径名表示的File是否为文件夹
public boolean isFile() 判断此路径名表示的File是否为文件
public boolean exists() 判断此路径名表示的File是否存在public long 1ength() 返回文件的大小(字节数量)(只能是文件,不能是文件夹)
public String getAbsolutePath() 返回文件的绝对路径(最完整)
public String getPath() 返回定义文件时使用的路径(构造时括号里是什么就返回什么)
public String getName() 返回文件的名称,带后缀,返回文件夹名称,无后缀
public long lastModified( ) 返回文件的最后修改时间(时间毫秒值)
创建和删除
public boolean createNewFile() 创建一个新的空的文件,若存在则创建失败;若父级路径是不存在的,那么方法会有异常; createNewFile方法创建的一 定是文件,如果路径中不包含后缀名,则创建一个没有后缀的文件
public boolean mkdir() 创建单级文件夹,//细节1: windows 当中路径是唯一的,如果当前路径已经存在,则创建失败,返回false; mkdir方法只能创建单级文件夹,无法创建多级文件夹。
public boolean mkdirs() 创建多级文件夹(可以单级,主用) aaa\\bbb\\ccc
public boolean delete() 删除文件、空文件夹,不走回收站
获取并遍历
public File[] listFiles() 获取当前该路径下所有内容,把所有内容放到数组中
-
当调用者File表示的路径不存在时, 返回null
-
当调用者File表示的路径 是文件时,返回null
-
当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
-
当调用者File表示的路径是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
-
当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
-
当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
//1.创建File对象
File f = new File( pathname: "D:\laaa");
//2.需求:打印里面所有的txt文件
File[] arr = f.listFiles();
for (File file : arr) {
//file依次表示aaa文件夹里面每一个 文件或者文件夹的路径
if(file.isFile() && file.getName().endsWith(".txt")){
System.out.print1n(file);
}
}
IO流
用于读写文件中的数据(可以读写文件,或网络中的数据
IO流的分类
IO流按照流向可以分类
输出流:程序—>文件
输入流:文件—>程序
IO流按照操作文件的类型可以分类
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件 ( md文件、txt文件、xml、lrc)
体系结构
字节流
- InputStream 字节输入流
- OutputStream 字节输出流
FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。
public static void main(String[] args) throws IOException {
/*
演示:字节输出流FileOutputStream
实现需求:写出一 段文字到本地文件中。 (暂时不写中文)
*/
//1.创建对象
//写出输出流 OutputStream
//本地文件 File,
//字符串对象和file对象都可以
//如果文件不存在会创建一一个 新的文件,但是要保证父级路径是存在的。
//如果文件已经存在,则会清空文件
File0utputStream fos = new FileOutputStream("myio\\a.txt"); //指定文件路径
//2.写出数据
//参数是整数,实际是ASCII对应字符
fos.write(97);
//3.释放资源 停止占用
fos.close();
}
写入数据的三种方式
void write(int b) 一次写一个字节数据
void write(byte[ ] b) 一次写一个字节数组数据
void write(byte[ ] b,int off(起始索引), int len(写入个数)) 一次写一个字节数组的部分数据
写入数据的两个问题
- 换行写
//1.创建对象
File0utputStream fos = new File0utputStream( name: "myiolla.txt");
//2.写出数据
String str = "kankelaoyezuishuai";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);
//再次写出一个换行符就可以了
String wrap = "\r\n";
byte[] bytes2 = Wrap.getBytes();
fos.write(bytes2);
String str2 = "666";
byte[] bytes3 = str2.getBytes();
fos.write(bytes3);
//3.释放资源
fos.close();
续写
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件
FileInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。
//1.创建对象 如果文件不存在直接报错
FileInputStream fis = new FileInputStream("myiolla.txt")
//2.读取数据
int b1 = fis.read(); //每次调用向下依次读取
System.out.print1n((char)b1); //char强转ASCII
int b6 = fis.read();
System.out.print1n(b6); //读取到最后输出-1
//3.释放资源
fis.close();
循环读取
//1.创建对象
FileInputStream fis = new FileInputStream("myio\la.txt");
//2.循环读取
int b;
while ((b = fis.read())!=-1) {
System.out.print1n((char) b);
}
//3.释放资源
fis.close();
文件拷贝
//1.创建对象
FileInputStream fis = new FileInputStream("D:\\itheima\\movie.mp4");
File0utputStream fos = new File0utputStream("myio\\copy.mp4");
//2.拷贝
//核心思想:边读边写
int b;
while((b = fis.read())!= -1){
fos.write(b);
}
//3.释放资源
//规则:先开的最后关闭
fos.close();
fis.close();
一次读取多个字节
public int read(byte[ ] buffer) 一次读一个字节数组数据 ,将读取到的字节码存到数组中,返回读取到的个数
一般设置[1024 * 1024 *5]长度的数组
注意: 一次读一个字节数组的数据,每次读取会尽可能把数组装满,并覆盖上次数据,若无法装满,则上一次数据不会被完全覆盖
int read(byte[ ] b,int off(起始索引), int len(读取个数))
字节流字符流
字符流
- Reader 字符输入流
- Writer 字符输出流
特点
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中.
使用场景
对于纯文本文件进行读写操作
FileReader
创建对象、读取数据和释放资源的 方法使用 与InputStream相同
读取数据空参read()细节
字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
如果遇到中文就会次读取多个,GBK一次读两个字节, UTF-8 一次读三个字节
在读取之后,方法的底层还会进行解码并转成十进制。
最终把这个十进制作为返回值
这个十进制的数据也表示在字符集上的数字
带参read(char [ ] buffer)
读取数据并解码强转为字符放入数组中
FileWriter
构造方法
public FileWriter(File file) 创建字符输出流关联本地文件
public FileWriter(String pathname) 创建字符输出流关联本地文件
public FileWriter(File file, boolean append) 创建字符输出流关联本地文件,续写
public FileWriter(String pathname, boolean append ) 创建字符输出流关联本地文件,续写
成员方法
void write(int c) 写出一个字符
void write(String str) 写出一个字符串
void write(String str, int off, int len) 写出一个字符串的一部分
void write(char[] cbuf) 写出一个字符数组
void write(char[] cbuf, int off, int len) 写出字符数组的一部分void flush() 将缓冲区数据,刷新到本地文件中,可以继续写入
void flush() 将缓冲区数据,刷新到本地文件中,不能继续写入
字节流和字符流应用
字节流 拷贝任意类型的文件
字符流 读取纯文本文件中的数据 往纯文本文件中写出数据
缓冲流(包装基本流)
原理:底层自带了长度为8192的缓冲区提高性能
BufferedInputStream 字节缓冲输入流
BufferedOutputStream 字节缓冲输出流
//1.创建缓冲流的对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myiol\a.txt")); //需关联对应的基本流对象,此处直接new了一个基本对象
Buffered0utputStream bos = new BufferedOutputStream(new FileOutputStream("myio\lcopy.txt")); //同上
字节缓冲流可成员方法的使用与字节流一致
BufferedReader 字符缓冲输入流
BufferedWrite 字符缓冲输出流
特有方法
public String readline( ) 读取一行数据,如果没有数据可读了,会返回null,不会读取回车换行
public void newLine( ) 跨平台的换行,适用各种操作系统
转换流
字符流和字节流之间的桥梁
InputStreamReader 把字节流转换为字符流
可以根据字符集一次读取多个字节
读取数据不会乱码了
OutputStreamWriter 把字符流转换为字符流往外写出
指定字符编码读取数据
FileReader fr = new FileReader("myio\\gbkfile.txt",Charset.forName("GBK")); //Charset.forName()方法可获取编码方式
利用转换流按照指定字符编码写出
FileWriter fw = new FileWriter("myio\\c .txt" , Charset.forName("GBK"));
案例:将本地文件中的GBK文件,转成UTF-8
FileReader fr = new FileReader("myio\b.txt",Charset.forName("GBK"));
FileWriter fw = new FileWriter("myio\\e.txt" ,Charset.forName("UTF-8"));
int b;
while ((b = fr.read()) != -1){
fw.write(b);
}
fw.close();
fr.close();
序列化流
属于字节流的一种,可以把Java中的对象写到本地文件中
public ObjectOutputStream(OutputStream out) 把基本流包装成高级流
public final void writeObject(Object obj) 把对象序列化(写出)到文件中去
//1.创建对象
Student stu = new Student("zhangsan",23);
//2.创建序列化流的对象/对象操作输出流
ObjectoutputStream oos = new ObjectoutputStream(new File0utputStream("myiolla.txt"));
//3.写出数据
oos.write0bject(stu);
//4.释放资源
oos.close();
细节
被写入的对象所在类需实现 Serializable 接口( implements Serializable)
Serializable接口里面是没有抽象方法,是标记型接口,一旦实现了这个接口,那么就表示当前的Student类可以被序列化
所以此处
public class Student implements Serializable{...}
反序列化流/对象操作输入流
可以把序列化到本地文件中的对象,读取到程序中来
构造方法
public ObjectInputStream( InputStream out) 把基本流变成高级流
成员方法
public Object readObject() 把序列化到本地文件中的对象,读取到程序中来
//1.创建反序列化流的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myiol\a.txt"));
//2.读取数据
Object o = ois.read0bject(); //可使用强转接受 Student o = (Student)ois.read0bject();
//3.打印对象
System.out.print1n(o);
//4.释放资源
ois.close();
序列化流细节
1.当被序列化类被修改后,原先生成的本地文件无法再转化回该类对象
解决方法,使该类被修改时版本号不改变
- private static final long serialVersionUID=1L; (不推荐)
- ctrl c -->file settings设置,在ideal 对标记类快捷添加版本号
2.某个成员变量的值不想序列化到本地
在成员变量前加关键字 transient
transient:瞬态关键字
作用: 不会把当前属性的值序列化到本地文件当中
补充:Java中的编码方法
String类中的方法 将String变成字节码数组
public byte[] getBytes() 使用默认方式进行编码
public byte[] getBytes(String charsetName) 使用指定方式进行编码
Java中解码的方法
String类中的构造方法 将字节码数组变成String
String(byte[] bytes) 使用默认方式进行解码
String(byte[] bytes, String charsetName) 使用指定方式进行解码
直接 根据字节数组 new一个新String对象