黑马程序员——IO流(一)
来源:互联网 发布:网络维护培训学校 编辑:程序博客网 时间:2024/05/22 10:25
------- android培训、java培训、期待与您交流! ----------
一.基本概念
处理数据的流的方式就是IO技术
流可以理解为数据流动
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流
输入流和输出流相对于内存设备而言.
将外设中的数据读取到内存中:输入
将内存的数写入到外设中:输出。
二.字符流
字符流的由来:
其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表。获取对应的文字。
在对这个文字进行操作。简单说:字节流+编码表
字节流的两个顶层父类:
1,InputStream 2,OutputStream.// 读和写
字符流的两个顶层父类:
1,Reader 2,Writer
这些体系的子类都以父类名作为后缀。
而且子类名的前缀就是该对象的功能。
字符流两个基类:
Reader Writer
既然IO流是用于操作数据的
那么数据的最常见体现形式是:文件
例子
//需求:在硬盘上,创建一个文件并写入一些文字数据//找到一个专门用于操作文件的Writer子类对象 FileWriter 后缀名是父类名,前缀名是该流对象的功能import java.io.*;class FileWriteDemo{ publicstatic void main(String[] args) throws IOException//因为创建文件时可能会创建到不存在的盘符下,所有要抛出或trycatch { //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件 //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,会覆盖。 //其实该步就是在明确数据要存放的目的地 FileWriterfw = new FileWriter("demo.txt"); //调用write方法,将字符串写入到流中。此时txt中无数据,在流的缓冲中 fw.writr("abcd"); //flush()刷新流对象的缓冲的数据,将数据刷到目的地中。此时txt有数据 fw.flush(); //close()关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据 //将数据刷到目的地中。 //和flush区别,flush刷新后,流可以继续使用,close刷新后,会将流关闭 fw.close(); } }
对已有文件的数据续写
//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写。FileWriter fw =newFileWriter("demo.txt",true);
IO流异常
例子
import java.io.*;class FileDemo{ publicstatic void main(String[] args) { FileWriterfw = null; //在外面建立引用,因为finally中的fw.close()无法 //读取到try中建立的fw,所以要先建立 try { fw= new FileWriter("demo.txt"); fw.write("abccccc"); } catch(IOExceptione) { System.out.println(e.toString()); } finally { try { if(fw!=null)//创建失败时,若fw为空,则无法调用close() fw.close();//一定要执行,避免出错后浪费资源 //三句话都可能发生异常,这句话单独try } catch(IOExceptione) { System.out.println(e.toString()); } } }}
读取数据
例子
import java.io.*;class FileReaderDemo{ publicstatic void main(String[] args) throws IOException { //创建一个文件读取对象,和指定名称的文件相关联 //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException FileReaderfr = new FileReader("demo.txt");/* //"demo.txt"内写ab //调用读取流对象的read方法 //read():一次读一个字符,而且会自动往下读 intch1 = fr.read(); System.out.println("ch1="+(char)ch1); //强转成char型,不写char会转成int类型,结果a intch2 = fr.read(); System.out.println("ch2="+(char)ch2); //结果b fr.close();*/ //写成循环 intch = 0; while((ch=fr.read())!=-1){ //返回-1就是读到结尾了 System.out.println((char)ch); }
//读取一个字符数组//read(char[])返回的是读到字符个数char[] buf = new char[3];//缓冲区通常定义成1024的整数倍 如char[] buf = new char[1024]int num = 0;while((num=fr.read(buf))!=-1) { System.out.println(newString(buf,0,num));}fr.close();
拷贝文本文件
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中
步骤:
1、在D盘创建一个文件,用于存储C盘文件中的数据
2、定义读取流和C盘文件关联
3、通过不断的读写完成数据存储
4、关闭资源
例子
public static void main(String[] args)throws IOException{ //1,读取一个已有的文本文件,使用字符读取流和文件相关联。 FileReaderfr = new FileReader("IO流_2.txt"); //2,创建一个目的,用于存储读到数据。 FileWriterfw = new FileWriter("copytext_1.txt"); //3,频繁的读写操作。 intch = 0; while((ch=fr.read())!=-1) { fw.write(ch); } //4,关闭流资源。 fw.close(); fr.close();}
字符流缓冲区:
BufferedWriter
:newLine(); //换行
BufferedReader
:readLine(); //读一行文本
BufferedWriter: 使用缓冲区
例子
FileWriter fw = newFileWriter("buf.txt"); //创建一个文件 //为了提高写入的效率。使用了字符流的缓冲区。//创建了一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联BufferedWriter bufw = newBufferedWriter(fw); //使用缓冲区的写入方法将数据先写入到缓冲区中。//bufw.write("abcdefq"+LINE_SEPARATOR+"hahahha");//bufw.write("xixiixii");//bufw.newLine();//bufw.write("heheheheh"); for(int x=1; x<=4; x++){ bufw.write("abcdef"+x); bufw.newLine(); bufw.flush();} //使用缓冲区的刷新方法将数据刷目的地中。//bufw.flush(); //关闭缓冲区。其实关闭的就是被缓冲的流对象(fw)。bufw.close();
缓冲区的出现是为了提高流的操作效率而出现的
所有在创建缓冲区之前,必须要先有流对象
该缓冲区提供了一个跨平台的换行符
newLine();
readLine()方法的原理
无论是读一行,还是读取多个字符。其实最终都是在硬盘上一个一个读取。
所以最终使用的还是read方法一次读一个的方法。
使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记。将标记前的缓冲数据变成字符串返回。
装饰设计模式
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象
并基于被装饰的对象的功能,提供更强的功能
装饰和继承的区别
继承:
首先有一个继承体系。
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体。
装饰:
想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展。
效率提高需要加入缓冲技术。
Writer
|--TextWriter:用于操作文本
|--BufferTextWriter:加入了缓冲技术的操作文本的对象。
|--MediaWriter:用于操作媒体。
|--BufferMediaWriter:
装饰模式比继承灵活,避免了继承体系臃肿
而且降低了类与类之间的关系
例子:
class PersonDemo { publicstatic void main(String[] args){ Personx = new Person(); //写成X方便理解 NewPersonp1 = new NewPerson(x); //装饰类构造方法,传入被装饰类对象。此时this.p = x,把x所指对象的地址赋给了NewPerson中的p,所以NewPerson中的p.chifan();调用的是x所指对象的方法 p1.chifan(); }} class Person{ voidchifan(){ System.out.println("吃饭"); }} //这个类的出现时为了增强Person而出现的class NewPerson{ privatePerson p; NewPerson(Personp){ this.p= p; } publicvoid chifan(){ System.out.println("开胃酒"); p.chifan(); //假如这里写成chifan(); 结果就会变成不断循环开胃酒 System.out.println("甜点"); }}// 结果// 开胃酒// 吃饭// 甜点
特点:装饰类和被装饰类都必须所属同一个接口或者父类。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能
所以装饰类和被装饰类通常都是属于一个体系中的
LineNumberReader
带行号的装饰类,基于readLine,但是带行号
三.字节流
基本操作与字符流相同
但它不仅可以操作字符,还可以操作其他媒体文件
字节流写数据直接写入目的地,没有必要调flush();
available():字节长度,如果abcds,就是5个字节,多大就是多少
如
FileInputStream fis = newFileInputStream("fos.txt");int num = fis.available();byte[] buf = newbyte[fis.available()];//定义一个刚刚好的缓冲区,不用再循环了//但若数据过大,则不要用此方法,如一个视频几G,没必要定义这么大的缓冲区//此时还是定义成1024的整数倍比较好,如byte[] buf = new byte[1024];fis.read(buf);System.out.println(new String(buf));fis.close();
//复制一张图片//思路:/1、用字节读取流对象和图片关联//2、用字节写入流对象创建一个图片文件,用于存储获取到的图片数据//3、通过循环读写,完成数据的存储//4、关闭资源//例子import java.io.*;class CopyPic{ publicstatic void main(String[] args) { FileOutputStreamfos = null; FileOutputStreamfis = null; try { fos= new FileOutputStream("c:\\2.bmp"); fis= new FileInputStream("c:\\1.bmp");// 这个是源 //建议使用这种读取数据的方法 byte[]buf = new byte[1024]; //定义一个缓冲区 intlen = 0; while((len=fis.read(buf))!=1) { for.write(buf,0,len); } } catch(IOExceptione) { thrownew RuntimeException("复制文件失败"); } finally { try { if(fis!=null) fis.close(); } catch(IOExceptione) { thrownew RuntimeException("读取关闭失败"); } try { if(fos!=null)//需要分别关闭(出现异常的情况下) fos.close(); } catch(IOExceptione) { thrownew RuntimeException("写入关闭失败"); } } }}
读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应的标准输入设备,键盘
//需求://通过键盘录入数据//当录入一行数据后,就将该行数据进行打印//如果录入的数据时over,那么停止录入 publicstatic void readKey2() throws IOException { /* * 获取用户键盘录入的数据, * 并将数据变成大写显示在控制台上, * 如果用户输入的是over,结束键盘录入。 * * 思路: * 1,因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串。 * 2,那就需要一个容器。StringBuilder. * 3,在用户回车之前将录入的数据变成字符串判断即可。 * */ //1,创建容器。 StringBuildersb = new StringBuilder(); //2,获取键盘读取流。 InputStreamin = System.in; //3,定义变量记录读取到的字节,并循环获取。 intch = 0; while((ch=in.read())!=-1) { //在存储之前需要判断是否是换行标记 ,因为换行标记不存储。 if(ch=='\r') continue; if(ch=='\n'){ Stringtemp = sb.toString(); if("over".equals(temp)) break; System.out.println(temp.toUpperCase()); sb.delete(0,sb.length()); } else //将读取到的字节存储到StringBuilder中。 sb.append((char)ch); System.out.println(ch); }
转换流
1 .字节流
InputStream ->FileInputStream
OutputStream ->FileOutputStream
2 . 字符流
Reader -> BufferedReader -> LineNumberReader
-> InputStreamReader -> FileReader
Writer -> BufferedWriter
-> OutputStreamWriter -> FileWriter
InputStreamReader OutputStreamWriter 为转换流,FileReader FileWriter为其子类
如何选用哪种流读取文件?
IO流分为字符流 与 字节流,根据读写文件确定使用哪一种流,比如
读取文件是否为文本:
是:用字符流
不是:用字节流
何时使用转换流?
1.
如果使用非默认编码保存文件或者读取文件时,需要用到转换流,因为字节流的重载构造方法中有指定编码格式的参数,而FielReader与 FileWriter 是默认编码的文本文件
比如:
当我们使用默认GBK编码保存文本时,下面2句代码其实是一样的效果,
new OutputStreamWriter(new FileOutputStream("out.txt"))
new FileWriter("out.txt")
当要求保存为其他编码比如UTF-8时,就要这样写
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道开发时用到哪些对象。只要通过四个明确即可。
1,明确源和目的(汇)
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
2,明确数据是否是纯文本数据。
源:是纯文本:Reader
否:InputStream
目的:是纯文本 Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
3,明确具体的设备。
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4,是否需要其他额外功能。
1,是否需要高效(缓冲区);
是,就加上buffer.
2,转换。
例子
需求1:复制一个文本文件。1,明确源和目的。源:InputStream Reader目的:OutputStream Writer 2,是否是纯文本?是!源:Reader目的:Writer 3,明确具体设备。源:硬盘:File目的:硬盘:FileFileReader fr = newFileReader("a.txt");FileWriter fw = newFileWriter("b.txt"); 4,需要额外功能吗?需要,需要高效。BufferedReader bufr = newBufferedReader(new FileReader("a.txt"));BufferedWriter bufw = newBufferedWriter(new FileWriter("b.txt"));
需求2:读取键盘录入信息,并写入到一个文件中。1,明确源和目的。源:InputStream Reader目的:OutputStream Writer 2,是否是纯文本呢?是源:Reader目的:Writer 3,明确设备源:键盘。System.in目的:硬盘。FileFileWriter fw = newFileWriter("b.txt");这样做可以完成,但是麻烦。将读取的字节数据转成字符串。再由字符流操作。 4,需要额外功能吗?需要。转换。 将字节流转成字符流。因为名确的源是Reader,这样操作文本数据做便捷。所以要将已有的字节流转成字符流。使用字节-->字符。InputStreamReaderInputStreamReader isr = newInputStreamReader(System.in);FileWriter fw = newFileWriter("b.txt"); 还需要功能吗?需要:想高效。BufferedReader bufr = newBufferedReader(new InputStreamReader(System.in));BufferedWriter bufw = newBufferedWriter(new FileWriter("b.txt"));
需求3:将一个文本文件数据显示在控制台上。1,明确源和目的。源:InputStream Reader目的:OutputStream Writer 2,是否是纯文本呢?是源:Reader目的:Writer 3,明确具体设备源:硬盘:File目的:控制台:System.outFileReader fr = new FileReader("a.txt");OutputStream out =System.out;//PrintStream 4,需要额外功能吗?需要,转换。FileReader fr= newFileReader("a.txt");OutputStreamWriter osw = newOutputStreamWriter(System.out);需要,高效。BufferedReader bufr = newBufferedReader(new FileReader("a.txt"));BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(System.out));
需求4:读取键盘录入数据,显示在控制台上。1,明确源和目的。源:InputStream Reader目的:OutputStream Writer 2,是否是纯文本呢?是源:Reader目的:Writer 3,明确设备。源:键盘:System.in目的:控制台:System.outInputStream in = System.in;OutputStream out = System.out; 4,明确额外功能?需要转换,因为都是字节流,但是操作的却是文本数据。所以使用字符流操作起来更为便捷。InputStreamReader isr = newInputStreamReader(System.in);OutputStreamWriter osw = newOutputStreamWriter(System.out);为了将其高效。BufferedReader bufr = newBufferedReader(new InputStreamReader(System.in));BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(System.out));
需求5,将一个中文字符串数据按照指定的编码表写入到一个文本文件中.1,目的。OutputStream,Writer2,是纯文本,Writer。3,设备:硬盘FileFileWriter fw = newFileWriter("a.txt");fw.write("你好"); 注意:既然需求中已经明确了指定编码表的动作。那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表。只能使用其父类。OutputStreamWriter.OutputStreamWriter接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStreamOutputStreamWriter osw = newOutputStreamWriter(new FileOutputStream("a.txt"),charsetName); //如 (newFileOutputStream("a.txt"),"GBK") 需要高效吗?BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(newFileOutputStream("a.txt"),charsetName));
什么时候使用转换流呢?
1,源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁。
提高对文本操作的便捷。
2,一旦操作文本涉及到具体的指定编码表时,必须使用转换流 。
目前为止,10个流对象重点掌握。
字符流:
FileReader
FileWriter
BufferedReader
BufferedWriter
InputStreamReader
OutputStreamWrier
字节流:
FileInputStream
FileOutputStream
BufferedInputStream
BufferedOutputStream
- 黑马程序员——io流(一)字符流
- 黑马程序员——IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——IO(Input Output)流(一)
- 黑马程序员——JAVA基础-IO流(一)
- 黑马程序员——Java IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——IO流总结(一)
- 黑马程序员——IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——Java基础--IO流(一)
- 黑马程序员——IO流(一)
- 黑马程序员——Java基础--------IO流(一)
- 黑马程序员——JAVA基础----IO流(一)
- 黑马程序员——java---IO(一)
- Xcode出现could not build module foundation错误 解决方案
- Android开发中模拟Home键操作和关闭手机软键盘
- EOR逻辑异或指令
- 采访:关于 Go 语言和《Go Web编程》
- P2P流媒体技术方案
- 黑马程序员——IO流(一)
- 史上最全设计模式导学目录(完整版)
- 基本的排序算法:冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序
- 常用ARM汇编指令
- eclipse 下github 安装
- webbench学习之getopt_long,atio
- 傅里叶变换、拉普拉斯变换、Z变换
- Jersey开发环境搭建(maven tomcat eclipse集成艰苦之旅)
- SDIO的SPI模式驱动分析