• 【从零开始的Java开发】1-6-4 Java输入输出流:File类、绝对路径和相对路径、字节流、缓冲流、字符流、对象序列化


    概述

    流就是指一连串流动的字符,以先进先出的方式发送信息的通道。

    文件输入——读
    文件输出——写

    File类

    文件:可认为是相关记录或放在一起的数据的集合。

    在Java中,使用java.io.File类对文件进行操作。

    File类:
    在这里插入图片描述
    构造方法:
    在这里插入图片描述
    常用方法

    是否可读或可写:canRead()canWrite()
    在这里插入图片描述
    文件是否存在:exists()
    在这里插入图片描述
    获取文件或路径的名称:getName()
    在这里插入图片描述
    是否是目录或文件:isDirectory()isFile()——若文件不存在,false
    在这里插入图片描述
    是否是隐藏文件:isHidden()
    在这里插入图片描述
    返回文件的最后一次修改时间:lastModified()
    在这里插入图片描述
    创建目录/创建多级目录:mkdir()/mkdirs()
    在这里插入图片描述

    File类的常用方法

    我在C盘有一个文件夹temp,里面有一个txt文件名为score。
    则它在Windows下的路径为:c:\\temp\\score.txt。(一个\是转义字符)

    代码1

    • 构造函数
    • isFile()isDirectory()
    public class FileDemo {
    
    	public static void main(String[] args) {
    		// 创建File对象
    		File file = new File("c:\\temp\\score.txt");
    
    		// 判断是否文件or目录
    		boolean flag1 = file.isFile();
    		boolean flag2 = file.isDirectory();
    
    		System.out.println("是否是文件:" + flag1);
    		System.out.println("是否是目录:" + flag2);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    输出:

    是否是文件:true
    是否是目录:false
    
    • 1
    • 2

    也可以这样:

    File file=new File("c:\\temp","score.txt");
    
    • 1

    File file1=new File("c:\\temp");
    File file=new File(file1,"score.txt");
    
    • 1
    • 2

    代码2

    • exists():判断文件是否存在
    • mkdir():创建文件目录
    // 创建一个目录
    File file2 = new File("c:\\temp", "HashSet");
    // 判断这个文件是否存在
    if (!file2.exists()) {
    	file2.mkdir();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行后:
    在这里插入图片描述
    如果想创建多级目录:(先把HashSet删掉)

    // 创建多级目录
    File file2 = new File("c:\\temp\\tempp\\HashSet", "HashSet");
    // 判断这个文件是否存在
    if (!file2.exists()) {
    	file2.mkdirs();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行后:
    在这里插入图片描述
    代码3
    创建文件:

    • createNewFile():创建文件
    // 创建文件
    File file = new File("c:\\temp\\score1.txt");
    if (!file.exists()) {
    	try {
    		file.createNewFile();
    	} catch (IOException e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行:
    在这里插入图片描述
    ps:若代码3中参数路径为:"c:\\temp\\score1",则会创建一个没有拓展名的文件。

    绝对路径和相对路径

    • 绝对路径:从盘符开始的路径
    • 相对路径:从当前路径开始的路径

    假设这是当前位置:
    在这里插入图片描述
    它的绝对路径是:c:\\temp\\tempp\\1.txt
    因为现在就在tempp这个文件夹下,所以1.txt的相对目录是:1.txt

    tempp的上级目录如下:
    在这里插入图片描述
    想在以temp为当前位置的位置找到1.txt,相对路径为:tempp\\1.txt
    访问上一层目录的方法:..\\
    访问上两层:..\\..\\

    在Eclipse下
    执行代码:

    //创建文件
    File f=new File("temp.txt");
    try {
    	f.createNewFile();
    } catch (IOException e) {
    	// TODO Auto-generated catch block
    	e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    会在工程目录下出现一个temp.txt

    在这里插入图片描述
    判断一个路径是绝对路径还是相对路径isAbsolute():若是绝对路径,则返回true

    获取路径

    • getPah():获得File构造方法参数表示的路径,也就是内容与File构造方法参数一致
    • getAbsolutePath():获取绝对路径

    代码:

    File f=new File("temp.txt");
    try {
    	f.createNewFile();
    	//是否绝对路径
    	System.out.println(f.isAbsolute());
    	//获取相对路径
    	System.out.println(f.getPath());
    	//获取绝对路径
    	System.out.println(f.getAbsolutePath());
    	//获取文件名
    	System.out.println(f.getName());
    } catch (IOException e) {
    	// TODO Auto-generated catch block
    	e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    输出:

    false
    temp.txt
    D:\eclipse\allProj\temp.txt
    temp.txt
    
    • 1
    • 2
    • 3
    • 4

    字节流概述

    • 字节输入流InputStream
    • 字节输出流OutputStream

    字节输入流InputStream包括:

    • 文件输入流FileInputStream
    • 管道输入流PipedInputStream
    • 过滤器输入流FilterInputStream
    • 对象输入流ObjectInputStream
    • 顺序输入流SequenceInputStream
    • 字节数组输入流ByteArrayInputStream
    • 缓冲字符输入流StringBufferInputStream

    过滤器输入流FilterInputStream包括:

    • 回压输入流PushbackInputStream
    • 缓冲输入流BufferedInputStream
    • 数据输入流DataInputStream

    字节输出流OutputStream包括:

    • 文件输出流FileOutputStream
    • 管道输出流PipedOutputStream
    • 过滤器输出流FilterOutputStream
    • 对象输出流ObjectOutputStream
    • 字节数组输出流ByteArrayOutputStream

    过滤器输出流FilterOutputStream包括:

    • 格式化输出流PrintStream
    • 缓冲输出流BufferedOutputStream
    • 数据输出流DataOutputStream

    文件输入流 FileInputStream

    • 从文件系统中的某个文件中获取输入字节
    • 用于读取诸如图像数据之类的原始字节流

    文档如下:
    在这里插入图片描述

    构造方法
    在这里插入图片描述
    重要方法

    方法名描述
    public int read()从输入流中读取一个数据字节
    public int read(byte[] b)从输入流中将最多b.length个字节的数据读入一个byte数组中
    public int read(byte[] b,int off,int len)从输入流中将最多len个字节的数据读入一个byte数组中
    public int close()关闭此文件输入流并释放与此流有关的所有系统资源

    若返回值为-1,则表达已经达到文件末尾。

    代码演示

    我们在工程目录下有一个temp.txt文件:我们想要读取它。
    在这里插入图片描述

    代码(无参的read()):

    public static void main(String[] args) {
    
    		try {
    			// 创建一个FileInputStream对象:要捕获FileNotFoundException异常
    			FileInputStream fis = new FileInputStream("temp.txt");
    
    			// 读取文件内容read:要捕获IOException异常
    			int n;
    			while ((n = fis.read()) != -1) {
    				System.out.print((char) n);
    			}
    			fis.close();// 关闭输入流,释放资源
    		} catch (FileNotFoundException e) {		
    			e.printStackTrace();
    		} catch (IOException e) {// IOException是FileNotFoundException的父类			
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    输出:asd123345

    核心代码:

    int n;
    while ((n = fis.read()) != -1) {
    	System.out.print((char) n);
    }
    
    • 1
    • 2
    • 3
    • 4

    也可以是这样(但是重复了):

    int n = fis.read();
    while (n != -1) {
    	System.out.print((char) n);
    	n = fis.read();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    int read(byte[] b)的代码——把核心代码替换成:

    //读取数据,存放到一个byte类型的数组中
    byte[] b=new byte[100];
    fis.read(b);
    System.out.println(new String(b));
    fis.close();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出:asd123345

    若把fis.read(b);改成fis.read(b,0,6);,则输出:asd123
    第二个参数表示偏移量:从byte数组的第几个开始存数据。
    第三个参数表示要读取的字符个数

    若第二个参数改为1,则输出: asd123,前面空了一格。

    文件输出流 FileOutputStream

    用来将数据写入到文件中。

    构造方法:
    在这里插入图片描述
    重要方法

    方法名描述
    public void write(int b)将指定字节写入文件输出流
    public void write(byte[] b)将b.length个字节从byte数组写入文件输出流
    public void write(byte[] b,int off,int len)将指定byte数组中从偏移量off开始的len个字节写入文件输出流
    public void close()关闭此文件输出流并释放与此流有关的所有系统资源

    代码:

    public class FileOutputDemo {
    
    	public static void main(String[] args) {
    		FileOutputStream fos;
    		FileInputStream fis;
    		try {
    			fos = new FileOutputStream("temp.txt");
    			fis = new FileInputStream("temp.txt");
    			//写入文件
    			fos.write(51);
    			fos.write('a');
    			//读取写入的文件
    			System.out.print(fis.read());
    			System.out.print((char) fis.read());
    			fis.close();
    			fos.close();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出:51a
    文件:因为编码原因,显示会不一样,但由输出我们可以知道写入的就是我们想要的51a
    在这里插入图片描述
    如果把fos = new FileOutputStream("temp.txt");改成fos = new FileOutputStream("temp.txt",true);,再运行一次,则文件内容为:3a3a

    原因:

    FileOutputStream(File file, boolean append)
    Creates a file output stream to write to the file represented by the specified File object.

    由上述例子可知,文件输入输出流是不太适合做和字符相关的工作的。

    我们再来看一个文件拷贝的例子。我们在工程目录下有一个jpg文件a,我们想把它拷贝到a_copy上。

    复制粘贴其实就是读取和写入。
    代码:

    public static void main(String[] args) {
    
    		try {
    			// 文件拷贝
    			FileInputStream fis = new FileInputStream("a.jpg");
    			FileOutputStream fos = new FileOutputStream("a_copy.jpg");
    			int n = 0;// 存储read方法的返回值
    			byte[] b = new byte[1024];//一次读1024个字节
    			while ((n = fis.read(b)) != -1) {
    				fos.write(b);
    			}
    			fis.close();
    			fos.close();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行后:
    在这里插入图片描述
    注意:fos.write(b,0,n);可以保证拷贝后的文件大小一致——因为副本文件可能比原来的文件大,这是由一次拷贝b个字节造成的(剩下的文件字节小于b个时,就会使得拷贝后的文件大一点)

    缓冲流概述

    • 缓冲输入流:BufferedInputStream
    • 缓冲输出流:BufferedOutputStream

    缓冲输入流相关方法:
    在这里插入图片描述

    缓冲输出流相关方法:
    在这里插入图片描述

    缓冲区满了会自动触发write()方法。

    案例:缓冲输入输出流

    • flush():清空缓冲区数据,使之触发write()方法

    代码(注释很详细):

    public class BufferedDemo1 {
    
    	public static void main(String[] args) {
    		try {
    			FileOutputStream fos = new FileOutputStream("temp.txt");
    			BufferedOutputStream bos = new BufferedOutputStream(fos);
    			FileInputStream fis = new FileInputStream("temp.txt");
    			BufferedInputStream bis = new BufferedInputStream(fis);
    
    			// 写
    			bos.write(50);
    			bos.write('a');
    
    			// 运行,发现temp.txt是空的,说明数据还在缓冲区里
    			// 缓冲区未满,没有触发自动write操作
    
    			// 强制清空,会触发写操作
    			bos.flush();
    
    			// 运行后,temp.txt就有2a了
    
    			// 读取
    			System.out.println(bis.read());
    			System.out.println((char) bis.read());
    			// 实际上,关闭缓冲区也会触发写操作
    			bos.close();
    
    			// 关闭所有流
    			bis.close();
    			fis.close();
    			fos.close();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    文件内容:2a
    输出:

    50
    a
    
    • 1
    • 2

    字符流概述

    • 字符输入流Reader
    • 字符输出流Writer

    字符输入流:
    在这里插入图片描述
    字符输出流:
    在这里插入图片描述

    案例:字节字符转换流

    • InputStreamReader
    • OutputStreamReader

    相关方法:
    在这里插入图片描述

    在这里插入图片描述
    代码演示:

    输入流:我们想读取文件如下:
    在这里插入图片描述
    代码:两个方法都可以

    public static void main(String[] args) {
    		try {
    			FileInputStream fis = new FileInputStream("temp.txt");
    			InputStreamReader isr = new InputStreamReader(fis);
    
    			// 读取数据
    			// 方法1
    			int n = 0;
    			char[] c = new char[10];
    			while ((n = isr.read()) != -1) {
    				System.out.print((char) n);
    			}
    
    			// 方法2
    			int n1 = 0;
    			while ((n1 = isr.read(c)) != -1) {
    				String str = new String(c, 0, n1);// n1表示要转换实际存储的字符数量
    				System.out.print(str);
    			}
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出:

    123
    asdzxc
    fgh
    
    • 1
    • 2
    • 3

    输出流:
    我们想把temp.txt的内容读出来,然后写到tempp.txt中。

    代码:

    public class ReaderDemo {
    
    	public static void main(String[] args) {
    		try {
    			FileInputStream fis = new FileInputStream("temp.txt");
    			InputStreamReader isr = new InputStreamReader(fis);
    			FileOutputStream fos = new FileOutputStream("tempp.txt");
    			OutputStreamWriter osw = new OutputStreamWriter(fos);
    
    			// 读取数据
    			char[] c = new char[10];
    			int n1 = 0;
    			while ((n1 = isr.read(c)) != -1) {
    				// 写字符串
    				String str = new String(c, 0, n1);// n1表示要转换实际存储的字符数量
    				osw.write(str);
    
    				// 或者写字符数组
    				// osw.write(c,0,n1);
    			}
    
    			// 清空缓存
    			osw.flush();
    
    			// 关闭流
    			fis.close();
    			fos.close();
    			isr.close();
    			osw.close();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    运行后:
    在这里插入图片描述
    关于编码:输入输出的编码要相同,不然会乱码。

    构造函数中,String charsetName是字符集,在这里可以写想要的编码形式,如"GBK""UTF-8"

    InputStreamReader(InputStream in, String charsetName)
    Creates an InputStreamReader that uses the named charset.

    OutputStreamWriter(OutputStream out, String charsetName)
    Creates an OutputStreamWriter that uses the named charset.

    其他字符流

    代码:

    public static void main(String[] args) {
    		try {
    			FileInputStream fis = new FileInputStream("temp.txt");
    			InputStreamReader isr = new InputStreamReader(fis, "GBK");
    			BufferedReader br = new BufferedReader(isr);
    			FileOutputStream fos = new FileOutputStream("tempp.txt");
    			OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
    			BufferedWriter bw = new BufferedWriter(osw);
    
    			// 读取数据
    			char[] c = new char[10];
    			int n1 = 0;
    			while ((n1 = br.read(c)) != -1) {
    				// 写字符串
    //				String str = new String(c, 0, n1);// n1表示要转换实际存储的字符数量
    //				bw.write(str);
    
    				// 或者写字符数组
    				bw.write(c, 0, n1);
    			}
    
    			// 清空缓存
    			bw.flush();
    
    			// 关闭流
    			fis.close();
    			fos.close();
    			isr.close();
    			osw.close();
    			br.close();
    			bw.close();
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行后:
    在这里插入图片描述

    对象序列化

    序列化:把Java对象转换为字节序列的过程。——写
    反序列化:把字节序列恢复为Java序列的过程。——读

    步骤:

    • 创建一个类,继承Serializable接口
    • 创建对象
    • 将对象写入文件
    • 从文件读取对象信息

    相关类:

    • 对象输入流:ObjectInputStream
    • 对象输出流:ObjectOutputStream

    需求:把Goods类的对象写入文件temp.txt中,然后再读取出来。

    代码:
    Goods类:

    public class Goods implements Serializable {
    	private String GoodsId;
    	private String GoodsName;
    	private double price;
    
    	public Goods(String goodsId, String goodsName, double price) {
    		GoodsId = goodsId;
    		GoodsName = goodsName;
    		this.price = price;
    	}
    
    	public String getGoodsId() {
    		return GoodsId;
    	}
    
    	public void setGoodsId(String goodsId) {
    		GoodsId = goodsId;
    	}
    
    	public String getGoodsName() {
    		return GoodsName;
    	}
    
    	public void setGoodsName(String goodsName) {
    		GoodsName = goodsName;
    	}
    
    	public double getPrice() {
    		return price;
    	}
    
    	public void setPrice(double price) {
    		this.price = price;
    	}
    
    	@Override
    	public String toString() {
    		return "Goods [GoodsId=" + GoodsId + ", GoodsName=" + GoodsName + ", price=" + price + "]";
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    测试类:

    public class GoodsTest {
    
    	public static void main(String[] args) {
    		// 定义一个Goods对象
    		Goods goods1 = new Goods("1", "电脑", 3000);
    
    		// 定义输入输出流
    		try {
    			FileOutputStream fos = new FileOutputStream("temp.txt");
    			ObjectOutputStream oos = new ObjectOutputStream(fos);
    			oos.writeObject(goods1);
    			oos.flush();
    
    			// 关闭流
    			oos.close();
    			fos.close();
    
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    运行后:
    在这里插入图片描述
    文件乱码,于是我们把它读取试试。

    代码:

    // 读取文件
    FileInputStream fis = new FileInputStream("temp.txt");
    ObjectInputStream ois = new ObjectInputStream(fis);
    try {
    	Goods goods = (Goods) ois.readObject();
    	System.out.println(goods);
    } catch (ClassNotFoundException e) {
    	e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出:Goods [GoodsId=1, GoodsName=电脑, price=3000.0]

  • 相关阅读:
    第 372 场 LeetCode 周赛题解
    服务器相关
    Vue Chrome浏览器手动调节模拟网速
    CEAC 之《企业信息化管理》1
    C 语言 时间函数使用技巧(汇总)
    蓝桥杯打卡Day9
    Kafka为什么是高性能高并发高可用架构
    电源模块频率测试有哪些方法?纳米软件分享
    vue中关于重置表单数据出现undefined的问题
    uImage的制作工具mkimage详解(源码编译、使用方法、添加的头解析、uImage的制作)
  • 原文地址:https://blog.csdn.net/karshey/article/details/126249310