IO流机制
File类的使用
File类的构造方法
File(URI uri)
File(String pathname)
File(File parent, String child)
File(String parent, String child)
File类的常用方法
boolean exists():判断文件是否存在
boolean createNewFile() :创建一个新文件,只能创建一个文件,不能创建目录(文件夹),创建时先判断文件 是否存在 ,不存在则创建并返回true, 存在则返回false.
File getAbsoluteFile() File 类型的绝对路径File文件形式,相当于 File file =new File(绝对名称),
String getAbsolutePath() String类型的绝对路径的字符串形式
String getName() : 获取的是路径的最后一级的名称
String getPath() //获取的是相对路径的名称:打File对象事调用的就是getPath()方法
String Parent() //返回当前文件的上一级目录,若没有上一级目录返回null
bolean isDirectory() //判断是否是文件
bolean isFile() //判断是否是文件夹
bolean delete()//删除一个文件或文件夹
File[] listFiles()// 只能获取当前文件夹下的的所有文件
Long length() //获取点前文件夹的长度
public class Test01_01 { public static void main(String[] args) throws IOException { // 创建文件对象:绝对路径 File f1 = new File("d:/a.txt"); // 创建文件对象:相对路径 File f2 = new File("a.txt"); boolean b1 = f1.createNewFile(); boolean b2 = f2.createNewFile(); String path1 = f1.getAbsolutePath(); //d:\a.txt String path2 = f2.getAbsolutePath(); //C:\idea_workspace\basic-java\a.txt System.out.println(path1+" "+path2); File fpath1 = f1.getAbsoluteFile(); //d:\a.txt File fpath2 = f2.getAbsoluteFile(); //C:\idea_workspace\basic-java\a.txt System.out.println(fpath1+" "+fpath2); String name1 = f1.getName(); //a.txt String name2 = f2.getName(); //a.txt System.out.println(name1+" "+name2); /* 获取的是相对路径 */ String p1 = f1.getPath();//d:\a.txt String p2 = f2.getPath(); //d:\a.txt System.out.println(p1+" "+p2); File f3 = new File("d:/aaa/aa"); System.out.println(f3.getParent()+"f3...."); System.out.println(f2.getParent()+"f2...."); Boolean b = f3.mkdirs(); System.out.println(b); File f4 = new File(f3,"a"); //在 aaa/aa文件夹下再创建一个文件目录a String parent = f4.getParent(); System.out.println(parent); f4.mkdir(); File f5 = new File("d:/aaa/aa/a","a.txt"); System.out.println(f5.getParent()); System.out.println(f4.getName()); //a f5.createNewFile();//在d:/aaa/aa/a下创建一个a.txt文件 System.out.println(f5); //d:\aaa\aa\a\a.txt,实际是复写了toStirng()方法,在toStirng中调用了getPath() //删除文件或文件夹delete() f2.delete(); f1.delete(); } } public static void main(String[] args) { // 创建文件对象 File f = new File("d:/aaa/b.txt"); // 获得文件名 String filename = f.getName(); // 获得文件大小 long filesize = f.length(); // 获得文件的绝对路径 String path = f.getAbsolutePath(); // 获得父文件夹路径,返回字符串 String parentPath = f.getParent(); // 获得父文件夹路径,返回文件对象 File parentFile = f.getParentFile(); // 输出信息 System.out.println("文件名:" + filename); System.out.println("文件大小:" + filesize); System.out.println("文件路径:" + path); System.out.println("文件父路径:" + parentPath); System.out.println("文件父路径:" + parentFile); }
运行结果
判断是否是文件或文件夹
public static void main(String[] args) { // 创建文件对象 File f1 = new File("d:/b.txt"); // 判断是否是一个文件 if(f1.isFile()) { System.out.println(f1.getName()+"是一个文件"); } else { System.out.println(f1.getName()+"不是一个文件"); } // 创建文件对象 File f2 = new File("d:/aaaa"); // 判断是否是一个文件夹 if(f2.isDirectory()) { System.out.println(f2.getName()+"是一个文件夹"); } else { System.out.println(f2.getName()+"不是一个文件夹"); } }
运行结果:
获取当前文件夹下的所有文件列表
public class Test01_08 { public static void main(String[] args) { // 创建文件对象 File f = new File("d:/aaa"); // 获得文件夹下所有文件 File[] files = f.listFiles(); // 遍历文件数组 for (File file : files) { // 将文件的名字打印到控制台 System.out.println(file.getName()); } } }
listFiles(FileFilter filter)、File listFiles(FilenameFilter filter)
、listFile的重写方法
File[] listFiles(FileFilter filter) //返回该文件夹下满足指定过滤器条件的文件和目录。
File listFiles(FilenameFilter filter)
FileFilter 和 FilenameFilter 是一个接口,接口中只定义了accept()一个方法,要使用该接口就要实现该方法
boolean accept(File pathname): FileFilter的方法,File pathname的File文件既有文件类型的也有目录类型的
boolean accept(File dir, String name) : FilenameFilter的方法,
注:File dir:的所有文件都被封装成了一个目录
File[] file = f.listFile(FileFilter filter)方法的执行步骤:
1.获取文件夹下的所有文件,将所有的文件都封装成File类型
2.遍历获取的文件,调用FileFilter的accept(File pathname)方法,将文件挨个传入,根据accept()中定义的规则筛选文件,判断方法的返回值, 若方法的返回值为true则把当前遍历的File文件存放在File[]数组中`
注: 调用boolean accept(File dir, String name)的原理大致相同,只是还多了一个功能,能接收的当前文件 夹的文件名,String name:接收的是文件名称,不是路径名称
public class Test01_09 { public static void main(String[] args) { File f = new File("d:/aaa/aa/a"); /** * d:/aaa/aaa/a下有两个文件:一个_a文件夹,一个a.txt文件 * 要求:只获取d:/aaa/aaa/a下的文件,不获取文件夹 */ File[] file = f.listFiles(new FilenameFilter() { @Override public boolean accept(File pathname, String name) { System.out.println(name); //a.txt /_a if(name.endsWith(".txt")){ return true; } return false; } }); System.out.println(file[0]); } }
**注: 使用FilenameFilter filter,所有文件都被封装成目录即文案夹
流的分类
按流向分:
- 输入流:从硬盘读取数据到内存
- 输出流:从内存中读取数据到硬盘
按读取的类型分:
- 字节流:读取时一次读取一个字节
OutputStream: 输出字节流
InPutStream: 输入字节流 - 字符流:读取时一次读取一个字符
Reader: 输入字符流
Writer:输出字节流
InputStream&OutPutStram
InputStream: 字节输入流
FileInputStream:
从硬盘读取文件内容到内存的的字节输入流
构造方法:
FileInputStream(File file)
FileInputStream(String name)
常用方法:
int read() //返回的是对应的字节数据,当没有数据时返回-1
int read(byte[] b) //返回值为读取的字节个数,
一个一个字节读取到byte[]数组中,再将byte[]数组的内容传递给应用程序
int read(byte[] b, int off, int len) //返回值为从内存中读取的字节个数
一个一个字节读取,将字节数据存放在指定的数组位置
public class Test03 { public static void main(String[] args) throws IOException { // 创建字节输入流对象并关联文件 FileInputStream fis = new FileInputStream("d:/c.txt"); // 定义变量接收读取的字节 int len = -1; byte[] bytes = new byte[6]; // 循环从流中读取数据 while((len = fis.read(bytes))>0) { System.out.print(new String(bytes,0,len)); } // 关闭流 fis.close(); } }
程序读取流的流程:
java程序 -----》找到jvm虚拟机-------->通知Os操作系统-----》由OS去硬盘读取文件
os拿到文件的数据------》通知OS操作系统----->找到JVM虚拟机------》将数据返还给java程序
OutPutStram:字节输出流
FileOutputStream:从内存中读取数据到硬盘的输出流,读取的时候一个字节一个字节读取,输出的时候也是一个字节一个字节的输出
构造方法:
- FileOutputStream(File file) //创建一个输出流,将流关联到指定的输出目的地
- FileOutputStream(String name) //创建一个输出流,将流关联到指定的输出目的地
- FileOutputStream(File file, boolean append) //创建一个输出流,将流关联到指定的输出目的地,并指定是否将数据添加到文件末尾
append = true:当流对象再与目的文件关联时,将数据添加到原文件的末尾
append = false :当流对象再与目的文件关联时,覆盖原文件 - FileOutputStream(String name, boolean append) //创建一个输出流,将流关联到指定的输出目的地,并指定是否将数据添加到文件末尾 append = true:将数据添加到原文件的末尾 append = false :覆盖原文件
常用方法:
- void write(int b) ://将一个字节写到指定目的地,数字>=255,写出的数据内容为空
- void write(byte[] b) // 将一个字节数组的数据写到目的地,写出的形式也是一个字节一个字节的写出到硬盘中
- void write(byte[] b, int off, int len) 将指定位置的字节数组的数据写到硬盘
void close() //关闭流对象
FileOutputStream fos = new FileInputStream("d/a.txt")的语义:
1.首先创建了一个输出流对象
2.输出流对象指向输出的目的地址d:/a.txt
fos.write(97)的语义:
流对象获取字节数据,将数据输出到指定的目的文件中
注:write(97)的97 代表的是一个字节,当写如文件中,文件展示是会根据编码表对数据进行解码,97在编码表中对应的是小写字母a
public class Test01 { public static void main(String[] args) throws IOException { // 1.创建字节输出流FileOutputStream对象并指定文件路径。 FileOutputStream fos = new FileOutputStream("d:/a.txt"); // 2.调用字节输出流的write(int byte)方法写出数据 fos.write(254); // byte[] bytes = {97,98}; fos.write(bytes); // 3.关闭流 fos.close(); } }
文件的换行:
public class Test02 { public static void main(String[] args) throws IOException { // 1.创建字节输出流FileOutputStream对象并指定文件路径,并追加方式 FileOutputStream fos = new FileOutputStream("d:/c.txt",true); // 2.调用字节输出流的write方法写出数据 // 2.1 要输出的字符串 String content = "i love java \r\n"; for (int i = 0; i< 5; i++) { fos.write(content.getBytes()); } // 3.关闭流 fos.close(); } }
程序写出流的流程:
java程序 -----》找到jvm虚拟机-------->通知Os操作系统-----》由OS去内存读取文件
os拿到文件的数据------》通知OS操作系统----->找到JVM虚拟机------》将数据写入到硬盘
Reader&Writer
Reader:字符输入流
FileReader: 操作文件的字符输入流
构造方法:
FileReader(File file)
FileReader(String fileName)
常用方法:
int read()
int read(char[] cbuf) //读取数据时是按字符读取的,单底层又将字符转为字节对象,因此,返回值是字节的个数 l
例如:读取好aaahhh,
返回的int值为8,一个中文字符占2个字节
int read(char[] cbuf, int off, int len)
Writer:字符输出流
FileWriter:操作文件的字符输出流
构造方法:
- FileWriter(File file)
- FileWriter(String fileName)
- FileWriter(File file, boolean append)
- FileWriter(String fileName, boolean append)
常用方法:
- void write(int c)
- void write(char[] cbuf)
- void write(char[] cbuf, int off, int len)
- void write(String str)
- void write(String str, int off, int len)
- void flush() //将内存缓冲区的数据刷到目的文件中
- FileWriter的write()方法实现机制
首选,将要写出的字符数据转为字节数据,放到内存缓冲区中,使用flush()将缓冲区中的数据写入到文件中,因此文件的接收的还是字节数据,再根据文件的编码参照对应的编码表将字节转为对应的字符
Properties(属性集)的使用
Properties的作用:
- load(InputStream instream): //读取键值对文件到Properties集合
- store(OutputStream out, String comments)://写出集合中的数据,形成一个键值对文件
Properties:是一个双列集合
properties extends hashmap ,hashmap implements map
properties:是一个唯一与Io流结合的集合
构造方法:
Properties() //默认范型为<String,String>
常用方法:
String getProperty(String key) ://底层调用map 的 get()方法
Object setProperty(String key, String value) //底层调用map 的 put()方法
set stringPropertyNames() //返回列表的键值,相当于map的keySet()方法
void load(InputStream inStream) //读取外部的键值对文件,将键值对的数据放在Properties集合中,InputStream关联键值对文件的地址
读取的键值对文件的形式一般都是 键 对应 值 ,键值对的连接一般使用 = 空格 或其他连接
void load(Reader reader)
void store(OutputStream out, String comments) //读取Properties集合,将集合中的数据已键值对文件形式存放在OutputStream关联的路径中
void store(Writer writer, String comments)
public class Test06 { public static void main(String[] args) throws IOException { //1:创建一个空的集合 Properties prop = new Properties(); //2:读取数据到集合中 prop.load(new FileInputStream("d:/score.txt")); //3:遍历集合,获取到每一个key Set<String> keys = prop.stringPropertyNames(); //获取到每一个key for (String key : keys) { //4:判断当前的key 是否为 "lisi" if ("lisi".equals(key)) { //把"lisi"的值设置为100 prop.setProperty(key, "100"); } } //把集合中所有的信息,重新存储到文件中 prop.store(new FileOutputStream("d://score.txt"), "haha"); } }
字节缓冲流
缓冲流的作用
在基本流的对象上创建,用于增强基本流的读写效率
四种基本流:
1.字节输入流
2.字节输出流
3.字符输入流
4.字符输出流
BufferedInpuStream: 字节缓冲输入流
构造方法:
- BufferedInputStream(InputStream in)
- BufferedInputStream(InputStream in, int size) //int size:指定了缓冲区的大小
常用方法:
继承了InputStream,有Inputstream的常用方法
BufferedInputStream(FileInputStream in) 的实现原理:
通过`BufferedInputStream创建了一个缓冲区,将缓冲区与流对象关联,FileInputStream in读取数据时不用频繁的来往于硬盘和内存之间,先将数据写入缓冲区中,最后将数据一次性的写入内存
public class Test07 { public static void main(String[] args) throws IOException { // 创建字节输出流FileOutputStream对象并指定文件路径。 FileOutputStream fos = new FileOutputStream("d:\\c.txt"); // 利用字节输出流创建高效字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(fos); // 调用高效字节输出流对象的write(int byte)方法写出一个字节数据 bos.write(97); // 关闭流 bos.close(); } }
BufferedOutputStream: 字节缓冲输出流
- 构造方法:
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size) //int size:指定了缓冲区的大小
常用方法:
继承了OutputStream,有Outputstream的常用方法
BufferedOutputStream(FileOutputStream out) 的实现原理:
通过`BufferedInputStream创建了一个缓冲区,将缓冲区与流对象关联,FileOutputStream out写出数据时不用频繁的来往于内存和硬盘之间,先将要写出的数据写入缓冲区中,最后将数据一次性的写出到硬盘
public static void main(String[] args) throws IOException { // 创建字节输出流FileOutputStream对象并指定文件路径。 FileOutputStream fos = new FileOutputStream("c:\\e.txt"); // 利用字节输出流创建高效字节输出流对象 BufferedOutputStream bos = new BufferedOutputStream(fos); // 调用高效字节输出流对象的write(byte[] buff)方法写出一个字节数据 bos.write("i love java".getBytes()); // 关闭流 bos.close(); }
字符缓冲流
BufferedReader:字符缓冲输入流
构造方法:
BufferedReader(Reader in)
BufferedReader(Reader in, int sz)
特有方法:
String readLine() //读取一个文本行
BufferedWriter:字符缓冲输出流
构造方法:
BufferedWriter(Writer out)
BufferedWriter(Writer out, int sz)
特有方法:
void newLine() //写入一个行分隔符,根据系统识别分隔符
转换流
使用转换流的原因:
因为对于字符来说有不同的编码方式,不同的编码方式对应着不同的编码表,字符的编码和字符的解码应该具有一一对应的关系
编码码的种类
1.GBK编码:一个字符占2个字节
2.Utf-8编码: 一个字符占3个字节
3.ASCII编码
因为编码不同会出现的问题:
电脑本地上一个.txt文件,默认编码格式为1个字符两个字节,当idea(默认编码为utf-8),读取数据时,将.txt传来的数据3个字节默认为一个字符,超找utf-8对应的码表,此时就会出现乱码的情况
InputStreamReader:转换输入流
InputStreamReader extend Reder
构造方法:
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, Charset cs) //指定对读取数据的解码方式
转换输入流的实现原理:
FileInputStream fis = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(fis,"gbk");
1.创建转换输入流对象,以字符的形式读取 InputStreamReader关联的源数据
2.FileInputStream将字符对象转为字节对象,并指定其解码方式
public static void main(String[] args) throws IOException{ // 创建字节输入流对象并关联文件 FileInputStream fis = new FileInputStream("a.txt"); // 创建转换输入流对象 InputStreamReader isr = new InputStreamReader(fis,"gbk"); // 定义字符数组存放读取的内容 char[] buffer = newchar[1024]; // 定义变量接收读取的字符个数 intlen = -1; while((len = isr.read(buffer)) != -1) { System.out.print(new String(buffer,0,len)); } // 关闭流 isr.close(); }
OutputStreamWriter:转换输出流
OutputStreamWriter extend Writer
构造方法:
- OutputStreamWriter(OutputStream out)
- OutputStreamWriter(OutputStream out, Charset cs) //指定对输出数据的编码方式
转换输出流的原理:
FileOutputStream fos = new FileOutputStream("a.txt")
OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
1.创建转换输出流对象,以字符的形式内存中的数据
2.通过FileOutputStream将字符对象转为字节对象,并指定其编码方式
public static void main(String[] args) throws IOException{ // 要保存的字符串 String content = "我爱Java"; // 创建字节输出流对象 FileOutputStream fos = new FileOutputStream("a.txt"); // 创建转换输出流对象 OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk"); // 调用方法写出数据 osw.write(content); // 关闭流释放资源 osw.close(); }
序列化流&反序列化流
ObjectOutputStream:序列化流
序列化:将对象转化为流对象的过程
构造方法:
ObjectOutputStream(OutputStream out)
常用方法:
writeObject(Object obj) //将obj对象写到输出流关联的目的文件中
注:要对对象进行序列化,该对象对应的类必须实现Serializable接口,否则会抛异常
ObjectInputStream:反序列化流
反序列化:将流对象转为对象的过程
构造方法:
ObjectInputStream (InputStream in)
常用方法:
Object readObject() 将InputStream 关联的序列化流对象封装成一个Object对象
实现反序列化的原理:
当一个类实现Serializable接口,该类编译成class文件会自动生成一个serialVersionUID(序列化标识符),当对对象进行序列化时,该标识符也会写入到序列化流中,进行反序列化是就是通过这个标识符来找到对应的class文件,进而得到相应的反序列化对象
当一个class文件被修改时,此时又会生成一个新的serialVersionUID(序列化标识符),原来生成的序列化流就不能反序列成相应的对象,因此需要给类固定一个serialVersionUID(序列化标识符),否则会抛出异常
固定一个serialVersionUID(序列化标识符)的做法:
声明一个变量:private static final Long serialVersionUID = 自定义的一个值
注:被static 和transient(瞬态关键字)修饰的变量的值是不能被序列化的
序列化集合
在文件中保存多个对象,对象存储在集合中,对集合序列化和反序列化
步骤:
1.定义存储对象的集合
2.往集合中添加对象
3.创建序列化流
4.writeObject(集合)
打印流
PrintStream extend OutputStream
特点:只负责数据的输出,不负责读取
构造方法:
PrintStream(File file)
PrintStream(OutputStream out)
PrintStream(String fileName)
常用方法:可以打印任何类型的数据
print(可接收任何数据)
println(可接收任何数据)
PrintStream ps = new PrintStream(File f);
ps.print() //默认在控制条输出
使用System.setOut(ps) : 指定输出到 new PrintStream(File f)关联的文件
其他