20-1,IO流-输入流-输出流
1,IO,即Input和Output的简写,表示输入输出。
IO流用于处理设备之间的设备传输,例如:内存,硬盘,优盘...
2,Java对数据的操作时通过流的方式。
数据从内存转移到硬盘称为输出,数据从硬盘转移到内存称为输入。
20-2,字节流-字符流
1,输入流和输出流是相对于内存设备而言的。
将外设中的数据读取到内存中,称为输入。
将内存中的数据写入到外设中,称为输出。
2,字符流的由来。
其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字,再对这个文字进行操作。简单说就是:字节流+编码表。
20-3,字符流-FileWriter
字符流负责字符的内存和硬盘之间的IO,中文汉字,英文字母都是字符。
1,IO流常用基类
字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer
注意:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。例如:InputStream的FileInputStream,Reader的子类FileReader,子类名的前缀就是该对象的功能。
2,需求:将一些文字存储到一个硬盘文件中。
记住:如果要操作文字数据,建议优先考虑字符流,而且要将数据从内存写到硬盘上,要使用字符流中的输出流,Writer。硬盘的数据基本体现是文件。希望可以找到一个可以操作文件的Writer,我们可以发现FileWriter可以满足需求。FileWriter没有空参构造函数,需要用参数指定写入哪个文件,或目的地路径。
public class FileWriterDemo { public static void main(String[] args) throws IOException { /* 创建一个可以往文件中写入字符数据的字符输出流对象。 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(指用于存储数据的地方) 如果文件不存在,则会自动创建。 如果文件存在,则会自动覆盖。 */ FileWriter fw = new FileWriter("demo.txt");//在当前目录下创建 //调用Writer对象中的write(String)方法,写入数据,其实是把数据写入到临时存储缓冲区中。 //此时文件中没有数据。 fw.write("abcde"); //进行刷新,将数据直接写到目的地中,用flush()方法 fw.flush(); //关闭流,关闭资源,在关闭前会先调用flush刷新缓冲中的数据到目的地。 fw.close(); //fw.write("haha");//这时已经无法再写入,因为流已经关闭,抛出异常:java.io.IOException:Stream closed } }
20-4,换行和续写
1,想要在输出的文件中进行换行操作,但每个操作系统的换行不一致怎么办?
可以用Properties获取系统信息,字段是line.separator。例如:
public static final StringLINE_SEPARATOR = System.getProperty("line.separator");
2,续写:之前的方法在输出完一个文件之后,不能再在这个文件后面继续写。想要实现续写操作,可以在FileWriter的构造函数中加入true。
FileWriter(String filename,Boolean append),加入已经有一个文本文件,并已经有数据abcde,并且关闭了这个输出流,那么如果是按照上述方法构造的,可以在关闭之后直接fw.writer("xixi");则可以实现在abcde后面直接续写xixi的功能。
20-5,IO的异常处理
开启一个IO流是需要消耗资源的,在用完这个流之后,我们应该将他关闭。但是在关闭之间如果程序抛出异常,会导致程序结束,但流仍未关闭,浪费了资源。所以对于可能抛出异常的IO操作,为了确保刘能关闭,要将关闭流的操作放到finally中,下面给出了IO异常通常的解决方法。
public class IOExceptionDemo { public static void main(String[] args) { FileWriter fw = null; try { /* 抛出IO异常,不能在外面new,因为有异常。 也不能在里面定义fw,否则finally块中会找不到fw变量, 只能在外面定义,在里面new。 */ fw = new FileWriter("k:\\demo.txt"); fw.write("abcde");// } catch(IOException e) { System.out.println(e.toString()); } finally { /* 无论有没有异常,释放资源的fw.close()操作必须要做, 将它放在finally中。 如果new的时候抛出异常,则表明文件创建失败,fw为null。 如果fw为null的话会抛出空指针异常,所以不为null时才能执行close()操作。 */ if(fw != null){ try { fw.close(); } catch(IOException e) { //处理方法...code... throw new RuntimeException("关闭失败"); } } } } }
20-6,字符流-FileReader-读取方式1
他是一个字符读取流,用于将硬盘中的字符读取到内存中。
需求:读取一个文本文件,将读取到的字符打印到控制台。
public class FileReaderDemo { public static void main(String[] args) throws IOException { //1,创建读取字符数据的流对象 //在创建读取流对象时,必须要明确被读取的文件, //一定要确定该文件是存在的,用一个读取流关联一个已存在文件 FileReader fr = new FileReader("demo.txt"); int ch = 0; while((ch = fr.read())!=-1) { System.out.println((char)ch); } } }
用read方法读取字符,返回一个int型的值,这个值在0-65535之间,如果读到结尾处的后一个字符,则返回-1。
20-7,FileReader读取文件方式2
自定义数组缓冲区的方式。定义一个char[]数组,将读取的字符先读到这个数组中,所有的都读取完后,再利用String的构造函数String(char[] buf,int start,intlen)将数组缓冲区中的数据输出。这样效率会比单个字符输出高。
public class FileReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("demo.txt"); //使用read(char[])读取文本文件数据 //先创建字符数组,相当于定义一个缓冲区 char[] buf = new char[1024];//一般定义成1024的整数倍 int len = 0; while((len = fr.read(buf)) != -1) { System.out.println(new String(buf,0,len)); } fr.close(); } }
一般优先使用第二种方式,第一种方式每次只取一个,要取好多次,第二种先将所有的取出存在一个数组中,再从数组中一次性取出,效率要高。