File和流二

一、File基本知识点

1. File
	构造方法:
		File(String pathname)
		File(String parent, String child)
		File(File parent, String child)
	相对路径和绝对路径
	成员方法:
		创建功能
			createNewFile()
			mkdir()
			mkdirs()
		删除功能
			delete()
				1. 不走回收站 2. 只能删除空文件夹
		判断功能
			exists()
			isFile()
			isDirectory()
		获取功能
			getAbsolutePath()
			getPath()
			getName()
			length() : 获取文件的字节个数, 不能获取文件夹(数据有问题)
2. 递归
	概述: 方法自己调用自己
	注意事项: 1. 必须有出口 2. 就算有出口次数不能过多
	
	递归求阶乘:
        public void fun(int n) {
            if (n == 1) {
                return 1;
            }

            return n * fun(n - 1);
        }
        
3. 字节输入流
	FileInputStream
	构造方法:
		FileInputStream(File file)
		FileInputStream(String name)
		输入流关联的文件如果不存在, 会报错
		
	成员方法:
		read() : 读取一个字节
			如果读取到末尾, 返回-1
		read(byte[] arr) : 将自己读取到字节数组中
			返回读取到有效的字节个数
			如果读取到末尾, 返回-1
4. 字节输出流
	FileOutputStream
		构造方法:
        	FileOutputStream(File file)
			FileOutputStream(String name)
			输出流关联的文件不存在, 会创建
			
		成员方法:
			write(int ) : 写出一个字节
			writer(byte[] arr, int off, int len)
				写出arr字节数组中, 从off索引开始的len个字节
				
	
5. 字符流
	字符流的应用场景:
		字符流可以拷贝纯文本文件, 但是也不用, 因为会使用字节流进行拷贝. 
		如果只读取纯文本文件可以使用字符流
		如果值写出纯文本文件可以使用字符流
		
	Writer: 有一个长度为1024的字符数组(缓冲区)
		
	close()和flush()
		close() : 关流, 但是在关流之前会刷出一次缓冲区
		flush() : 刷出一次缓冲区

关于文件删除说明

java.io.File里的delete操作很实用也很常用,可以用来删除单独的文件和某一目录。但有时候会出现delete失败的情况,出现这种情况的原因一般有以下几种:

1、删除时还有其他程序在使用该文件,此时将无法正确删除

2、没有close关闭和该文件相关的所有输入输出流等,导致无法删除(这一点是最容易忘记的,你犯的可能就是这一条)

3、当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败。这里可以采用listFiles对目录下的文件或者目录进行处理。

下面给出一个具体的例子:

File f = new File(path);

DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));

if (f.exists()) {

System.out.println(f.getAbsoluteFile());

if (!f.delete()) {

System.out.println("请关闭使用该文件的所有进程或者流!!");

} else {

System.out.println(f.getName()+" 成功被删除!");

}

}

此时f是无法delete的,即f.delete()将返回false,原因就在于没有关闭dos.所以需要在if之前加入一句f.close(),这样就可以删除成功了。

File f = new File(path);

DataOutputStream dos = new DataOutputStream(new FileOutputStream(f));

if (f.exists()) {

System.out.println(f.getAbsoluteFile());

if (!f.delete()) {

System.out.println("请关闭使用该文件的所有进程或者流!!");

} else {

System.out.println(f.getName()+" 成功被删除!");

}

}

二. 属性集

  • Properties

1. 构造方法

public Properties()

2. 成员方法

  • 作为双列集合的使用
public Object setProperty(String key, String value) 
    	添加键值对
    
public String getProperty(String key)
    	根据键获取值
public class Demo01 {
    public static void main(String[] args) {

        // 创建了一个属性集的对象(双列集合)
        // Properties的键和值有默认的数据类型 : String
        Properties p = new Properties();

        // 添加
        p.setProperty("username", "zhangsan");
        p.setProperty("password", "123");

        p.setProperty("password", "456");

        // 获取
        String username = p.getProperty("username");
        System.out.println(username);

        System.out.println(p);

    }
}
  • 作为配置文件使用
public void load(InputStream inStream)
    : 加载 -> 从输入流中读取属性列表(键和元素对)。
    : 从输入流关联的配置文件中获取键值对信息
public void store(OutputStream out,
                  String comments) // 注释
	: 将此 Properties 表中的属性列表(键和元素对)写入输出流
    : 将此 Properties中的键值对, 写到配置文件中
public class Demo03 {
    public static void main(String[] args) throws IOException {

        Properties p = new Properties();

        // 输入流关联配置文件
        FileInputStream fis = new FileInputStream("day13-code\\aaa.properties");

        // 加载
        p.load(fis);

        fis.close();

        String username = p.getProperty("username");
        String password = p.getProperty("password");
        System.out.println(username + "---" + password);

    }
}

三. 缓冲流

缓冲区 : 数组

1. 字节流

缓冲流的输入输出流:

  • 带缓冲区的字节输入流 : BufferedInputStream
  • 带缓冲区的字节输出流 : BufferedOutputStream

构造方法

public BufferedInputStream(InputStream in)
    
public BufferedOutputStream(OutputStream out)

带缓冲的流一定要进行刷新操作,不然可能会导致其最终效果不符合实际情况

2. 字符流

带缓冲区的字符输入流

  • BufferedReader

构造方法

public BufferedReader(Reader in)

成员方法

public String readLine()
			: 读取一行, 一行的结束是以换行符为结束标记(没有获取到换行符)
                如果读取到文件的末尾, 返回null

带缓冲区的字符输出流

  • BufferedWriter

构造方法

public BufferedWriter(Writer out)

成员方法

public void newLine() : 写出跨平台的换行符

缓冲流的基本拷贝

public class Demo01 {
    public static void main(String[] args) throws IOException {
        /*FileInputStream fis = new FileInputStream("day13-code\\aaa.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);*/


        // 创建带缓冲区的字节输入流(高效字节输入流)
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day13-code\\test.mp4"));
        // 创建带缓冲区的字节输出流(高效字节输出流)
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day13-code\\copyTest.mp4"));

        int b;
        while ((b = bis.read()) != -1) {
            bos.write(b);
        }

        bos.close();
        bis.close();

    }
}

读取一行

public class Demo02 {
    public static void main(String[] args) throws IOException {

        // 创建高效字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("day13-code\\aaa.txt"));

        // 读取一行
        String line = br.readLine();

        System.out.println(line);
        // 关流
        br.close();
    }
}

写出换行

public class Demo03 {
    public static void main(String[] args)  throws IOException {
        // write once run anywhere

        BufferedWriter bw = new BufferedWriter(new FileWriter("day13-code\\bbb.txt"));

        bw.write("天将降大任于斯人也");
        bw.newLine();
        bw.write("必现苦其心志");
        bw.newLine();
        bw.write("劳其筋骨");
        bw.newLine();
        bw.write("饿其体肤");
        bw.newLine();
        bw.write("空乏其身");
        bw.newLine();
        bw.write("行拂乱其所为");
        bw.newLine();
        bw.write("所以动心忍性");
        bw.newLine();
        bw.write("增益其所不能");

        bw.close();

    }
}

一行一行的拷贝

public class Demo04 {
    public static void main(String[] args) throws IOException {
        // 创建输入输出流对象
        BufferedReader br = new BufferedReader(new FileReader("day13-code\\bbb.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("day13-code\\copyBbb.txt"));

        String line;

        // 不断的读取
        while ((line = br.readLine()) != null) {
            // 写出读取到的一行
            bw.write(line);
            // 换行
            bw.newLine();
        }

        // 关流
        bw.close();
        br.close();

    }
}

四. 转换流

转换流 --- 字符流

1. 输入流

  • InputStreamReader
    • 是字节流通向字符流的桥梁, 可以通过指定的字符集, 将字节转换成字符

构造方法

public InputStreamReader(InputStream in, String charsetName)
    charsetName: 字符集的名字
        
public InputStreamReader(InputStream in) : 使用默认字符集, 将字节转换成字符

2. 输出流

  • OutputSreamWriter
    • 是字符流通向字节流的桥梁, 可以通过指定的字符集, 将字符转换成字节

构造方法

public OutputStreamWriter(OutputStream out,                          String charsetName)public OutputStreamWriter(OutputStream out) : 使用默认字符集, 将字符转换成字节

转换流拷贝不同字符集的文件

public class Demo02 {
    public static void main(String[] args) throws IOException {
        // 创建转换流的输入流对象, 指定字符集(gbk)
        InputStreamReader isr = new InputStreamReader(new FileInputStream("g:\\gbk.txt"), "gbk");

        // 创建转换流的输出流对象, 指定字符集(utf-8)
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day13-code\\utf-8.txt"), "utf-8");

        int c;
        while ((c = isr.read()) != -1) {
            osw.write(c);
        }

        osw.close();
        isr.close();
    }
}

3. 转换流的其他应用场景

  • 只能获取到字节流, 想要读取文件中的一行
    • 字节流: FileInputStream
    • 读取一行: BufferedReader
public class Demo03 {
    public static void main(String[] args) throws IOException {
        // 只有字节流
        FileInputStream fis = new FileInputStream("day13-code\\aaa.txt");

        // 将字节流转换成BufferedReader字符流  ->  字节流通向字符流的桥梁 -> InputStreamReader
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));

        System.out.println(br.readLine());

        br.close();
    }
}
  • 自己完成键盘录入(不使用Scanner)
public class Demo04 {    public static void main(String[] args) throws IOException {        // BufferedReader       InputStreamReader          System.in(InputStream)        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        // 读取一行        String s = br.readLine();        System.out.println("获取到的字符串是: " + s);        br.close();    }}

4. 打印流

public class Demo01 {
    public static void main(String[] args) throws IOException {
        // System.out : 标准的输出流 -> 默认指向控制台
        // System.in : 标准的输入流  -> 默认指向控制台
        // System.err:  标准错误输出流  -> 指向控制台, 打印出来的内容是红色的
        Scanner sc = new Scanner(System.in);

		// 打印是红色的
        System.err.println("魑魅魍魉");

        // 会打印到控制台
        System.out.println("abc");

        PrintStream ps = new PrintStream("day13-code\\ccc.txt");
        // 修改打印流
        System.setOut(ps);

        // 这个会打印到ccc.txt中
        System.out.println("abc");

        ps.close();

    }
}

五. 序列化流

是字节流

1. 输入流

  • ObjectInputStream : 反序列化
  • 对象输入流

构造方法

public ObjectInputStream(InputStream in)

成员方法

public final Object readObject()

2. 输出流

  • ObjectOutputStream: 序列化
  • 对象输出流

构造方法

public ObjectOutputStream(OutputStream out)

成员方法

public final void writeObject(Object obj)

String类型的序列化和反序列化

public class Demo01_String {
    public static void main(String[] args) throws IOException {

        String s = "哈哈哈";

        // 创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day13-code\\object.txt"));

        oos.writeObject(s);

        oos.close();

    }
}

// ==================================================================================
public class Demo02_String {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 创建对象输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day13-code\\object.txt"));

        // 读取
        String s = (String) ois.readObject();

        System.out.println(s);

        ois.close();
    }
}

自定义类型的序列化和反序列化

public class Demo03_Person {
    public static void main(String[] args) throws IOException {

        // 创建Person对象
        Person p = new Person("高圆圆", 35);
        // 创建对象输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day13-code\\object.txt"));

        // NotSerializableException : 需要实现Serializable接口, 但是没实现
        // StreamCorruptedException : 不小心修改了写出硬盘上的文件
        // 写出
        oos.writeObject(p);

        oos.close();
    }
}
// ====================================================================================
public class Demo04_Person {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        // 创建对象输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day13-code\\object.txt"));
        // ClassNotFoundException : 编译时异常, 未雨绸缪
        //      找不到Xxx.class字节码文件
        // 读取
        Person p = (Person) ois.readObject();
        System.out.println(p);
        ois.close();

    }
}

了解即可

  1. 序列化和反序列化操作的时候, 需要使用到对象的字节码文件(Xxx.class)
  2. transient修饰的内容可以不被序列化

六. 装饰设计模式

目标: 在不改变原有类中内容的前提下, 对类中的功能进行增强

完成这个目标的操作方式:

1. 装饰设计模式
2. 继承, 重写
3. 动态代理
posted @ 2022-03-01 17:36  写的代码很烂  阅读(74)  评论(0编辑  收藏  举报