File类的使用


1.File类的理解

1.File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹) 2.File类声明在java.io包下 3.File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成
4.后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的“终点”


2.File的实例化
2.1常用构造器

File(String filePath)
File(String parentPath, String childPath)
File(File parentPath, String childPath)


2.2路径的分类

相对路径:相较于某个路径下,指明的路径
绝对路径:包含盘符在内的文件或文件目录的路径


说明:

IDEA中:
如果大家开发使用Junit中的单元测试方法测试,相对路径即为当前Module下
如果大家使用main()测试,相对路径即为当前的Project下
Eclipse中:
不管使用单元测试方法还是使用main()测试,相对路径都是当前的Project下


2.3路径分隔符

windows:\
unix:/


3.File类的常用方法
image.png
image.png
image.png


IO流概述

1.流的分类

  • 1.操作数据单位:字节流、字符流
  • 2.数据的流向:输入流、输出流
  • 3.流的角色:节点流、处理流


图示:
image.png

2.流的体系结构
image.png

3.重点说明的几个流结构
image.pngimage.png
image.png

4.输入、输出的标准化过程
**4.1输入过程

① 创建File类的对象,指明读取数据的来源。(要求此文件一定要存在)
② 创建相应的输入流,将File类的对象作为参数,传入流的构造器中
③ 具体读入过程:创建相应的byte[ ] 或char[ ]
④ 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理


4.2输出过程

① 创建File类的对象,指明写出数据的位置。(不要求此文件一定要存在)
② 创建相应的输出流,将File类的对象作为参数,传入流的构造器中
③ 具体写出过程:write(char[ ] / byte[ ] buffer, 0, len)
④ 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理


节点流(或文件流)

1.FileReader/FileWriter的使用:
1.1FileReader的使用

  1. /*
  2. 将java25下的hello.txt文件内容读入程序中,并输出到控制台
  3. 说明点:
  4. 1.read():返回读入的一个字符。如果达到文件末尾,返回-1
  5. 2.异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
  6. 3.读入的文件一定要存在,否则就会报FileNotFoundException
  7. */
  8. //对read()操作升级:使用read的重载方法
  9. @Test
  10. public void testFileReader1(){
  11. FileReader fr = null;
  12. try {
  13. //1.File类的实例化
  14. File file = new File("hello.txt");
  15. //2.FileReader流的实例化
  16. fr = new FileReader(file);
  17. //3.读入的操作
  18. //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾。返回-1
  19. char[] cbuf = new char[5];
  20. int len;
  21. while ((len = fr.read(cbuf)) != -1){
  22. //方式一:
  23. //错误的写法
  24. // for (int i = 0;i < cbuf.length;i++){
  25. // System.out.print(cbuf[i]);
  26. // }
  27. //正确的写法
  28. // for (int i = 0;i < len;i++){
  29. // System.out.print(cbuf[i]);
  30. // }
  31. //方式二:
  32. //错误的写法:对应着方式一的错误的写法
  33. // String str = new String(cbuf);
  34. // System.out.println(str);
  35. //正确的写法
  36. String str = new String(cbuf, 0, len);
  37. System.out.println(str);
  38. }
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. } finally {
  42. if (fr != null){
  43. //4.资源的关闭
  44. try {
  45. fr.close();
  46. } catch (IOException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }
  51. }

1.2FileWriter的使用

  1. /*
  2. 从内存中写出数据到硬盘的文件里
  3. 说明:
  4. 1.输出的操作,对应的File可以不存在的。并不会报异常
  5. 2.File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件
  6. File对应的硬盘中的文件如果存在:
  7. 如果流使用的构造器是:FileWrite(file, false) / FileWriter(file):对原有文件的覆盖
  8. 如果流使用的构造器是:FileWrite(file, true):不会对原有文件覆盖,而是在原有文件基础上追加内容
  9. */
  10. @Test
  11. public void testFileWriter(){
  12. FileWriter fw = null;
  13. try {
  14. //1.提供File类的对象,指明写出到的文件
  15. File file = new File("hello1.txt");
  16. //2.提供FileWriter的对象,用于数据的写出
  17. fw = new FileWriter(file, false);
  18. //3.写出的操作
  19. fw.write("I have a dream!\n");
  20. fw.write("you need to have a dream!");
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. } finally {
  24. //4.流资源的关闭
  25. try {
  26. if (fw != null) {
  27. fw.close();
  28. }
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }


1.3文本文件的复制

  1. @Test
  2. public void testFileReadFileWriter(){
  3. FileReader fr = null;
  4. FileWriter fw = null;
  5. try {
  6. //1.创建File的对象,指明读入和写出的文件
  7. File srcFile = new File("hello.txt");
  8. File destFile = new File("hello2.txt");
  9. //不能使用字符流来处理图片等字节数据
  10. // File srcFile = new File("劳斯莱斯.jpg");
  11. // File destFile = new File("劳斯莱斯1.jpg");
  12. //2.创建输入流和输出流的对象
  13. fr = new FileReader(srcFile);
  14. fw = new FileWriter(destFile);
  15. //3.数据的读入和写出操作
  16. char[] cbuf = new char[5];
  17. int len;//记录每次读入到cbuf数组中的字符个数
  18. while ((len = fr.read(cbuf)) != -1){
  19. //每次写出len个字符
  20. fw.write(cbuf, 0, len);
  21. }
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. } finally {
  25. //4.关闭流资源
  26. //方式一:
  27. // try {
  28. // if (fw != null) {
  29. // fw.close();
  30. // }
  31. // } catch (IOException e) {
  32. // e.printStackTrace();
  33. // }finally {
  34. // try {
  35. // if (fr != null) {
  36. // fr.close();
  37. // }
  38. // } catch (IOException e) {
  39. // e.printStackTrace();
  40. // }
  41. // }
  42. //方式二:
  43. try {
  44. if (fw != null) {
  45. fw.close();
  46. }
  47. } catch (IOException e) {
  48. e.printStackTrace();
  49. }
  50. try {
  51. if (fr != null) {
  52. fr.close();
  53. }
  54. } catch (IOException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. }

2.FileInputSteam / FileOutputStream的使用:

结论:

1.对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
2.对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理

  1. /*
  2. 实现对图片的复制
  3. */
  4. @Test
  5. public void testFileInputOutputStream(){
  6. FileInputStream fis = null;
  7. FileOutputStream fos = null;
  8. try {
  9. //1.造文件
  10. File srcfile = new File("劳斯莱斯.jpg");
  11. File destfile = new File("劳斯莱斯1.jpg");
  12. //2.造流
  13. fis = new FileInputStream(srcfile);
  14. fos = new FileOutputStream(destfile);
  15. //3.复制的过程
  16. byte[] buffer = new byte[1024];
  17. int len;
  18. while ((len = fis.read(buffer)) != -1){
  19. fos.write(buffer, 0, len);
  20. }
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. } finally {
  24. if (fos != null){
  25. try {
  26. //4.关闭流资源
  27. fos.close();
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. if (fis != null){
  33. try {
  34. fis.close();
  35. } catch (IOException e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. }
  40. }

【注意】

相对路径在IDEA和Eclipse中使用的区别?
IDEA:
如果使用单元测试方法,相对路径基于当前Module的
如果使用main()测试,相对路径基于当前Project的
Eclipse:
单元测试方法还是main(),相对路径都是基于当前Project的


缓冲流的使用

1.缓冲流涉及到的类:

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter


2.作用:

提高流的读入、写入的速度
提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb

3.典型代码
3.1使用BufferedInputStream和BufferedOutputStream:处理非文本文件

  1. @Test
  2. public void BufferedStreamTest(){
  3. BufferedInputStream bis = null;
  4. BufferedOutputStream bos = null;
  5. try {
  6. //1.造文件
  7. File srcFile = new File("2021JavaEE学习路线图.jpg");
  8. File destFile = new File("2021JavaEE学习路线图2.jpg");
  9. //2.造流
  10. //2.1 造节点流
  11. FileInputStream fis = new FileInputStream(srcFile);
  12. FileOutputStream fos = new FileOutputStream(destFile);
  13. //2.2 造缓冲流
  14. bis = new BufferedInputStream(fis);
  15. bos = new BufferedOutputStream(fos);
  16. //3.复制的细节:读入、写出
  17. byte[] buffer = new byte[10];
  18. int len;
  19. while ((len = bis.read(buffer)) != -1){
  20. bos.write(buffer, 0, len);
  21. // bos.flush();//刷新缓冲区
  22. }
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. } finally {
  26. //4.资源关闭
  27. //要求:先关闭外层的流,再关闭内层的流
  28. if (bos != null){
  29. try {
  30. bos.close();
  31. } catch (IOException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. if (bis != null){
  36. try {
  37. bis.close();
  38. } catch (IOException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. //说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略
  43. // fos.close();
  44. // fis.close();
  45. }
  46. }

3.2使用BufferedReader和BufferedWriter:处理文本文件

  1. @Test
  2. public void testBufferedReaderBufferedWriter(){
  3. BufferedReader br = null;
  4. BufferedWriter bw = null;
  5. try {
  6. //创建文件和相应的流
  7. br = new BufferedReader(new FileReader("dbcp.txt"));
  8. bw = new BufferedWriter(new FileWriter("dbcp2.txt"));
  9. //读写操作
  10. //方式一:使用char[]数组
  11. // char[] cbuf = new char[1024];
  12. // int len;
  13. // while ((len = br.read(cbuf)) != -1){
  14. // bw.write(cbuf, 0, len);
  15. // // bw.flush();
  16. // }
  17. //方式二:使用String
  18. String data;
  19. while ((data = br.readLine()) != null){
  20. //方法一:
  21. // bw.write(data + "\n");//data中不包含换行符
  22. //方法二:
  23. bw.write(data);//data中不包含换行符
  24. bw.newLine();//提供换行的操作
  25. }
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. } finally {
  29. if (bw != null){
  30. //关闭资源
  31. try {
  32. bw.close();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. if (br != null){
  38. try {
  39. br.close();
  40. } catch (IOException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }
  45. }

转换流的使用

1.转换流涉及到的类:属于字符流

InputStreamReader:将一个字节的输入流转换为字符的输入流
解码:字节、字节数组 —-> 字符数组、字符串

OutputStreamWriter:将一个字符的输出流转换为字节的输出流
编码:字符数组、字符串 —-> 字节、字节数组
说明:编码决定了解码的方式


2.作用:

  1. 提供字节流与字符流之间的转换


3.图示:
image.png

4.典型实现:

  1. @Test
  2. public void test1() throws IOException {
  3. FileInputStream fis = new FileInputStream("dbcp.txt");
  4. InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
  5. //参数二指明了字符集,具体使用哪个字符集,取决于文件保存时使用的字符集
  6. // InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
  7. char[] cbuf = new char[20];
  8. int len;
  9. while ((len = isr.read(cbuf)) != -1){
  10. String str = new String(cbuf, 0, len);
  11. System.out.print(str);
  12. }
  13. isr.close();
  14. }
  15. /*
  16. 此时处理异常的话,仍然应该使用try-catch-finally
  17. 综合使用InputStreamReader和OutputStreamWriter
  18. */
  19. @Test
  20. public void test2() throws IOException {
  21. //1.造文件、造流
  22. File file1 = new File("dbcp.txt");
  23. File file2 = new File("dbcp_gbk.txt");
  24. FileInputStream fis = new FileInputStream(file1);
  25. FileOutputStream fos = new FileOutputStream(file2);
  26. InputStreamReader isr = new InputStreamReader(fis, "utf-8");
  27. OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
  28. //2.读写过程
  29. char[] cbuf = new char[20];
  30. int len;
  31. while ((len = isr.read(cbuf)) != -1){
  32. osw.write(cbuf, 0, len);
  33. }
  34. //3.关闭资源
  35. osw.close();
  36. isr.close();
  37. }


5.说明:

文件编码的方式(比如:GBK),决定了解析时使用的字符集(也只能是GBK)


编码集

1.常见编码表

ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表。最多两个字节编码所有字符
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。


2.对后面学习的启示

客户端/浏览器端 <—-> 后台(java , Go , Python , Node.js , php) <—-> 数据库
要求前前后后使用的字符集都要统一:UTF-8


其它的流的使用


1.标准的输入输出流:

System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
修改默认的输入和输出行为:
System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流


2.打印流:

PrintStream和PrintWriter

说明:
提供了一系列重载的print()和println()方法,用于多种数据类型的输出
System.out返回的是PrintStream的实例


3.数据流:

DataInputStream和DataOutputStream

作用:
用于读入或写出基本数据类型的变量或字符串


示例代码:

  1. /*
  2. 练习:将内存中的字符串、基本数据类型的变量写出到文件中
  3. 注意:处理异常的话,仍然应该使用try-catch-finally
  4. */
  5. @Test
  6. public void test3() throws IOException {
  7. //1.
  8. DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
  9. //2.
  10. dos.writeUTF("刘建辰");
  11. dos.flush();//刷新操作,将内存中的数据写入文件
  12. dos.writeInt(23);
  13. dos.flush();
  14. dos.writeBoolean(true);
  15. dos.flush();
  16. //3.
  17. dos.close();
  18. }
  19. /*
  20. 将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中
  21. 注意点:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致
  22. */
  23. @Test
  24. public void test4() throws IOException {
  25. //1.
  26. DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
  27. //2.
  28. String name = dis.readUTF();
  29. int age = dis.readInt();
  30. boolean isMale = dis.readBoolean();
  31. System.out.println("\tname = " + name + "\tage = " + age + "\tisMale = " + isMale);
  32. //3.
  33. dis.close();
  34. }

对象流的使用


1.对象流:

ObjectInputStream和ObjectOutputStream


2.作用:

用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

image.png

3.对象的序列化机制:

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,可以恢复成原来的Java对象


4.序列化过程代码实现:

  1. /*
  2. 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
  3. 使用ObjectOutputStream
  4. */
  5. @Test
  6. public void testObjectOutputStream(){
  7. ObjectOutputStream oos = null;
  8. try {
  9. //1.
  10. oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
  11. //2.
  12. oos.writeObject(new String("我爱中国!"));
  13. oos.flush();//刷新操作
  14. oos.writeObject(new Person("王哥",23));
  15. oos.flush();
  16. oos.writeObject(new Person("张哥",23,1001,new Account(5000)));
  17. oos.flush();
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. } finally {
  21. if (oos != null){
  22. //3.
  23. try {
  24. oos.close();
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }
  30. }

5.反序列化过程代码实现:

  1. /*
  2. 反序列化:将磁盘文件中的对象还原为内存中的一个java对象
  3. 使用ObjectInputStream
  4. */
  5. @Test
  6. public void testObjectInputStream(){
  7. ObjectInputStream ois = null;
  8. try {
  9. ois = new ObjectInputStream(new FileInputStream("object.dat"));
  10. Object obj = ois.readObject();
  11. String str = (String) obj;
  12. Person p = (Person) ois.readObject();
  13. Person p1 = (Person) ois.readObject();
  14. System.out.println(str);
  15. System.out.println(p);
  16. System.out.println(p1);
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. } catch (ClassNotFoundException e) {
  20. e.printStackTrace();
  21. } finally {
  22. if (ois != null){
  23. try {
  24. ois.close();
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }
  30. }

6.实现序列化的对象所属的类需要满足:

1.需要实现:Serializable
2.当前类提供一个全局常量:serialVersionUID
3.除了当前类需要实现Serializable接口之外,还必须保证其内部所有属性也必须可序列化(默认情况下,基本数据类型可序列化)
补充: ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量



RandomAccessFile的使用


1.随机存取文件流:RandomAccessFile

2.使用说明:

1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建
如果写出到的文件存在,则会对原有文件内容进行覆盖(默认情况下,从头覆盖)
4.可以通过相关的操作,实现RandomAccessFile”插入“数据的效果。seek(int pos)


3.
典型代码1:

  1. @Test
  2. public void test1(){
  3. RandomAccessFile raf1 = null;
  4. RandomAccessFile raf2 = null;
  5. try {
  6. raf1 = new RandomAccessFile(new File("劳斯莱斯.jpg"),"r");
  7. raf2 = new RandomAccessFile(new File("劳斯莱斯1.jpg"),"rw");
  8. byte[] buffer = new byte[1024];
  9. int len;
  10. while ((len = raf1.read(buffer)) != -1){
  11. raf2.write(buffer, 0, len);
  12. }
  13. } catch (IOException e) {
  14. e.printStackTrace();
  15. } finally {
  16. if (raf1 != null){
  17. try {
  18. raf1.close();
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. if (raf2 != null){
  24. try {
  25. raf2.close();
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }

典型代码2:

  1. /*
  2. 使用RandomAccessFile实现数据的插入效果
  3. */
  4. @Test
  5. public void test3() throws IOException {
  6. RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
  7. raf1.seek(3);//将指针调到角标为3的位置
  8. //保存指针3后面的所有数据到StringBuilder中
  9. StringBuilder builder = new StringBuilder((int) (new File("hello.txt").length()));
  10. byte[] buffer = new byte[20];
  11. int len;
  12. while ((len = raf1.read(buffer)) != -1){
  13. builder.append(new String(buffer, 0, len));
  14. }
  15. //调回指针,写入”xyz“
  16. raf1.seek(3);
  17. raf1.write("xyz".getBytes());
  18. //将StringBuilder写入到文件中
  19. raf1.write(builder.toString().getBytes());
  20. raf1.close();
  21. //思考:将StringBuilder替换为ByteArrayOutputStream
  22. }

Path、Paths、Files的使用

1.NIO的使用说明:

Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java IO API
NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作。
NIO将以更加高效的方式进行文件的读写操作
随着 JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为NIO.2。


2.Path的使用 —- JDK7提供
2.1 Path的说明:

Path替换原有的File类


2.2如何实例化:
image.png

2.3常用方法:
image.png

3.Files工具类 —- JDK7提供
3.1作用:

操作文件或文件目录的工具类


3.2常用方法:
image.png
image.png