------- android培训、java培训、期待与您交流! ----------
IO流
第一部分
1、IO流
|--IO流用来处理设备之间的数据传输
|--java对数据的操作是通过流的方式
|--java用于操作流的对象都在IO包中
|--流按操作数据分为两种:字节流与字符流;
|--流按流向分为:输入流,输出流。
2、IO流常用基类
|--字节流的抽象基类:
|--InputStream ,OutputStream。|--字符流的抽象基类:
|--Reader ,Writer。
|--注:由这四个类派生出来的子类名称都是 以其父类名作为子类名的后缀。
3、FileWriter
|--既然IO是用来操作数据的,那么数据的最常见的体现形式是:文件,|--FileWriter:用来写入字符文件的便捷类,后缀名是父类名,前缀名就是该流对象的功能;
|--需求:
在硬盘上,创建一个文件并写入一些文字数据;步骤:1、创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建到指定的目录下,如果该目录下已有重名文件,将被覆盖,其实该步就是在明确数据要存在的目的地;
2、调用write方法,将字符串写入到流中;
3、刷新流对象的缓冲中的数据;
4、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:14px;">import java.io.*; class FileWriterDemo { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("demo.txt"); fw.write("abcdefg"); // 将数据刷到目的地; fw.flush(); // 关闭流资源,但是在关闭之前会刷新一次内部的缓冲中的数据,将数据刷到目的地中, // 和flush的区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭; fw.close(); } }</span></span>
5、如何处理IO异常
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:14px;">import java.io.*; //一个标准的io异常就处理完了。 class FileWriterDemo2 { public static void main(String[] args) { // 调用了windows底层的创建文件的资源;在外面建立引用 FileWriter fw = null; try { // 在里面进行初始化 fw = new FileWriter("k:\\demo.txt"); // 把数据写到了流里面 fw.write("abcdefghaha"); fw.flush(); } catch (IOException e) { System.out.println(e.toString()); } finally { //fw.close();要单独try一下。 try { if(fw!=null)//如果fw=null,那么调用close的方法是没有意义的。 fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }</span></span>
6、文件数据的续写;
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:14px;">/* 演示对已有文件的数据续写 */ import java.io.*; class FileWriterDemo3 { public static void main(String[] args) { FileWriter fw = null; try { // 传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行续写 fw = new FileWriter("demo.txt",true);//对已有文件的数据进行续写。 fw.write("nihao\r\nxiexie");//加了一个换行符; } catch (IOException e) { System.out.println(e.toString()); } finally { try { if(fw!=null) fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }</span><span style="font-size:18px;"> </span></span>
在windows里面的换行是\r\n,而在Linux里面换行的是\n;
7、运行结果
第二部分
1、读操作第一种方式
|--FileReader:用来读取字符文件的便捷类。|--一次读取单个字符
2、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-size:14px;">/* 文本文件的读取 */ import java.io.*; class FileReaderDemo { public static void main(String[] args) { // 创建一个文件读取流对象,和指定名称的文件相关联 // 要保证该文件已经存在的,如果不存在,会发生异常 FileReader fr =null; try { fr = new FileReader("demo.txt"); int ch =0; // 调用读取流对象的read方法; // read()方法:一次读取一个自读,而且会自动往下读; // 返回的整数类型int,作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1 while((ch=fr.read())!=-1) { System.out.print((char)ch); } /* while(true) { // 读取一个字符的方法,该方法返回的是一个int型的 int ch = fr.read(); if(ch==-1) break; System.out.println("ch="+(char)ch); } */ } catch (IOException e) { System.out.println(e.toString()); } finally { try { if(fr!=null) fr.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }</span><span style="font-size:18px;"> </span></span>
3、运行结果
4、文本文件读取方式二
第二种方式:通过字符数组进行读取;
|--int read(char[] cbuf) 返回的是个数,读取几个就返回几个
步骤:
1、定义一个字符数组,用于存储读到字符,该read(char[] cbuf)返回的是读到的一个字符个数;
2、当缓冲区里面的数据存满了以后,就将数据打印出去;
5、代码实现
<span style="font-family:Microsoft YaHei;font-size:14px;">/* 这个是读取一个就存一下,等到存满了,就一次性打出去; */ import java.io.*; class FileReaderDemo2 { public static void main(String[] args) { FileReader fr =null; try { fr = new FileReader("demo.txt"); // 缓冲区通常情况下会定义1024的倍数; char[] buf = new char[1024];//读取一个数组。通过字符数据进行读取 // 定义一个变量,因为每一次返回来的个数不一样 int num =0; // num的值只要不等于-1,就可以一直读 while((num=fr.read(buf))!=-1) { // 把数组中从什么位置开始,读几个,读到几个,就打几个 // String(char[] value, int offset, int count System.out.println(new String(buf,0,num)); } // int num = fr.read(buf);//返回的是读取的字符数,如果已到达流的末尾,则返回 -1 // System.out.println("num="+num+"..."+new String(buf));//把数组变成字符串 } catch (IOException e) { System.out.println(e.toString()); } finally { try { if(fr!=null) fr.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }</span>
6、运行结果
7、第二种方式练习1
读取一个.java文件,并打印在控制台上;8、代码实现
<span style="font-family:Microsoft YaHei;">import java.io.*; class FileReaderTest { public static void main(String[] args) { FileReader fr =null; try { fr = new FileReader("FileWriterDemo.java"); char[] buf = new char[1024];//读取一个数组。2K int num =0; while((num=fr.read(buf))!=-1) { System.out.print(new String(buf,0,num)); } // int num = fr.read(buf);//返回的是读取的字符数,如果已到达流的末尾,则返回 -1 // System.out.println("num="+num+"..."+new String(buf)); } catch (IOException e) { System.out.println(e.toString()); } finally { try { if(fr!=null) fr.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }</span>
9、运行结果
10、第二种方式练习2
将c盘一个文本文件复制到D盘。复制的原理:其实就是将c盘下的文件数据存储到D盘的一个文件中;
步骤:
|--在D盘中创建一个文件,用于存储C盘文件中的数据;|--定义读取流和C盘文件相关联;|--通过不断的读写完成数据存储;|--关闭资源;第一种方式拷贝:这个是从C盘读一个字符,就往D盘写一个字符;
第二种方式拷贝:这个是从C盘读字符用字符缓冲区进行存储,,如果存满了以后就打印出去,再次读取;
11、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.*; class CopyTest { public static void main(String[] args) throws IOException { copy_2(); } // 第二种方式 public static void copy_2() { // 在外面先定义好引用 FileWriter fw=null; FileReader fr =null; try { // 在里面初始化 fw = new FileWriter("RuntimeCopy_2.txt"); fr = new FileReader("FileWriterDemo.java"); int len = 0; // 定义一个字符数组; char[] buf = new char[1024]; while((len=fr.read(buf))!=-1) { // 有一个写入数组的方法。把缓冲区里面的数据写到流里面去 // void write(char[] cbuf) // abstract void write(char[] cbuf, int off, int len) // 写入数组,从哪边开始,写几个 fw.write(buf,0,len); } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { // 关流要分开单独try 和catch; try { if(fr!=null) fr.close(); } catch (IOException e) { System.out.println(e.toString()); } try { if(fw!=null) fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } } // 第一种方式 // 从C盘读取一个字符,就往D盘写一个字符; public static void copy_1()throws IOException { // 创建目的地; FileWriter fw = new FileWriter("RuntimeCopy_1.txt"); // 与已有的文件相关联 FileReader fr = new FileReader("RuntimeDemo.java"); int ch =0; // 一次读取一个字符; while((ch=fr.read())!=-1) { // 因为是一次读取一个字符,那么就一次写入一个字符 // void write(int c) fw.write(ch);//写入单个字符。读一个我就写一个。 } // 关流 fr.close(); fw.close(); } }</span>
第三部分
1、字符流的缓冲区
缓冲区的出现提高了对数据的读写效率;为了提高流的读写数据,那么就要先有流对象;字符流缓冲去对应的类:具备缓冲技术的字符流;
|--BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。|--BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。2、字符写入流
步骤:
|--创建一个字符写入流对象;|--为了提高字符写入流效率,加入了缓冲技术;缓冲技术就是先把数据先存起来,在一次性将数据一次性写出去;|--只要是用到缓冲区,就要进行刷新|--其实缓冲区的关闭,就是在关闭了缓冲区中的流对象;3、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">/* 把数据写入到文件中,加入缓冲技术 */ import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("buf.txt"); // 为了提高流的写入效率,加入了缓冲区技术; // 要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可; BufferedWriter bufw = new BufferedWriter(fw); for(int x=0;x<5;x++) { bufw.write("abce"+x); bufw.newLine();//newLine是一个跨平台的换行符 bufw.flush(); } // 其实关闭缓冲区,就是关闭了缓冲区的流对象,就不要写fw.close(); bufw.close(); } }</span>
4、字符输出流
步骤:
|--创建一个读取流对象和文件相关联;|--为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数;
|--按照读取一行的方式进行读取;
5、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.*; class BufferedReaderDemo { public static void main(String[] args) throws IOException { // 创建一个读取流对象和文件相关联 FileReader fr = new FileReader("buf.txt"); // 为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数; BufferedReader bufr = new BufferedReader(fr); String line =null; // String readLine() ,按照读取一行的方式进行读取 while((line=bufr.readLine())!=null) { System.out.println(line); } // String s = bufr.readLine();//读取一行数据 // System.out.println("s="+s); bufr.close(); } }</span>
6、通过缓冲区复制文本文件
代码体现
<span style="font-family:Microsoft YaHei;">/* 通过缓冲区复制一个.java文件 */ import java.io.*; class CopyTextByBuf { public static void main(String[] args) { BufferedWriter bufw = null; BufferedReader bufr = null; try { bufw = new BufferedWriter(new FileWriter("BufferReader.txt")); bufr = new BufferedReader(new FileReader("BufferedReaderDemo.java")); // 一行一行的进行读取; String line =null; while((line=bufr.readLine())!=null) { // 写字符串的方法; bufw.write(line); bufw.newLine();//要进行一次换行操作 bufw.flush(); } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if(bufw!=null) bufw.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } try { if(bufr!=null) bufr.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } } } }</span><strong> </strong>
第四部分
1、字节流
|--InputStream:此抽象类表示字节输入流的所有类的超类。|--OutputStream:此抽象类是表示输出字节流的所有类的超类(写);
需求:想要操作图片数据,这时就要用到字节流;2、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">/* 要以第二个为主; */ import java.io.*; class FileStream { public static void main(String[] args) throws IOException { readFile_3(); } // 第三种 public static void readFile_3()throws IOException { FileInputStream fis = new FileInputStream("fos.txt"); byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区,不用循环了。 fis.read(buf); // int num = fis.available(); // System.out.println(num); System.out.println(new String(buf)); fis.close(); } // 第二种,还是以这个为主。定义一个1024的数组长度。 public static void readFile_2()throws IOException { FileInputStream fis = new FileInputStream("fos.txt"); // 创建一个字节数组 byte[] buf = new byte[1024]; int len =0; while((len=fis.read(buf))!=-1) { // 一次性打印出来了; System.out.println(new String(buf,0,len)); } fis.close(); } // 这是是读一个打一个,比较麻烦 // 读一个文件 public static void readFile_1()throws IOException { FileInputStream fis = new FileInputStream("fos.txt"); int ch=0; while((ch=fis.read())!=-1) { // 读出来的是一个整数,要转一下 System.out.print((char)ch); } fis.close(); } // 写一个文件 public static void fileStream()throws IOException { FileOutputStream fos = new FileOutputStream("fos.txt"); // OutputStream操作的是字节数组,那么可以将字符串变成字节,在字符串里面的方法,把字符串变成字符数组,是toCharArray fos.write("abcdef".getBytes()); fos.close();//字节流还是要关闭的。 } }</span><span style="font-size:18px;"> </span>
3、运行结果
4、字节流练习
复制一个文件
思路:
|--用字节读取流对象和图片相关联;|--用字节写入流对象创建一个图片文件,用于存储获取到的图片数据;|--通过循环读写,完成数据的存储;|--关闭资源;5、代码体现
<span style="font-family:Microsoft YaHei;"><span style="font-size:14px;">/* 复制一个图片文件 */ import java.io.*; class CopyPic { public static void main(String[] args) { FileOutputStream fos =null; FileInputStream fis =null; try { fos = new FileOutputStream("c:\\2.bmp"); // 这个是源; fis = new FileInputStream("c:\\1.bmp"); // 定义缓冲区; byte[] buf = new byte[1024]; int len =0; while((len=fis.read(buf))!=-1) { fos.write(buf,0,len); } // System.out.println(len);不要写输出语句 } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if(fis!=null) fis.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } try { if(fos!=null) fos.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } } } }</span><span style="font-size:18px;"> </span></span>
6、字节流缓冲区
演示mp3的复制,通过缓冲区
字节流缓冲区:
|--BufferedInputStream
|--BufferedOutputStream
7、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.*; class CopyMp3 { public static void main(String[] args) { // 为了看到拷贝用的时间 long start = System.currentTimeMillis(); copy_1(); long end = System.currentTimeMillis(); System.out.println((end-start)+"毫秒"); } // 通过字节流的缓冲区完成复制 public static void copy_1() { BufferedOutputStream bufos = null; BufferedInputStream bufis = null; try { bufos = new BufferedOutputStream(new FileOutputStream("c:\\2.mp3")); bufis = new BufferedInputStream(new FileInputStream("c:\\1.mp3")); // 不需要定义字节缓冲区,因为已经有了缓冲区了。 int by =0; while((by=bufis.read())!=-1) { bufos.write(by); } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if(bufis!=null) bufis.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } try { if(bufos!=null) bufos.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } } } }</span><span style="font-size:18px;"> </span>
第五部分
1、键盘录入
|--System.out:对应的标准输出设备:控制台;|--System.in:对应的标砖输入设备:键盘;2、需求
想要通过键盘录入的方式,在控制台上打印一个小写转成大写的程序;3、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.*; class ReadIn { public static void main(String[] args) throws IOException { InputStream in = System.in; // 定义一个缓冲区,用于存储数据 StringBuffer sb = new StringBuffer(); // int by = in.read(); // int ch =0; while(true) { // 当我敲回车的时候把数据一次性打印出来 int ch = in.read(); if(ch=='\r') continue; if(ch=='\n') { // 把缓冲区里面的数据变成字符串 String s = sb.toString(); // 判断字符串内容是否相同 if("over".equals(s)) break; System.out.println(s.toUpperCase()); sb.delete(0,sb.length());//清空缓冲区。 } else sb.append((char)ch); } in.close(); // System.out.println((char)(by)); } }</span><span style="font-size:18px;"> </span>
4、需求分析
通过刚才的键盘录入一行数据并打印其带邪恶,发现其实就是读一行数据的原理;也就是readLine方法;能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?readLine方法是字符流BufferedReader类中的方法;而键盘录入的read方法是字节流InputStream的方法;能不能将字节流转成字符流在使用字符流缓冲区的readLine方法呢?步骤:
|--获取键盘录入对象;|--将字节流对象转成字符流对象,使用转换流InputStreamReader|--为了提高效率,将字符串进行还从技术高效操作,使用BufferedReader
5、代码体现
<span style="font-family:Microsoft YaHei;font-size:14px;">import java.io.*; class TransStreamDemo { public static void main(String[] args) throws IOException { // 1、 InputStream in = System.in; // 字节流转成字符流的桥梁的引出是通过read和readLine的方法 // 因为一次读一个的方法太破了,我们要一次读取一行的方法,因此就要将 // read是字节流InputStream里面的方法。我们要用的是字符流BufferedReader里面的 // readeLine方法,因此要将字节流转成字符流,才可以使用字符流里面的方法; // 将字节流转成字符流;已经是字符流了; // 2、 InputStreamReader isr = new InputStreamReader(in);//把字节流串传进来 // 为了提高效率,将字符串进行缓冲技术高效操作,使用BufferedReader // 因为BufferedReader可以对Reader进行装饰,就是功能的增强;可以接收一个Reader的子类, // 这个子类就是Reader的转换流InputStreamReader; // 3、 BufferedReader bufr = new BufferedReader(isr); // 可以将上面的3句话变成一句话 // 读取键盘录入;最常见写法 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); // 用printStream的父类OutputStream来接收输出流; // 1、 OutputStream out = System.out; // 这个是字符流转换成字节流的桥梁。 // 2、 OutputStreamWriter osw = new OutputStreamWriter(out); // 这时候要用到一个newLine进行换行操作,但是newLine是BufferWriter的方法 // 要把OutputStreamWriter增强一下。 // 3、 BufferedWriter bufw = new BufferedWriter(osw); // 要用到的是缓冲区的方法; // 同样3句话变成一句话 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out)); // 一次读取一行的操作; String line = null; while((line =bufr.readLine())!=null) { // 要定义一个结束标记; if("over".equals(line)) break; bufw.write(line.toUpperCase()); // 进行换行;用的是缓冲区的方法; bufw.newLine(); // 要将缓冲区进行刷新一下; bufw.flush(); // 这时候就不要输出语句了;直接用osw.write(line.toUpperCase()); // System.out.println(line.toUpperCase()); } bufr.close(); } }</span><span style="font-size:18px;"> </span>
第六部分
1、流操作的规律
通过三个明确来完成:
|--通过源和目的;
|--源:输入流:InputStream Reader|--目的输出流:OutputStream Writer
|--操作的数据是否是纯文本
|--是:用字符流;|--不是:用字节流;|--当体系明确后,在明确要使用哪个具体的对象
|--源设备:内存,硬盘(文件),键盘
|--目的设备:内存,硬盘(文件),控制台
2、需求一
将一个文本文件中的数据存储到另一个文件中,-->复制文件;步骤:
|--源:因为是源,所以使用读取流:InputStream Reader|--是不是操作的文本文件:是!就用字符流:Reader
这样体系就明确了;接下来要使用该体系中的哪个对象;|--明确设备:硬盘:是一个文件
Reader体系中可以操作文件的对象是FileReader;|--是否需要提高效率:是,加入Reader体系中的缓冲区;BufferedReader
|--目的:OutputStream Writer
|--是否是纯文本:是!用Writer
|--设备:硬盘一个文件
|--Writer体系中的可以操作文件的对象是FileWriter
|--是否需要提高效率:是,加入Writer体系中的缓冲区;BufferedWriter
3、需求二
将一个图片文件中的数据存储到另一个文件中,复制文件,按照流操作的规律完成。
|--源:InputStream Reader|--是不是操作的文本文件:是!就用字符流:Reader|--设备:键盘,对应的是键盘System.in
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文件数据方便,转成字符流按照字符串操作是最方便的,
所以既然明确了Reader,那么就将System.in转成了Reader
用了Reader体系中的转换流,InputStreamReader
|--需要提高效率吗?
|--需要,用BufferedReader;
|--目的:OutputStream Writer
|--是否是纯文本文件:是!用Writer
|--是否需要提高效率?需要,用BufferedWriter
第七部分
我的总结
|--文件的读取方式有两种:
|--缓冲区的出现是为了提高流的读写数据,所以在创建缓冲区之前,必须就要先有流对象;|--一次读取单个字符,这个效率特别慢,需要循环N次;
|--一次读取多个字符,并用缓冲区存储起来,如果存满了,就打印出去;
|--只要用到缓冲区就要将缓冲区进行刷新;
|--BufferedWriter:该缓冲区中提供了一个跨平台的换行符,就是newLine,只有用到缓冲区才有这个方法;
|--BufferedReader:该缓冲区提供了一个一次读一行的方法readLine,方便于对文本数据的获取;当返回null时,代表读到文件末尾;
|--readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符,所以要进行newLine;
|--readLine方法的原理:无论是读一行,获取速去多个字符,其实最终都是在硬盘上一个一个的读取,所以最终使用的还是read方法一次读一个的方法;
|--在读取数据的方法里面,字符流用的是字符数组,字节流用的是字节数据;
|--InputStreamReader 是字节流通向字符流的桥梁,也就是字节流转成字符流;本身是一个字符流,就要传一个字节流
|--OutputStreamWriter 是字符流通向字节流的桥梁,也就是字符流转成字节流;
|--掌握流操作的规律;
|--转换流什么时候用,字符和字节之间的桥梁,通常,在涉及等到字符编码表转换的时候,需要用到转换流