文件和目录路径名的抽象表示形式 Java把电脑中的文件和文件夹封装为一个File类,使得我们可以通过使用File对文件和文件夹进行操作
作用 * 由于在不同系统上路径分隔符与名称分隔符的差异,所以采用成员变量的形式进行文件路径的书写可以确保可移植性 * 如:Linux下路径分隔符为 “:” 名称分隔符为"/" 而windows下路径分隔符为";" 名称分隔符为"\"
File(String pathName);
pathName:字符串路径名称路径可以是文件结尾,也可以是文件夹结尾路径可以是相对路径,也可以是绝对路径创建File对象,只是把字符串路径封装为file对象,不考虑路径的真实情况File(String parent,String child);
优点:父路径和子路径单独书写,使用起来非常灵活,父路径和子路径都可以变化File(File parent,String child);
优点: 父路径和子路径单独书写,使用起来非常灵活,父路径和子路径都可以变化父路径是file对象,可以使用一些File的一些方法对路径进行一些操作,再使用路径创建对象 File(URI uri);获取方法
public String getAbsolutePath(): 返回该对象的绝对路路径字符串public String getName(): 返回file表示的文件或文件夹名称public String getPath(): 返回该file的文件路径字符串(创建对象时传入的路径字符串)public Long length(): 返回文件的大小(以字节为单位的),注意 文件夹的大小为0,若路径不存在,也返回0判断方法
public boolean exists(): 此file表示的文件或目录是否存在public boolean isDirectory(): 此文件是否为一个目录public boolean isFile(): 此file表示的是否为文件创建和删除的方法
public boolean createNewFile(): 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件
返回值 true:当文件不存在时,创建文件并放回true、false:当文件存在时,不创建文件,返回false 注意: 此方法只能创建文件,并不能创建文件夹创建文件的路径必须存在,否则会抛出IOExceptionpublic boolean mkdir(): 创建单级文件夹(返回值同上)
注意:创建时看名称不能看类型,public boolean mkdirs(): 既可以创建单级的空文件夹,也可以创建多级文件夹(返回值同上)
路径不存在时不会抛出异常public boolean delete(): 删除file对象表示的文件或文件夹
delete方法时直接在硬盘删除文件,不走回收站,所以删除需要谨慎 File file=new File("a.txt"); file.mkdir(); // 可以创建并且返回true 但是创建的是名为a.txt文件夹4.File类遍历文件夹功能 1. public String [] list(): 返回一个String类型数组,表示file目录中所有的文件或目录 2. public File[] listFiles(): 返回一个file类型数组,表示file目录中所有的文件或目录 3. public File[] listFiles(FileFilter filter): 4. public File[] listFiles(FilenameFilter):
文件过滤器有两种:
FileFilter接口
用于过滤文件(file对象)抽象方法: boolean accept(File pathname) 测试指定抽象路径名是否包含在,某个路径名列表中FilenameFilter接口
用于过滤文件名称抽象方法:boolean accept(File dir,String name) 测试指定文件是否应该包含在某一个文件列表中 File dir :构造方法中传递的被遍历的目录String name:使用listFiles方法遍历目录,获取的每一个文件/文件夹名称注意:
在public File[] listFiles(FileFilter filter): 和public File[] listFiles(FilenameFilter): 执行中,listFile方法总共做了三件事
listFiles方法会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹,并且封装为File对象listFiles方法会调用参数传递的过滤器中的accept方法listFiles方法会把遍历得到的每一个File对象传递给accept方法,作为参数pathname 返回值 当返回为true时,就会把传递过去的File对象保存到File数组中两个过滤器接口中都只有一个抽象方法,需要自己创建类实现接口,由于只有一个抽象方法所以还可以使用lamda表达式来简化书写 以下是两个过滤器使用的实例(搜索文件中)
package filetest; import java.io.File; // 使用监听器对文件夹中所有的以 .java结尾的文件进行输出打印 public class IODemo01 { public static void main(String[] args){ // 使用了相对路径 File file=new File("../JavaSEReview"); allFile(file); } public static void allFile(File file){ File[] files=file.listFiles(new FileFilterImpl()); // 可以采用匿名内部类简化,也可以采用lamda表达式简化 if (files != null) { for (File file1:files ) { // 采用递归语句将文件夹逐一遍历 if(file1.isDirectory()){ allFile(file1); }else{ System.out.println(file1); } } } } }FileFilter接口的实现:
package filetest;/* * @author:一身都是月~ * @date:2020/10/3 9:31 * */ import java.io.File; import java.io.FileFilter; public class FileFilterImpl implements FileFilter { @Override public boolean accept(File pathname) { if (pathname.getName().endsWith(".java")||pathname.isDirectory()) { return true; } return false; } }FilenameFilter接口的实现:
package filetest;/* * @author:一身都是月~ * @date:2020/10/3 9:32 * */ import java.io.File; import java.io.FilenameFilter; public class FilenameFilterImpl implements FilenameFilter { @Override public boolean accept(File dir, String name) { File file=new File(dir,name); if (file.getName().endsWith(".java")||file.isDirectory()){ return true; } return false; } }注意: 1. 路径是不区分大小写的 2. 路径中的文件名称分隔符windows下使用反斜杠,而反斜杠是转义字符,所以需要使用两个反斜杠表示一个普通的反斜杠
终于到大头IO流了
我想肯定有很多小伙伴才开始的时候会分不清输入和输出吧,反正当时我是这样的,先看一张 图,看完你就直到啦~
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IL4XXTXC-1601883703353)(C:\Users\Lenovo\Desktop\学习\笔记文档\IO流01.png)]
计算机中的一切文件数据(文本、视频、图片……)都是以2进制数字形式保存的,都是一个个的字节,所以在传输时一样如此,字节流可以传输任意文件数据,在操作流的时候,我们要时刻明白,无论使用什么流对象,底层的传输都是二进制数据
注意
使用字节流写数据时,会把10进制的整数转换为2进制的整数,(注意写进文件的是字节),在我们打开记事本等文本编辑器的时候,查询编码表,将字节转换为字符表示 如果在 0-127 范围内,会查询ASCII表 其他数值则会查询系统默认编码表 可以结合String转换为字节数组,然后写入
使用步骤 1. 创建一个OutputStream对象 2. 调用对象中的输出方法,把数据写入到文件中 3. 释放资源(流会占用一定的内存,使用完毕需要把内存清空)
【OutputStream】是所有输出字节流的超类 定义了一些子类共性的方法 public void close() 关闭此输出流并释放与此流下相关联的任何系统资源public void flush() 刷新此输出流并强制任何缓冲的输出字节流被写出public void write(byte[] b) 将b.length个字节从指定的数组写到此输出流中 如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表如果写的第一个字节是负数,那第一个字节会和第二个字节组成一个中文显示,查询系统默认编码表(GBK) public void write(byte[] b , int off , int len) 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流中public abstract void write(int b) 将指定的字节输出流注意
使用字节流读取数据时,得到的是对应的字节数据,所以可以使用char转型从而得到字符数据 可以使用read(byte[] b) 将数据读取到字符数组中,然后可以用String中一个构造方法转换为字符串,- String(byte[] bytes) String(byte[] bytes, int offset , int length)
使用步骤 1. 创建一个InputStream对象 2. 调用对应的读取方法 3. 释放资源
【InputStream】是所有字节输入流的超类
定义了一些子类共用的方法 int read() 从输入流中读取数据的下一个字节,当读取到文件末尾时,返回-1int read(byte[] b)void close()FileInputStream:文件字节输入流
构造方法 FileInputStream(String name)FileInputStream(File file)参数: String name:文件路径File file:文件 构造方法的作用 创建一个FileInputStream对象会把FileInputStream对象指定构造方法中要读取的文件 常用方法 public int read();public int read(byte[] bytes); 关于参数 bytes[] 起到缓冲作用,存储每次读取到的多个字节数组长度一般定义为1024(1kb)或者1024的整数倍 返回值int 表示每次读取的有效字节个数,当达到数据末尾则返回-1 读取数据的原理(硬盘------>内存) java程序------> JVM-------> OS(操作系统)------->OS读取 数据的方法---->读取文件.【Reader】 所有字符输入流的超类
定义了一些子类共用的方法 .FileReader
继承自inputStreamReader,InputStreamReader又继承自Reader构造方法 FileReader(String name);FileReader(File file);此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的,想要自己指定这些值,需要结合转换流使用
使用步骤 1. 创建FileWriter对象,构造方法中绑定数据写入的目的地 2. 使用FileWriter中的方法write,把数据写入到内容缓冲区(字符转换为字节) 3. 使用FileWriter中的flush,把内存缓冲区中的数据,刷新到文件中 4. 释放资源(会先把缓冲区的数据刷新到新文件中)
注意 * 虽然参数为int类型的四个字节,但是只会保留一个字符的信息写出 * 未调用close方法,数据只是保存到了缓冲区。并未写入到文件中
【Writer】 所有字符输出流的超类FileWriter可以在try后边增加一个(),在括号中定义流对象,那么这个流对象的作用域就在try中有效,try代码执行完毕后,会自动把流对象释放,不用再写finally
于是代码可以这样写
public static void copyFile(){ try (OutputStream os=new FileOutputStream("../JavaSEReview/src/filetest/copy.txt",false); InputStream is=new FileInputStream("../JavaSEReview/src/filetest/IODemo01.java");){ byte[] bytes=new byte[1024]; int len; while((len=is.read(bytes))!=-1){ os.write(bytes,0,len); } } catch (IOException e) { e.printStackTrace(); } } JDK9新特性在try前边可以定义流对象,在try后边的()中可以直接引入流对象的名称(变量名),在try代码执行完毕后,流对象也可以自动释放掉,不用写finally
我这里由于JDK版本并没有升级就不做案例了,不过感觉JDK9版本的这个新特性有点多余,因为try。catch后还是得throws,当然这个我也不是很清楚欢迎大家补充
BufferedOutputStream继承自OutputStream
继承自父类的共性成员方法:
public void close()public void flush()public void write(byte[] b)public void write(byte[] b , int off , int len)public abstract void write(int b)构造方法
BufferedOutputStream(OutputStream out) 创建一个新的缓冲流,将数据写到指定的底层输出流BufferedOutputStream(OutputStream out , int size) 创建一个新的缓冲流,以将具有指定缓冲区大小的数据写入指定的底层输入流 参数: OutputStream字节输出流,我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高其写入效率int size:指定缓冲区大小,可以不指定使用步骤
创建FileOutputStream对象,构造方法中绑定输出的目的地创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,使用BufferedOutputStream对象的write方法,将数据写入到内部缓冲区使用BufferedOutputStream对象中的flush方法,将内部缓冲区的文件刷新到文件中释放资源(会先调用flush方法,所以第四步可以省略)特有成员方法
void newLine() 写一个行分隔符,会根据不同的操作系统,获取不同的换行符windows: \r\nLinux: /nMac:/r使用步骤:
创建字符缓冲输出流对象,构造方法中传递字符输出流调用字符缓冲流中的方法write,把数据写入到内存缓冲区调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据刷新到文件中释放资源在IDEA中,使用FileReader读取项目中的文本文件,由于IDEA的设置,都是默认为UTF-8编码所以并没有出现问题,然而,在读取创建的本地的非UTF-8编码的文件时,就会出现乱码问题
UTF-8 国际标准码表,用三个字节存储中文字符GBK 中文码表,使用两个字节存储中文字符类通过实现Serializable接口以启用其序列化功能,未实现接口的类将无法使其任何状态序列化与反序列化,序列化接口没有方法和字段,仅用于标识可序列化的语义 如果不实现接口,则会抛出NotSerializableException异常
注意
静态的成员变量是不能被序列化的
static 静态优先于非静态加载到内存中(静态优先于对象进入到内存中)transient关键字修饰的成员变量也不能被序列化
transient:瞬态关键字,被transient修饰成员变量,不能被序列化序列化运行时使用一个称为serialVersionUID的版本号与每个可序列化类相关联,该序列hao 在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类,如果接收者加载的该对象的serialVersionUID与对应的发送者的类的版本号不同,则反序列化将会导致InvalidClassException异常,所以在每次修改了类的定义后,都会给class文件生成一个新的序列号,导致之前序列化的对象反序列化失败
解决方法:无论是否对类的定义修改,都不重新生成新的序列号(可以手动给类添加一个序列号) 在可序列化类中可以通过声明名为“serialVersionUID”字段,**(该字符必须是静态的static、最终的final、long型字段)**显示的声明自己的serialVersionUID;把对象以流的方式写入到文件,叫写对象,也叫对象的序列化
ObjectOutputStream:对象的序列化流构造方法:
ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream的ObjectOutputStream特有方法
writerObject(Object object) 将指定的对象写入到ObjectOutputStream流中把文件中保存的对象,以流的方式读取出来,叫读对象,也叫对象的反序列化
ObjectInputStream:对象的反序列化流
特有方法 Object readObject() 除了声明了IOException异常外,还有ClassNotFoundException异常PrintStream:打印流 PrintStream 为其他输出流添加了功能,使它们能够方便的打印各种数据值表示形式
特点:
只负责数据的输出,不负责数据的读取与其他输出流不同,PrintStream永远不会抛出IOException异常有自己的自动的flush功能继承自OutputStream构造方法:
PrintStream(File file)PrintStream(OutputStream out )PrintStream(String fileName)其余方法可到java api中查询注意:
如果使用继承自父类的write方法写数据,那么查看数据时就会查询编码表如果使用PrintStream特有的方法print/println 方法写数据,写的数据原样输出可以改变输出语句的目的地(打印流的刘翔) 输出语句(System.out.print())默认在控制台输出,可以使用System.setOut(PrintStream printStream)方法,改变默认的输出的目的地