目录
♫什么是文件
♫文件路径
♫文件类型
♫文件的管理
♪File的构造方法
♪File的常用方法
♫文件的内容操作
♪InputStream
♪OutputStream
♪字符流读写文件
♫Scanner与流对象
♫什么是文件
文件在计算机里可以指“狭义”的文件(指硬盘上的文件和目录),也可以值“广义”的文件(操作系统将很多硬件设备和软件资源也抽象成文件来统一管理),这里要介绍的文件就是指“狭义”的文件。
♫文件路径
变量存储数据是在内存中,而文件存储数据则是在硬盘上,每个文件在硬盘上都有一个独有的文件路径,文件路径有绝对路径和相对路径之分,下面这个图片的绝对文件路径就是D:/picture/tree.png:
其中D:为盘符,是通过硬盘分区来的,每个盘符可以对应一个硬盘,也可以多个盘符对应一个硬盘;/用于分割目录,windows也可以用\分割目录,如果在代码中用\需要注意转义字符的问题。
它的相对路径根据当前工作目录的不同而变化:
♩.如果工作目录是D:/,相对路径写作./picyure/tree.png
♩.如果工作目录是D:/picture,相对路径写作./tree.png
♩.如果工作目录是D:/picture./a,相对路径写作../tree.png(..表示当前目录的上一级)
♩.如果工作目录是D:/picture/a/b,相对路径写作../../tree.png
♫文件类型
我们平常使用的文件有音频文件,视频文件,图片文件,word文件等等,这些不同的文件都可以归纳为文本文件和二进制文件两种。
♩.文本文件:是一种用于存储文本数据的文件类型,其中包含 ASCII 或 Unicode 编码的字符。文本文件往往包括人类可读的字符和行结尾符号。常见的文本文件格式包括.txt、.html、.xml 等。
♩.二进制文件:是使用二进制代码编写的文件类型,它们可以包含任何类型的数据,包括图像、音频、视频、可执行文件和其他应用程序数据。二进制文件由计算机使用特定的二进制编码表示,无法直接阅读或修改。
♫文件的管理
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述,但是有 File 对象并不代表真实存在该文件,通过File类可以查询、创建、删除文件。File的属性
修饰符及返回类型 属性 描述 static String pathSeparator 依赖于系统的路径分隔符, String 类型的表示static char pathSeparator 依赖于系统的路径分隔符, char 类型的表示注:pathSeparator 是File的一个静态变量,相当于 / 或 \♪File的构造方法
方法 描述 File(File parent, String child) 根据父目录 + 孩子文件路径,创建一个新的 File 实例 File(String pathname) 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径 File(String parent, String child) 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示File file = new File("d:/"); File file1 = new File(file,"test"); File file2 = new File("d:/test"); File file3 = new File("d:/","test"); System.out.println(file1); System.out.println(file2); System.out.println(file3);
运行结果:
♪File的常用方法
返回值类型方法名 描述 String getParent() 返回 File 对象的父目录文件路径String getName() 返回 FIle 对象的纯文件名称String getPath() 返回 File 对象的文件路径String getAbsoultePath() 返回 File 对象的绝对路径String getCanonicalPath() 返回 File 对象的修饰过的绝对路径boolean exists() 判断 File 对象描述的文件是否真实存在boolean isDirectory() 判断 File 对象代表的文件是否是一个目录boolean isFile() 判断 File 对象代表的文件是否是一个普通文件boolean createNewFile() 根据 File 对象,自动创建一个空文件。成功创建后返回 trueboolean delete() 根据 File 对象,删除该文件。成功删除后返回 truevoid deleteOnExit() 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行String list() 返回 File 对象代表的目录下的所有文件名File[] listFiles() 返回 File 对象代表的目录下的所有文件,以 File 对象表示boolean mkdir() 创建 File 对象代表的目录boolean mkdirs() 创建 File 对象代表的目录,如果必要,会创建中间目录boolean renameTo(File dest) 进行文件改名,也可以视为我们平时的剪切、粘贴操作boolean canRead() 判断用户是否对文件有可读权限boolean canWrite() 判断用户是否对文件有可写权限
♫文件的内容操作
Java中使用流对象对文件内容进行操作,从类型上分为以字节为单位读写数据的字节流对象(InputStream、OutputStream)和以字符为单位读写数据的字符流对象(Reader、Writer),流对象的四个核心操作是:①.打开文件(构造方法)(8)②.关闭文件(close())③.读文件(read() 对应 InputStream 和 Reader)④.写文件(write() 对应 OutPutStream 和 Writer)。
♪InputStream
InputStream 用于以字节为单位读取文件内容,它是抽象类,可以借助它的实现类(如:FileInputStream)来创建实例对象:
public class Test { public static void main(String[] args) throws FileNotFoundException { File file = new File("d:/test"); InputStream inputStream1 = new FileInputStream(file); InputStream inputStream2 = new FileInputStream("d:/test"); } }
创建好实例对象后可以通过read()方法读取该文件的内容:
返回类型 方法名 描述 int read() 读取一个字节的数据,返回 -1 代表已经完全读完了int read(byte[] b) 最多读取 b.length 字节的数据到 b 中,返回实际读到的数量, -1 代表以及读完了int read(byte[] b, int off, int len) 从 off 开始读,最多读取 len - off 个 字节的数据到 b 中,返回实际读到的数量, -1 代表以及读完了public class Test { public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("d:/test"); byte[] buffer1 = new byte[1024]; byte[] buffer2 = new byte[1024]; int a = inputStream.read(); inputStream.read(buffer1); inputStream.read(buffer2,2,4); } }
注:访问硬盘/IO设备是比较耗时的,故一次读取一个字节,总共读取1024次比一次读取1024个字节更耗时
读取完文件内容后就可以关闭该流对象:
inputStream.close();
注:一个线程对应一个PCB,一个进程对应一个或多个PCB,每个进程里PCB所对应的文件描述符表是共用的,每次打开一个文件都会在文件描述符表上申请一个位置,如果打开的文件不及时释放就可能导致文件描述符表被占满了,这样子下次再申请打开文件就会打开失败
虽然JC会在回收OutputStream对象的时候释放文件描述符表,但一般还是我们手动释放比较及时,为了保证能执行到close操作可以这样处理:
try(InputStream inputStream = new FileInputStream("d:/test")) { byte[] buffer1 = new byte[1024]; byte[] buffer2 = new byte[1024]; int a = inputStream.read(); inputStream.read(buffer1); inputStream.read(buffer2,2,4); }
这个语法在Java中叫作try with resources,需要实现Closeable接口的类才被使用:
♪OutputStream
OutputStream 用于以字节为单位写入文件内容,它也是抽象类,可以借助它的实现类(如:FileOutputStream)来创建实例对象
public class Test { public static void main(String[] args) throws FileNotFoundException { File file = new File("d:/text"); OutputStream outputStream1 = new FileOutputStream(file); OutputStream outputStream2 = new FileOutputStream("d:/test"); } }
创建好实例对象后可以通过write()方法向该文件写入内容:
返回类型 方法名 描述 void write(int b) 写入要给字节的数据void write(byte[] b) 将 b 这个字节数组中的数据全部写入os中int write(byte[] b, int off, int len) 将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个public class Test { public static void main(String[] args) throws IOException { OutputStream outputStream = new FileOutputStream("d:/text"); byte[] b = new byte[1024]; outputStream.write(97); outputStream.write(b); outputStream.write(b,3,5); } }
注:OutputStream打开一个文件会清空文件的原有内容
OutputStream也继承了closeable接口:
同样可以使用try with resources的方式关闭字节流:
try(OutputStream outputStream = new FileOutputStream("d:/text")) { byte[] b = new byte[1024]; outputStream.write(97); outputStream.write(b); outputStream.write(b,3,5); }
由于 I/O 的速度是很慢的,所以 OutputStream 为 了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定缓冲区里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,close()会在关闭流对象的同时刷新缓冲区,通过 flush() 也可以对缓冲区进行刷新:
outputStream.flush();
♪字符流读写文件
字符流读写文件和字节流差不多,都是通过 read() 和 write() 方法实现读写操作:
public class Test { public static void main(String[] args) { try(Reader reader = new FileReader("d:/text")) { while (true) { int ch = reader.read(); if (ch == -1) { break; } System.out.print("" + (char)ch); } } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } }
public class Test { public static void main(String[] args) { try(Writer writer = new FileWriter("d:/text")) { writer.write("hello"); } catch (IOException e) { throw new RuntimeException(e); } } }
♫Scanner与流对象
Scanner 是搭配流对象来使用的,我们常用的 Scanner scanner = new Scanner(System.in); 中 System.in 就是一个标准输入输出流对象(从键盘读取数据),当将该该流对象替换成文件流对象时就会从文件里读取数据:
public class Test { public static void main(String[] args) { try (InputStream inputStream = new FileInputStream("d;/test")) { Scanner scanner = new Scanner(inputStream); //从文件读取数据 scanner.next(); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } }