【Java SE进阶】Day09 字节流、字符流、I/O操作、属性集
一、I/O概述
1、输入输出
- 输入:硬盘-->内存
- 输出:内存-->内存
2、流
- 字节流:一个字节等于8位
- 字符流:一个字符=2个字节
二、字节流
1、概述
- 以字节的方式读取/传输
- 可以读取任意文件
2、字节输出流
- OutputStream
- 抽象类,是所有字节输出类的超类
- 方法:
- close()
- flush() :刷新并写出
- write(byte[] b)
- write(byte[] b, int off, int len)
- write(int b) :写入指定的字节,如97
- 构造方法传递文件路径的两种形式
- 常见子类:
- FileOutputStream
- ObjectOutputStream
- ……
- 输出一个字节
public class Demo01OutputStream { //字节输出流写入数据到文件【内存->硬盘】 public static void main(String[] args) throws IOException { //声明异常,所有异常都是io包下的, // 只需要声明所有io异常的父类IOException FileOutputStream fos =new FileOutputStream("src\\com\\liujinhui\\Day1105Stream\\a.txt");//抛出异常,声明 fos.write(97);//写一个字节到文件中 fos.close();//关闭此流并释放与流相关的所有资源 } }
- 输出多个字节
public class Demo02FileOutputStream { public static void main(String[] args) throws IOException { //创建FileOutputStream对象,将数据目的地传入 FileOutputStream fos=new FileOutputStream(new File("src\\com\\liujinhui\\Day1105Stream\\b.txt")); //对象调用方法write,把数据写入到文件中 //想往文件中写100 fos.write(49); fos.write(48); fos.write(48); /* * void write(byte[] b) 将 b.length 个字节从指定 byte 数组写入此文件输出流中。 一次写多个字节: 如果写的第一个字节是正数(0-127),显示的时候会查询ASCII码表 如果写的第一个字节是负数,那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询默认码表(GBK) * */ //byte[] bytes={65,66,67,68,69};//ABCDE byte[] bytes={65,66,67,68,69}; fos.write(bytes); /* void write(byte[] b, int off, int len) :把字节数组的一部分写入到文件中 将指定 byte 数组中从偏移量 off 【数组的开始索引】开始的 len 个字节写入此文件输出流。 */ fos.write(bytes,1,2); //写入字符串的方法 /* * 可以使用String类中的方法,把字符串转化为字符数组 * byte[] getBytes(Charset charset) 使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。 * */ byte[] bytes2="你好".getBytes();//[-28, -67, -96, -27, -91, -67] //使用的UTF-8,三个字节是一个中文 //GBK两个字节是一个中文 System.out.println(Arrays.toString(bytes2)); fos.write(bytes2); fos.close(); } }
- 文件追加&续写
package com.liujinhui.Day1105Stream; import java.io.FileOutputStream; import java.io.IOException; /* * 追加写/续写:使用FileOutputStream的两个参数的构造方法 *FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。 参数1:写入数据的目的地 参数2:追加写开关,true就追加写数据,false就创建新文件,覆盖原来的文件,重新写数据 写换行:写换行符号 windows:\r\n linux :/n mac:/r * */ public class Demo03Append { public static void main(String[] args) throws IOException { FileOutputStream fos=new FileOutputStream("src\\com\\liujinhui\\Day1105Stream\\c.txt",true); for (int i=0;i<10;i++){ fos.write("你好".getBytes()); fos.write("\r\n".getBytes()); } fos.close(); } }
3、字节输入流
- InputStream,所有字节输入流的父类
- 常见子类
- read() :读一个字节,读取到文件末尾时读取完毕
- read(byte[] b)
- read(byte[] b, int off, int len)
while ((len=fis.read())!=-1){ System.out.print(len); System.out.println(len); System.out.print((char)len);//转换为对应字符 }
- 读取多个字节
package com.liujinhui.Day1105Stream; import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; /* 字节输入流一次读取多个字节的方法: * int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 int read(byte[] b, int off, int len) 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。 明确: 1.方法参数byte[] b的作用 2.方法的返回值int是什么 String类的构造方法: String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String String(byte[] bytes, int offset, int length) 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。 * */ public class Demo06MultiBitReadFileInput { public static void main(String[] args) throws IOException { //创建FileInputStream对象,构造方法中绑定要读取的数据源 FileInputStream fis=new FileInputStream("src\\com\\liujinhui\\Day1105Stream\\a.txt"); //使用read读取文件 byte[] bytes=new byte[2]; int len=fis.read(bytes); System.out.println(len); System.out.println(Arrays.toString(bytes));//Arrays的toString方法 System.out.println(new String(bytes));//String的构造 ab len=fis.read(bytes);//2 System.out.println(len);//读取的字节的个数 System.out.println(new String(bytes));//String的构造 ih len=fis.read(bytes);//-1 System.out.println(len);//读取的字节的个数 System.out.println(new String(bytes));//String的构造 ih //释放资源 fis.close(); } }
- 优化:
package com.liujinhui.Day1105Stream; import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; public class Demo06MultiBitReadFileInput { public static void main(String[] args) throws IOException { //创建FileInputStream对象,构造方法中绑定要读取的数据源 FileInputStream fis=new FileInputStream("src\\com\\liujinhui\\Day1105Stream\\a.txt"); //使用read读取文件 byte[] bytes=new byte[1024]; int len=0;//记录每次读取的有效字节个数 //读取事一个重复的过程,可以使用循环优化 /* * 不知道文件中有多少字节,所以使用while循环 * while循环结束的条件:读取到-1结束 * */ while((len=fis.read(bytes))!=-1){ System.out.println(new String(bytes,0,8));//读取从0开始的7个有效字符串 //使用1个参数的String构造方法,如果一次读取的byte数组初始化过长,会产生很多空格 } //释放资源 fis.close(); } }
- 练习:从A文件将内容读入,并写出到B文件 中
package com.liujinhui.Day1105Stream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* * 文件复制练习:一读一写 * 明确: * 数据源:D:\\a.bmp * 数据目的地:E:\\a.bmp * 文件复制的步骤 * 1.创建输入流对象,绑定数据源 * 2.创建字节输出流对象,构造方法中绑定目的地 * 3.使用输入流中的read读 * 4.使用输出流中的write写 * 5.释放资源 * */ public class Demo07FileCopy { public static void main(String[] args) throws IOException { //1.创建输入流对象,绑定数据源 FileInputStream fis=new FileInputStream("d:\\a.bmp"); //2.创建字节输出流对象,构造方法中绑定目的地 FileOutputStream fos =new FileOutputStream("e:\\b.bmp"); /* * 3.使用输入流中的read读 * 4.使用输出流中的write写 * */ int len=0; //一次读取一个字节,写入一个字节 while((len=fis.read())!=-1){ fos.write(len); } //释放资源(先关写的,再关读的,如果写完了,肯定读完了) fos.close(); fis.close(); } }
三、字符流
1、字节流读取中文问题
package com.liujinhui.Day1105Stream; /* 问题:使用字节流读取中文文件 1个中文 GBK:占用2个字节 UTF-8:占用3个字节 * */ import java.io.FileInputStream; import java.io.IOException; public class Demo08GBKUTF { public static void main(String[] args) throws IOException { FileInputStream fis=new FileInputStream("src\\com\\liujinhui\\Day1105Stream\\c.txt");//UTF-8 占用3字节 int len=0; while((len=fis.read())!=-1){ System.out.println(len);//6个数 //System.out.println((char)len);//产生乱码 } fis.close(); } }
2、字符输入流
- Reader类,是所有字符输入流的超类
package com.liujinhui.Day1105Stream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; /* java.io.Reader:字符输入流,是最顶层父类,定义了一些共性的成员方法,是一个抽象类 共性的成员方法: int read() 读取单个字符并返回 int read(char[] cbuf) 一次读取多个字符,将字符读入数组 abstract void close() 关闭该流并释放与之关联的所有资源 抽象类的常见子类: 直接已知子类: BufferedReader, CharArrayReader, FilterReader, InputStreamReader【其下面的子类FileReader用来读取字符文件的便捷类】, PipedReader管道流, StringReader java.io.FileReader文件字符输入流 extends java.io.InputStreamReader extends java.io.Reader多重继承 作用:把硬盘文件中的数据以字符的方式读入内存中 构造方法: FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader。 FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader 构造方法的作用: 1.创建一个FileReader对象 2.把FileReader对象指向要读取的文件 FileReader字符输入流的使用步骤: 1.创建FileReader对象,构造方法中绑定读取的数据源 2.使用FileReader中的方法read读取文件 3.释放资源 * */ public class Demo09Reader { public static void main(String[] args) throws IOException { //1.创建FileReader对象,构造方法中绑定读取的数据源 FileReader fr=new FileReader("src\\com\\liujinhui\\Day1105Stream\\c.txt"); //2.使用FileReader中的方法read读取文件 /*int len=0; //读取单个 while((len=fr.read())!=-1){ System.out.print((char) len); }*/ //使用数组缓冲读取多个字符 char[] cs=new char[1024];//存储到的多个字符 int lens=0;//记录的是每次读取的有效字符个数 /* 把字符数组转换为字符串 String(char[] value) 分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。 把字符数组的一部分转换为字符串 String(char[] value, int offset, int count) 分配一个新的 String,它包含取自字符数组参数一个子数组的字符。 * */ while((lens=fr.read(cs))!=-1){ System.out.println(new String(cs,0,lens)); } } }
3、字符输出流
package com.liujinhui.Day1105Stream; import java.io.FileWriter; import java.io.IOException; /* java.io.Writer:字符输出流,是所有字符输出流的最顶层父类,是一个抽象类 成员方法: abstract void close() 关闭此流,但要先刷新它。 abstract void flush() 刷新该流的缓冲。 void write(char[] cbuf) 写入字符数组。 abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 void write(int c) 写入单个字符。 子类:BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter java.io.Writer 继承者 java.io.OutputStreamWriter 继承者 java.io.FileWriter java.io.FileWriter文件字符输出流 作用:把内存中的字符数据写入到文件中 构造方法: FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象,写入数据的目的地,是一个文件的路径 FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象 构造方法的作用: 1.创建FileWriter对象 2.根据构造方法中传递的文件/文件路径,创建文件 3.把FileWriter对象指向创建好的文件 使用步骤: 1.创建一个FileWriter对象,构造方法中绑定要写入数据的目的地 2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程) 3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中 4.释放资源(会把内存缓冲区中的数据刷新到文件中) * */ public class Demo10Writer { public static void main(String[] args) throws IOException { //1.创建一个FileWriter对象,构造方法中绑定要写入数据的目的地 FileWriter fw=new FileWriter("src\\com\\liujinhui\\Day1105Stream\\d.txt"); //2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程) fw.write(97);//不关闭,文件中没有数据【write把字符转化为字节】 //3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中 fw.flush(); //4.释放资源(会把内存缓冲区中的数据刷新到文件中) fw.close(); } }
- 其他方法(直接写入字符串)
package com.liujinhui.Day1105Stream; import java.io.FileWriter; import java.io.IOException; /* 字符输出流写数据的其他方法 void write(char[] cbuf) 写入字符数组。 abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。 void write(int c) 写入单个字符。 void write(String str) 写入字符串。 void write(String str, int off, int len) 写入字符串的某一部分。 * */ public class Demo12WriterOther { public static void main(String[] args) throws IOException { FileWriter fw =new FileWriter("src\\com\\liujinhui\\Day1105Stream\\f.txt"); char[] cs={'a','c','b','a','h'}; fw.write(cs);//acbah //写字符数组的一部分 fw.write(cs,1,3);//cba //写字符串 fw.write("刘金辉");//刘金辉 fw.write("黑马程序员",2,3);//程序员 fw.close(); } }
- 续写换行同字节输出流
四、I/O异常的处理
1、try_catch_finally
2、JDK7(try加括号自动释放)和JDK9(多变量分号分隔)
package com.liujinhui.Day1105Stream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* jdk9新特性 在try前定义流对象 在try后面的()中可以直接引入流对象的变量名 在try的代码执行完毕之后,流对象也可以释放掉,不用谢finally 格式: A a=new A(); B b=new B(); try(a,b){ .......} catch(){ } * */ public class Demo16JDK9Exception { public static void main(String[] args) throws FileNotFoundException { FileInputStream fis=new FileInputStream("d:\\a.bmp"); //2.创建字节输出流对象,构造方法中绑定目的地 FileOutputStream fos =new FileOutputStream("e:\\b.bmp"); try(fis;fos) { long s = System.currentTimeMillis(); //使用数组缓冲读取多个字节,写入多个字节 byte[] bytes = new byte[1024]; int len = 0; while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0, len); } } catch(IOException e){ System.out.println(e); } long e=System.currentTimeMillis(); System.out.println("复制文件共耗时"+(e-s)+"毫秒"); //fos.write(97);//不能再写,流已经被关闭 } }
五、属性集
1、概述
package com.liujinhui.Day1105Stream; import java.util.Properties; import java.util.Set; /* java.util.Properties集合 extends java.util.Properties implements Map<k,v> Properties类表示了一个持久的属性集,Properties可保存在流中或从流中加载 Properties集合是一个唯一和IO流相结合的集合 可以使用Properties集合中的方法store把集合中的临时数据,持久化写入到硬盘中存储 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用 属性列表中的每个键和对应的值都是一个字符串: Properties集合是一个双列集合,key和value默认都是字符串,无需写泛型 * */ public class Demo17Properties { public static void main(String[] args) { show01(); } /* * 使用Properties集合存储数据,遍历取出Properties集合中的数据 * Properties集合是一个双列集合,key和value默认都是字符串 * Properties有一些操作字符串的特有方法 * Object setProperty(String key, String value) 调用 Hashtable 的方法 put。 【map中的put方法】 String getProperty(String key, String defaultValue) 【通过key找value值】 用指定的键在属性列表中搜索属性。 【map集合中的get方法】 Set<String> stringPropertyNames() 【map集合中的keySet()方法】 返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。 * * */ private static void show01() { //1.创建Properties集合对象 Properties prop=new Properties(); //2.使用setProperty方法 prop.setProperty("赵丽颖","168"); prop.setProperty("迪丽热巴","165"); prop.put("欧阳娜娜",166);//可以用但不推荐,设置错的话取不出来 //使用stringPropertyNames方法,把集合中的键取出存储到set集合中 Set<String> set=prop.stringPropertyNames(); //遍历键,使用getProperty,通过key获取value for (String key:set){ System.out.println(prop.getProperty(key)); } } }
2、方法store
package com.liujinhui.Day1105Stream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.Properties; /* store方法,把集合中的临时数据,持久化写入硬盘存储 void store(OutputStream out, String comments) 【传递字节输出流,不能写中文】 以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。 void store(Writer writer, String comments) 【传递字符输出流,可以写中文】 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。 参数: String comments---注释,用来解释保存的文件是来做啥的,不能用中文,默认是Unicode编码,系统是GBK 一般使用空字符串 使用步骤: 1.创建Properties集合对象,添加数据 2.创建字节输出流/字符输出流对象,构造方法中绑定输出数据的目的地 3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储 4.释放资源 * */ public class Demo18PropertiesStore { public static void main(String[] args) throws IOException{ show03(); } private static void show03() throws IOException{ //使用字节流 //1.创建Properties集合对象,添加数据 Properties prop=new Properties(); //2.使用setProperty方法 prop.setProperty("赵丽颖","168"); prop.setProperty("迪丽热巴","165"); //2.创建字节输出流,但是字节流显示的是乱码,不能保存中文 prop.store(new FileOutputStream("src\\com\\liujinhui\\Day1105Stream\\r.txt"),"new save"); } private static void show02() throws IOException { //1.创建Properties集合对象,添加数据 Properties prop=new Properties(); //2.使用setProperty方法 prop.setProperty("赵丽颖","168"); prop.setProperty("迪丽热巴","165"); //2.创建字节输出流/字符输出流对象,构造方法中绑定输出数据的目的地 FileWriter fw=new FileWriter("src\\com\\liujinhui\\Day1105Stream\\h.txt"); //3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储 prop.store(fw,"save data"); //4.释放资源 fw.close(); } }
3、方法load
package com.liujinhui.Day1105Stream; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Set; /* void load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。 void load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。 参数: -InputStream inStream :字节输入流,不能读取含有中文的键值对 -Reader reader:字符输入流,可以读取含有中文的键值对 使用步骤: 1.创建Properties集合对象 2.使用Properties集合对象中的方法load读取键值对文件 3.遍历Properties集合对象集合 注意: 1.存储键值对的文件中,键和值的连接符可以使用- 、空格或其他符号 2.存储键值对的文件中,使用#被注释的键值对,不会再被读取 3.存储的文件中,默认是字符串,不用再加引号 * */ public class Demo19Load { public static void main(String[] args) throws IOException{ show03(); } private static void show03() throws IOException { //1.创建Properties集合对象 Properties prop=new Properties(); //2.使用Properties集合对象中的方法load读取键值对文件 prop.load(new FileReader("src\\com\\liujinhui\\Day1105Stream\\h.txt")); //3.遍历Properties对象集合 Set<String> set=prop.stringPropertyNames(); for (String key:set){ String value=prop.getProperty(key); System.out.println(key+"-"+value); } } }
本文来自博客园,作者:哥们要飞,转载请注明原文链接:https://www.cnblogs.com/liujinhui/p/14829485.html