20 字节流、字符流、属性集

字节流、字符流、属性集

一、字节流

1. 字节输出流和文件字节输出流

  • java.io.OutputStream:字节输出流

    • 此抽象类是表示输出字节流的所有类的超类。
    • 一些子类共性的成员方法:
      • public void close():关闭此输出流并释放与此流相关联的任何系统资源。
      • public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
      • public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
      • public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
      • public abstract void write(int b):将指定的字节输出流。
  • java.io.FileOutputStream extends OutputStream

    • FileOutputStream:文件字节输出流。

    • 作用:把内存中的数据写入到硬盘的文件中。

    • 构造方法:

      • FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据到输出文件流。
      • FileOutputStream(File file):创建一个向指定File对象表示的文件中写入数据的文件输出流。
      • 参数:
        • String name:一个文件的路径。
        • File file:一个文件。
    • 构造方法的作用:

      • 创建一个FileOutputStream对象。
      • 会根据构造方法中传递的文件/文件路径,创建一个空的文件。
      • 会把FileOutputStream对象指向创建好的文件。

2. 字节输出流写入数据到文件

  • 写入数据的原理(内存 —> 硬盘):
    • java程序 —> JVM —> OS —> OS调用写数据的方法 —> 把数据写入到文件中
  • 字节输出流的使用步骤:
    • 创建一个FileOutputStream对象,构造方法中传递写入数据的目的地。
    • 调用FileOutputStream对象中的方法write,把数据写入到文件中。
    • 释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提高程序的效率)。
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt");
        fos.write(97);
        fos.close();
    }
}

3. 文件存储原理与记事本打开文件的原理

  • 写数据的时候,会将10进制的整数转换为2进制输入存入硬盘。

  • 任意的文本编辑器在打开文件的时候,把字节转换为字符表示。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rAnVj6do-1589461317122)(https://raw.githubusercontent.com/zhugulii/picBed/master/02_%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E7%9A%84%E5%8E%9F%E7%90%86%E5%92%8C%E8%AE%B0%E4%BA%8B%E6%9C%AC%E6%89%93%E5%BC%80%E6%96%87%E4%BB%B6%E7%9A%84%E5%8E%9F%E7%90%86.bmp)]

4. 字节输出流写多个字节的方法

  • public void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
    • 如果写的第一个字节是正数(0~127),那么显示的时候会查询ASCII表。
    • 如果写的第一个字节是负数,那么第一个字节会和第二个字节组成一个中文显示,查询系统默认码表(GBK)。
  • public void write(byte[] b, int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
    • int off:数组的开始索引。
    • int len:写入len个字节。
  • 写入字符的方法:可以使用String类中的方法把字符串转换为字节数组。
    • byte[] getBytes():把字符转换为字节数组。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File("/Users/zgl/Desktop/b.txt"));
        byte[] bytes1 = {97,98,99};
        byte[] bytes2 = {-97,98,-99};
        byte[] bytes3 = "你好".getBytes();
        fos.write(bytes1);
        fos.write(bytes2);
        fos.write(bytes3);
        fos.write(bytes1,1,1);
        fos.close();
    }
}

5. 字节输出流的续写和换行

  • 追加写/续写:使用两个参数的构造方法。

    • FileOutputStream(String name, boolean append):创建一个向具有指定name的文件写入数据的输出文件流。
    • FileOutputStream(File file, boolean append):创建一个向具有指定file的文件写入数据的输出文件流。
      • 参数:
        • String name、File name:写入数据的目的地。
        • boolean append:追加写开关。
          • true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据。
          • false:创建一个新文件,覆盖源文件。
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt",true);
            for (int i = 0; i < 5; i++) {
                fos.write("你好".getBytes());
            }
            fos.close();
        }
    }
    
  • 写换行:写换行符号

    • win:\r\n
    • Linux:\n
    • Mac: \r
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/a.txt",true);
            for (int i = 0; i < 5; i++) {
                fos.write("你好".getBytes());
                fos.write("\r".getBytes());
            }
            fos.close();
        }
    }
    

6. 字节输入流和文件字节输入流

  • java.io.InputStream:字节输入流。此抽象类是表示字节输入流的所有类的超类。
    • 一些子类共性的方法:
      • int read():从输入流中读取数据的下一个字节并返回,读取到文件的末尾返回-1。
      • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区的数组b中。
      • void close():关闭此输入流并释放与该流关联的所有系统资源。
  • java.io.FileInputStream extends InputStream
    • FileInputStream:文件字节输入流
    • 作用:把硬盘中的数据,读取到内存中使用。
    • 构造方法:
      • FileInputStream(String name)
      • FileInputStream(File file)
      • 参数:读取文件的数据源
        • String name:文件的路径
        • File file:文件
      • 构造方法的作用:
        • 会创建一个FileInputStream对象。
        • 会把FileInputStream对象指向构造方法中要读取的文件。

7. 字节输入流读取字节数据

  • 读取数据的原理(硬盘 —> 内存):
    • java程序 —> JVM —> OS —> OS读取数据的方法 —> 读取文件
  • 字节输入流的使用步骤:
    • 创建FileInputStream对象,构造方法中绑定要读取的数据源。
    • 使用FileInputStream对象中的方法read,读取文件。
    • 释放资源。
import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
        int tmp;
        while ((tmp = fis.read()) != -1) {
            System.out.print((char) tmp);   // abc
        }
        fis.close();
    }
}

8. 字节输入流一次读取多个字节

  • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储在缓冲区的数组b中。
    • 参数byte[] b,起到缓冲作用,存储每次读取到的多个字节。
    • 数组的长度一般定义为1024(1KB)或者1024的整数倍。
    • 返回值为每次读取到的有效字节个数。
  • String类的构造方法:
    • String(byte[] bytes):把字节数组转换为字符串。
    • String(byte[] bytes, int offset, int length):把字节数组的一部分转换为字符串,offset为数组的开始索引,length:转换的字节个数。
import java.io.FileInputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
        byte[] bytes = new byte[1024];
        int len;
        while ((len = fis.read(bytes)) != -1) {
            System.out.println(new String(bytes,0,len));  // abcdefgh
        }
        fis.close();
    }
}

9. 练习:文件复制

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        long s = System.currentTimeMillis();

        FileInputStream fis = new FileInputStream("/Users/zgl/Desktop/a.txt");
        FileOutputStream fos = new FileOutputStream("/Users/zgl/Desktop/b.txt");

        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes,0,len);
        }
        fis.close();
        fos.close();
        long e = System.currentTimeMillis();
        System.out.println("复制文件共用时:" + (e-s) + "毫秒!");
    }
}

二、字符流

1. 使用字节流读取中文的问题

  • 可能会出现乱码问题。
  • 1个中文字符:
    • GBK:占用两个字节。
    • UTF-8:占用三个字节。

2. 字符输入流、文件字符输入流

  • java.io.Reader:字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类。
  • 共性的成员方法:
    • int read():读取单个字符并返回。
    • int read(char[] cbuf):一次读取多个字符,将字符读入数组。
    • void close():关闭该流并释放与之关联的所有资源。
  • java.io.FileReader extends InputStream extends Reader
    • FileReader:文件字符输入流。
    • 作用:把硬盘文件中的数据以字符的方式读取到内存中。
    • 构造方法:
      • FileReader(String fileName)
      • FileReader(File file)
      • 参数:
        • String filename:文件的路径
        • File file:文件
      • FileReader:构造方法的作用:
        • 创建一个FileReader对象。
        • 会把FileReader对象指向要读取的文件。

3. 字符输入流读取字符数据

  • 使用步骤:
    • 创建FileReader对象,构造方法中绑定要读物的数据源。
    • 使用FileReader对象中的方法read读取文件。
    • 释放资源。
  • String类的构造方法:
    • String(char[] value):把字符数组转换为字符串。
    • String(char[] value, int offset, int count):把字符数组的一部分转换为字符串,offset为数组的开始索引,length:转换的符节个数。
import java.io.FileReader;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        
        FileReader fr = new FileReader("/Users/zgl/Desktop/a.txt");
        
        //使用read()
        /*int tmp1;
        while ((tmp1 = fr.read()) != -1) {
            System.out.print((char)tmp1);  // 你好,朱古力!
        }*/

        //使用read(char[] chars)
        int len;
        char[] chars = new char[1024];
        while ((len = fr.read(chars)) != -1) {
            System.out.println(new String(chars,0,len));  // 你好,朱古力!
        }

        fr.close();
    }
}

4. 字符输出流和文件字符输出流

  • java.io.Writer:字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类。
  • 共性的成员方法:
    • void write(int c):写入单个字符。
    • void write(char[] cbuf):写入字符数组。
    • void write(char[] cbuf, int off, int len):写入字符数组的某一部分,off为数组的开始索引,len为写的字符个数。
    • void write(String str):写入字符串。
    • void write(String str, int off, int len):写入字符串的某一部分,off为字符串的开始索引,len为写的字符个数。
    • void flush():刷新该流的缓冲。
    • void close():关闭此流,但要先刷新它。
  • java.io.FileWriter extends OutputStreamWriter extends Writer
  • FileWriter:文件字符输出流。
  • 作用:把内存中字符数据写入到文件中。
  • 构造方法:
    • FileWriter(File file):根据给定的file对象构造一个FileWriter对象。
    • FileWriter(String filename):根据给定的文件名构造一个FileWriter对象。
    • 参数:
      • String filename:文件的路径。
      • File file:文件。
    • 作用:
      • 会创建一个FileWriter对象。
      • 会根据构造方法中传递的文件/文件的路径,创建文件。
      • 会把FileWriter对象指向创建好的文件。

5. 字符输出流将单个字符写入文件

  • 使用步骤:

    • 创建FileWriter对象,构造方法中绑定要写入数据的目的地。
    • 使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)。
    • 使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中。
    • 释放资源(会先把内存缓冲区中的数据刷新到文件中)。
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            FileWriter fw = new FileWriter("/Users/zgl/Desktop/b.txt");
            fw.write(97);
            fw.flush();
            fw.close();
        }
    }
    

6. flush方法和close方法的区别

  • flush:刷新缓冲区,流对象可以继续使用。

  • close:先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用。

    import java.io.FileWriter;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            FileWriter fw = new FileWriter("/Users/zgl/Desktop/c.txt");
            fw.write(97);
            fw.flush();
            //可以继续使用流对象
            fw.write(98);
            fw.close();
            //抛出异常 IOException: Stream closed
            fw.write(99);
        }
    }
    

7. 字符输出流写数据的其他方法

  • void write(char[] cbuf):写入字符数组。

  • void write(char[] cbuf, int off, int len):写入字符数组的某一部分,off为数组的开始索引,len为写的字符个数。

  • void write(String str):写入字符串。

  • void write(String str, int off, int len):写入字符串的某一部分,off为字符串的开始索引,len为写的字符个数。

    import java.io.FileWriter;
    import java.io.IOException;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            FileWriter fw = new FileWriter("/Users/zgl/Desktop/d.txt");
            char[] chars = {'a','b','c'};
            fw.write(chars);  // abc
            fw.write(chars,1,2); // bc
    
            String str = "zhuguli";
            fw.write(str);  // zhuguli
            fw.write(str,3,4);  // guli
    
            fw.flush();
            fw.close();
        }
    }
    

8. 字符输出流的续写和换行

  • 追加写/续写:使用两个参数的构造方法。
    • FileWriter(String name, boolean append)
    • FileWriter(File file, boolean append)
      • 参数:
        • String name、File name:写入数据的目的地。
        • boolean append:追加写开关。
          • true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据。
          • false:创建一个新文件,覆盖源文件。
  • 写换行:写换行符号
    • win:\r\n
    • Linux:\n
    • Mac: \r
import java.io.FileWriter;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("/Users/zgl/Desktop/e.txt",true);
        for (int i = 0; i < 5; i++) {
            fw.write("你好");
        }
        for (int j = 0; j < 5; j++) {
            fw.write("你好" + "\r");
        }
        fw.flush();
        fw.close();
    }
}

9. JDK7 和 JDK9 流中异常的处理

  • JDK 7的新特性:

    • try后边可以增加一个(),在括号中可以定义流对象。

    • 这个流对象的作用域就在try中有效。

    • try中的代码执行完毕,会自动把流对象释放,不用写finally

    • 格式:

      try(定义流对象;定义流对象;...){
        可能会产生异常的代码
      }catch(异常类变量 变量名){
        异常处理逻辑
      }
      
  • JDK9 的新特性:

    • try的前边可以定义流对象。

    • try后边的()可以直接引入流对象的名称(变量名)。

    • try中的代码执行完毕,会自动把流对象释放,不用写finally

    • 格式:

      A a = new A();
      B b = new B();
      try(a,b){
        可能会产生异常的代码
      }catch(异常类变量 变量名){
        异常处理逻辑
      }
      

三、属性集

1. 使用Properties集合存储数据,遍历取出Properties集合中的数据

  • java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>

  • Properties类表示了一个持久的属性集,Properties可保存在流中或从流中加载。

  • Properties集合是唯一一个与 IO 流相结合的集合。

    • 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储。
    • 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用。
  • 属性列表中每个键及其对应值都是一个字符串。

    • Properties集合是一个双列集合,keyvalue默认都是字符串。
  • Properties集合有一些操作字符串特有的方法:

    • Object setProperty(String key, String value)调用Hashtable的方法put
    • String getProperty(String key)通过key找到value值,此方法相当于Map集合中的get(key)方法。
    • set<String> stringPropertyName()返回此属性列表中的键集。
    import java.util.Properties;
    import java.util.Set;
    
    public class Test {
        public static void main(String[] args) {
            Properties prop = new Properties();
            prop.setProperty("朱古力","18");
            prop.setProperty("猪猪侠","20");
            prop.setProperty("猪猪猪","22");
    
            Set<String> strings = prop.stringPropertyNames();
            for (String key : strings) {
                String value = prop.getProperty(key);
                System.out.println(key + "=" + value);
            }
        }
    }
    

2. Properties集合中的方法store

  • 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储。

  • void store(OutputStream out, String comments)

  • void store(Writer writer, String comments)

    • 参数:
      • OutputStream out:字节输出流,不能写入中文。
      • Writer writer:字符输出流,可以写中文。
      • String comment:注释,用来解释说明保存的文件是做什么用的。
        • 不能使用中文,会产生乱码,默认是Unicode编码
        • 一般使用""空字符串。
  • 使用步骤:

    • 创建Properties集合对象,添加数据。
    • 创建字节/字符输出流对象,构造方法中绑定要输出的目的地。
    • 使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储。
    • 释放资源。
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Properties;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            Properties prop = new Properties();
            prop.setProperty("朱古力","18");
            prop.setProperty("猪猪侠","20");
            prop.setProperty("猪猪猪","22");
    
            FileWriter fw = new FileWriter("/Users/zgl/Desktop/f.txt");
            prop.store(fw,"save");
            fw.close();
        }
    }
    

3. Properties集合中的方法load

  • 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用。

  • void load(InputStream inStream)

  • void load(Reader reader)

    • 参数:
      • InputStream inStream:字节输入流,不能读取含有中文的键值对。
      • Reader reader:字符输入流,能读取含有中文的键值对。
  • 使用步骤:

    • 创建Properties集合对象。
    • 使用Properties集合对象中的方法load读取保存键值对的文件。
    • 遍历Properties集合。
  • 注意:

    • 存储键值对的文件中,键与值默认的连接符号可以使用=空格、其他符号。
    • 存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取。
    • 存储键值对的文件中,键与值默认都是字符串,不用再加引号。
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.Properties;
    import java.util.Set;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            Properties prop = new Properties();
            FileReader fw = new FileReader("/Users/zgl/Desktop/f.txt");
            prop.load(fw);
    
            Set<String> keys = prop.stringPropertyNames();
            for (String key : keys) {
                String value = prop.getProperty(key);
                System.out.println(key + "=" + value);
            }
    
            fw.close();
        }
    }
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值