黑马程序员---IO流
2013-05-23 18:13
211 查看
------- Java、.Net、Android培训期待与您交流!-------
一、概念:
(1)用来处理设备(硬盘,控制台,内存)间的数据。
(2)java中对数据的操作都是通过流的方式。
(3)java用于操作流的类都在io包中。
(4)按照流操作的数据的类型不同:分为字节流和字符流。字符流是为了方便中文的操作而来的。
(5)按照流的流向不同分为:输入流,输出流
字符流和字节流(四个抽象基类):
字节流两个基类:InputStream(输入流) OutputStream(输出流)
字符流两个基类:Reader(输入流) Writer(输出流)
二、字符流:
1、结构树:
Reader(read:可以读一个字符或者是读一个字符数组,结束标记返回:-1.要关流)
|--StringReader(操作字符串)
|--CharArrayReader(操作字符数组)(同ByteArrayInputStream,但需要抛异常)
|--PipedReader
|--FilterReader
|--InputStreamReader(常用)
读取转换流:将字节文本转换成字符文本,前提必须接收一个输入字节流对象InputStream
|--FileReader(常用)
|--BufferedReader(特有方法:readLine:返回一行,不返回回车符,打印要用println方法。结束标记返回:null)
|--LineNumberReader(很少)(特有方法:setLineNumber、getLineNumber)
Writer(write:可以写入一个字符或者一个字符数组。写入操作需要刷新flush和关流(关流前会自动刷新一次))
|--StringWriter(操作字符串)
|--CharArrayWriter(操作字符数组)(同ByteArrayOutputStream,但需要抛异常)
|--PrintWriter(常用)
其中有方法:write、print、println、close、flush、append,这些方法都不需要进行处理或抛出异常,方法本身已经覆盖父类方法并且进行了处理。其中只是构造函数和一些特定方法要抛出异常或进行处理。构造函数可以接受的参数有(file对象、字符串路径、字符输出流Writer、字节输出流OutputStream/System.out);
|--FilterWriter
|--OutputStreamWriter(常用)
写入转换流:将字符文本转换成字节文本,前提必须接收一个输出字节流对象OutputStream
|--FileWriter(常用)
|--BufferedWriter(常用)(特有方法:newLine:跨平台换行符)
2、输出(写入)流操作步骤:
1>、FileWriter:
2>、BufferedWriter :
3、输入(读取)流操作步骤:
1>、FileReader:
2>、BufferedReader:包括异常处理
三、字节流:
1、结构树:
InputStream(read:可以读一个字节或者是读一个字节数组,结束标记返回:-1。available:返回读取文本的字节个数。要关流)
|--ByteArrayInputStream(操作字节数组输入流)
在构造的时候,需要接收数据源,而且数据源是一个字节数组。因为该对象操作的是数组,并没有使用系统资源,所以不用进行close关闭。
|--ObjectInputStream(一般)
方法:readObject(Object obj):读取文件中对象的内容(或值)来直接使用。一次读一个对象,其他方法和ObjectOutputStream都互补。
|--PipedInputStream(一般,比较特殊的流对象)
管道流:输入输出流可以直接进行连接,结合线程来使用。
问题:因为出现多线程,在read方法(阻塞方法,有数据才读,否则等待)执行时可能发生死锁。
构造方法:PipedInputStream(PipedOutputStream src):创建输入流连接到src(输出流)
PipedInputStream():创建尚未连接的管道输入流。
方法:connect(PipedOutputStream src):连接到输出流src,仅用于为创建连接的构造函数。
|--StringBufferInputStream
|--SequenceInputStream(一般)
SequenceInputStream(Enumeration<? extends InputStream> en)
枚举Enumeration是Vector特有的方法,已被ArrayList替换。将多个输入流整合成一个输入流来操作。
构造方法可以接收一个枚举类型的引用,该引用所指向的内容都是InputStream或其子类类型的对象。
|--AudioInputStream
|--FileInputStream(常用)
|--FilterInputStream
|--LineNumberInputStream(前提必须接收一个输入字节流对象InputStream)
|--BufferedInputStream(常用)(同BufferedReader,没有readLine方法)
|--DataInputStream(常用)
专门用于操作基本数据类型的输入流,读取文件的内容全部是二进制表现形式,再经过解码变成我们认识的文字。
方法:readUTF():该方法调用的是UTF-8的修改版,一个汉字占4个字节。
注:read方法和DataOutputStream中的write方法必须匹配,否者读出的数据与来输入数据不一样如writeInt方法必须匹配readInt方法。
OutputStream(write:可以写入一个字节或者一个字节数组。关流)
|--ByteArrayOutputStream(操作字节数组输出流)
在构造的时候,不用定义数据目的,因为该对象已经在内部封装了可变长度的字节数组。
因为该对象操作的是数组,并没有使用系统资源,所以不用进行close关闭。
特有方法:writeTo(OutputStream out):抛IOException,将字节数组输出流的全部内容写入到指定的输出流参数中(文件)。
|--ObjectOutputStream(一般)
几个特别的方法:writeInt:写入文件中的是32位数据,即返回int型,不是字节,操作基本数据类型。
write:写入文件中的是数据的最低8位,即字节。writeLong、writeChar、writeFloat等同理。
writeObject(Object obj):写入文件中的是一个对象包括对象中的数据。
注:被操作的对象需要实现序列化接口Serializable(标记接口:接口中没有方法可覆盖),系统会自定给该类成员变量加上一个UID标记作为序列号,保证其唯一性。static final long serialVersionUID = 51L;
该对象中只有一般成员变量才能被序列化(即存储在堆内存中),放在方法区中的方法和static修饰的成员变量不能被序列化。另外被transient修饰的一般成员变量也不能被序列化。
|--PipedOutputStream(一般,比较特殊的流对象)
|--FileOutputStream(常用)
|--FilterOutputStream
|--BufferedOutputStream(常用)(同BufferedWriter,没有方法newLine)
|--PrintStream(常用)
其中有方法:write、print、println、close、flush、append,这些方法都不需要进行处理或抛出异常,方法本身已经覆盖父类方法并且进行了处理。其中只是构造函数和一些特定方法要抛出异常或进行处理。构造函数可以接受的参数有(file对象、字符串路径、字节输出流OutputStream/System.out);
|--DataOutputStream(常用)
专门用于操作基本数据类型的输出流,写入文件的全部是二进制表现形式,文件再经过指定编码表解码变成一些对应的字符显示在文件中(一般都是乱码)。
方法:writeUTF():该方法调用的是UTF-8的修改版,一个汉字占4个字节。
字节流和字符流的操作步骤基本一样。
2、问题:字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
答:因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1。那么就出现数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0(通过将读取的原字节数据&255来实现),变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
四、特殊流:RandomAccessFile(特殊类,重点掌握)
特点:该类不是IO体系中子类,而是直接继承自Object,但是它是IO包中成员,因为它具备读和写功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。getFilePointer获取指针位置,seek改变指针的位置。
RandomAccessFile(File file, String mode)
RandomAccessFile(String name, String mode)
通过构造函数可以看出,该类只能操作文件。而且操作文件还有模式(mode):只读r,读写rw,rws和rwd。
模式只读 r:不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。
模式 rw:操作的文件不存在,会自动创建,如果存则不会覆盖。
总结该类三大特点:
1>模式(mode):r、rw、rws、rwd。
2>将读和写操作封装进同一个类中,且可直接读取和写入基本数据类型。writeLong,readLong等。
3>seek(int pointer):同个该方法可以改编指针的位置,实现对指定位置数据的读取和写入操作,但是要对数据分段,即数据要有规律。
如写入:李斯,57
王五,23
张晓轩,32
前2者是有规律(字段大小一样)的数据写入,但是最后一个与前面的不存在规律性。
用法:通过seek设置可以实现多个线程对数据的分段存储而互不干扰(针对同一个文件)。下载文件,就是应用的分段存储原理。
五、字符编码:
编码表:将各个国家的文字用数字来表示,并一一对应,形成一张表。
编码:字符串变成字节数组。OutputStreamWriter
String-->byte[]; str.getBytes(charsetName); charsetName:字符集,即编码表
解码:字节数组变成字符串。InputStreamReader
byte[] -->String: new String(byte[],charsetName);
常见码表:
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表,欧洲码表。用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符,最少用一个字节表示字符。如ASCII码表中的字符。。
注:GBK或UTF-8和ISO8859-1进行可以进行护编解码,但GBK和UTF-8两者不可逆编解码。如:用记事本写“联通”(编码为GBK),记事本会自动调用UTF-8来解码,出现乱码。
六、IO流需求:
1、流操作的基本规律:通过三个明确来完成(重点)。
1>明确源和目的。
源 :输入流:InputStream Reader
目的:输出流:OutputStream Writer。
2>操作的数据是否是纯文本?
是:字符流。
否:字节流。
注:前两用来明确体系。
3>当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分:
源设备 :内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
注意:有时候源和目的可能只有其一。
2、需求
2.1:将一个图片文件中数据存储到另一个文件中,复制文件。要按照以上格式完成三个明确。
分析:这个需求中有源和目的都存在。
1>源:InputStream Reader。
2>因为图片不是纯文本,选择 InputStream。
这样体系就明确了。
3>明确需要使用的对象。
明确设备:硬盘,一张图片。InputStream体系中可以操作文件的对象是 FileInputStream
是否需要提高效率:是!加入InputStream体系中缓冲区 BufferedInputStream.
FileInputStream fis = new FileInputStream("sex.jpg");
BufferedInputStream bufis = new BufferedInputStream(fis);
1>目的:OutputStream Writer
2>不是纯文本!OutputStream。
3>设备:硬盘,一张图片。OutputStream体系中可以操作文件的对象 FileOutputStream。
是否需要提高效率:是!加入OutputStream体系中缓冲区 BufferedOutputStream
FileOutputStream fos = new FileOutputStream。("sex_copy.gif");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
2.2:将键盘录入的数据保存到一个文件中。要按照以上格式完成三个明确。
分析:这个需求中有源和目的都存在。
1>源:InputStream Reader
2>是纯文本:Reader
3>设备:键盘,对应的对象是 System.in.
疑问:不是选择Reader吗?System.in对应的不是字节流吗?
答案:为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的,即将键盘录入的字节流数据转换成字符流来操作。使用了Reader体系中转换流:InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要! BufferedReader
BufferedReader bufr = new BufferedReader(isr);
1>目的:OutputStream Writer
2>是存文本!Writer。
3>设备:硬盘,一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("GBK.txt");
需要提高效率吗?需要! BufferedWriter
BufferedWriter bufw = new BufferedWriter(fw);
***************************
扩展,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
1>目的:OutputStream Writer
2>是存文本!Writer。
3>设备:硬盘,一个文件。使用 FileWriter,但FileWriter使用的默认编码表是GBK,怎么解决?
答案:指定的编码表只有转换流可以指定,所以要使用的对象是 OutputStreamWriter。该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流按指定的编码表输出。使用FileOutputStream创建文件。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF-8.txt"),"UTF-8");
需要高效吗?需要。 BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
注:记住转换流什么使用,字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。
2.3:将一个文本数据打印在控制台上。要按照以上格式完成三个明确。
分析:这个需求中有源和目的都存在。
1>源:InputStream Reader
2>是纯文本!Reader
3>设备:硬盘,文本文件。使用 FileReader.
需要提高效率吗?需要! BufferedReader
FileReader fr = new FileReader("Demo.txt");
BufferedReader bufr = new BufferedReader(fr);
1>目的:OutputStream Writer
2>是纯文本!Writer。
3>设备:控制台,对应的对象是System.out。
为了方便操作,其中可能含有中文字等,所以选择Writer中的转换流 OutputStreanWriter
OutputStreanWriter osw = new OutputStreanWriter(System.out);
需要提高效率吗?需要! BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
七、示例:
示例1:复制一个图片。
通过缓冲区字节数组临时存储,然后在复制,很快。
示例2:将键盘录入的数据保存到一个文件中。
总结:前面提到java中对数据的操作都是通过流的方式,所以这章非常重要,实际开发中都离不开都数据的处理。掌握字节流和字符流的操作步骤,他们之间的转换桥梁:InputStreamReader和OutputStreamWriter。以及字节流和字符流中一些特有的方法,如BufferedReader的特有方法readLine:返回一行,不返回回车符,打印要用println方法,结束标记返回:null。IO流涉及计到的是从内存、硬盘、键盘到内存、硬盘、控制台9种类型操作,一般从硬盘、键盘到硬盘、控制台最寻常。
其次注意RandomAccessFile这个特殊类,是唯一一个同时具备输入输出流的对象的。以及其三大特点,及其应用领域。
一、概念:
(1)用来处理设备(硬盘,控制台,内存)间的数据。
(2)java中对数据的操作都是通过流的方式。
(3)java用于操作流的类都在io包中。
(4)按照流操作的数据的类型不同:分为字节流和字符流。字符流是为了方便中文的操作而来的。
(5)按照流的流向不同分为:输入流,输出流
字符流和字节流(四个抽象基类):
字节流两个基类:InputStream(输入流) OutputStream(输出流)
字符流两个基类:Reader(输入流) Writer(输出流)
二、字符流:
1、结构树:
Reader(read:可以读一个字符或者是读一个字符数组,结束标记返回:-1.要关流)
|--StringReader(操作字符串)
|--CharArrayReader(操作字符数组)(同ByteArrayInputStream,但需要抛异常)
|--PipedReader
|--FilterReader
|--InputStreamReader(常用)
读取转换流:将字节文本转换成字符文本,前提必须接收一个输入字节流对象InputStream
|--FileReader(常用)
|--BufferedReader(特有方法:readLine:返回一行,不返回回车符,打印要用println方法。结束标记返回:null)
|--LineNumberReader(很少)(特有方法:setLineNumber、getLineNumber)
Writer(write:可以写入一个字符或者一个字符数组。写入操作需要刷新flush和关流(关流前会自动刷新一次))
|--StringWriter(操作字符串)
|--CharArrayWriter(操作字符数组)(同ByteArrayOutputStream,但需要抛异常)
|--PrintWriter(常用)
其中有方法:write、print、println、close、flush、append,这些方法都不需要进行处理或抛出异常,方法本身已经覆盖父类方法并且进行了处理。其中只是构造函数和一些特定方法要抛出异常或进行处理。构造函数可以接受的参数有(file对象、字符串路径、字符输出流Writer、字节输出流OutputStream/System.out);
|--FilterWriter
|--OutputStreamWriter(常用)
写入转换流:将字符文本转换成字节文本,前提必须接收一个输出字节流对象OutputStream
|--FileWriter(常用)
|--BufferedWriter(常用)(特有方法:newLine:跨平台换行符)
2、输出(写入)流操作步骤:
1>、FileWriter:
第一步:创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。其实该步就是在明确数据要存放的目的地。 Writer fw = new FileWriter("file.txt"); 第二步:调用write方法,将字符串写入到流中。 fw.write("Hello java!"); 第三部:刷新流对象中的缓冲区中的数据。 fw.flush(); 第四部:关闭流数据,但是关闭前会刷新一次内部的缓冲区中的数据,将数据刷到目的地中。 和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。 fw.close(); 续写方式:传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写。 FileWriter fw1 = new FileWriter("file.txt",true); fw1.write("I think I loved you\r\nthanks..."); //\r\n:Windows系统中的换行符,\n是Linux中的换行符。 fw1.close();
2>、BufferedWriter :
第一步:创建一个字符写入流对象。 FileWriter fw = new FileWriter("buf.txt"); 第二步:为了提高效率加入缓冲技术,将字符写入流对象作为参数传递给缓冲对象的构造函数。 BufferedWriter bufw = new BufferedWriter(fw); for (int i=0; i<5; i++) { bufw.write("abcd"+i); //该写入缓冲区提供了一个跨平台的换行符:newLine() bufw.newLine(); bufw.flush(); //记住只要用到缓冲区,就要记得刷新 } 第三部:关闭缓冲区,就是在关闭缓冲区中的流对象。 bufw.close();
3、输入(读取)流操作步骤:
1>、FileReader:
第一步:创建一个文件读取流对象,和指定名称的文件相关联,要保证该文件是已经促在的,如果不存在,会发生异常:FileNotFoundException Reader r = new FileReader("file.txt"); 第二步:调用读取流对象的read方法。read是一次读一个字符,而且会自动往下读。 方式一:读取单个字符 int len = 0; //r.read()读完后返回-1; while ((len=r.read())!=-1){ System.out.print((char)len); } 方式二:通过定义的字符数组进行读取。定义一个字符数组,用于存储读取到的字符,read(char[])返回的是读取到的字符个数。 FileReader fr = new FileReader("SystemDemo.java"); char[] chs = new char[1024]; len =0; while ((len=fr.read(chs))!=-1) { //new String(chs,0,len):将字符数组chs中角标0到num之间(含头不含尾)的字符封装成字符串。 System.out.print(new String(chs,0,len)); //print:注意不用prinln,避免换行操作。 } 第三步:关闭流。 r.close(); fr.close();
2>、BufferedReader:包括异常处理
public static void main(String[] args) { FileReader fr = null; BufferedReader bufr = null; try{ 第一步:创建一个读取流对象和文件相关联。 fr = new FileReader("Demo.java"); 第二步:为了提高效率加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数。 bufr = new BufferedReader(fr); String line = null; while ((line=bufr.readLine())!=null){ System.out.println(line); } } catch (IOException e){ Date d =new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String s = sdf.format(d); //按sdf的格式格式化时间d的格式。 try{ PrintStream ps = new PrintStream("IOExeception.log"); //创建日志文件 ps.println(s); //将异常发生的时间s写入到日志文件中。 System.setOut(ps); //重新分配”标准“输出设备。 } catch (IOException ex){ throw new RuntimeException("日志文件创建失败"); } e.printStackTrace(System.out); //就异常信息写入到日志文件中 } finally{ try{ if(bufr!=null) bufr.close(); } catch (IOException e){ throw new RuntimeException("读取流关闭失败"); } } }
三、字节流:
1、结构树:
InputStream(read:可以读一个字节或者是读一个字节数组,结束标记返回:-1。available:返回读取文本的字节个数。要关流)
|--ByteArrayInputStream(操作字节数组输入流)
在构造的时候,需要接收数据源,而且数据源是一个字节数组。因为该对象操作的是数组,并没有使用系统资源,所以不用进行close关闭。
|--ObjectInputStream(一般)
方法:readObject(Object obj):读取文件中对象的内容(或值)来直接使用。一次读一个对象,其他方法和ObjectOutputStream都互补。
|--PipedInputStream(一般,比较特殊的流对象)
管道流:输入输出流可以直接进行连接,结合线程来使用。
问题:因为出现多线程,在read方法(阻塞方法,有数据才读,否则等待)执行时可能发生死锁。
构造方法:PipedInputStream(PipedOutputStream src):创建输入流连接到src(输出流)
PipedInputStream():创建尚未连接的管道输入流。
方法:connect(PipedOutputStream src):连接到输出流src,仅用于为创建连接的构造函数。
|--StringBufferInputStream
|--SequenceInputStream(一般)
SequenceInputStream(Enumeration<? extends InputStream> en)
枚举Enumeration是Vector特有的方法,已被ArrayList替换。将多个输入流整合成一个输入流来操作。
构造方法可以接收一个枚举类型的引用,该引用所指向的内容都是InputStream或其子类类型的对象。
|--AudioInputStream
|--FileInputStream(常用)
|--FilterInputStream
|--LineNumberInputStream(前提必须接收一个输入字节流对象InputStream)
|--BufferedInputStream(常用)(同BufferedReader,没有readLine方法)
|--DataInputStream(常用)
专门用于操作基本数据类型的输入流,读取文件的内容全部是二进制表现形式,再经过解码变成我们认识的文字。
方法:readUTF():该方法调用的是UTF-8的修改版,一个汉字占4个字节。
注:read方法和DataOutputStream中的write方法必须匹配,否者读出的数据与来输入数据不一样如writeInt方法必须匹配readInt方法。
OutputStream(write:可以写入一个字节或者一个字节数组。关流)
|--ByteArrayOutputStream(操作字节数组输出流)
在构造的时候,不用定义数据目的,因为该对象已经在内部封装了可变长度的字节数组。
因为该对象操作的是数组,并没有使用系统资源,所以不用进行close关闭。
特有方法:writeTo(OutputStream out):抛IOException,将字节数组输出流的全部内容写入到指定的输出流参数中(文件)。
|--ObjectOutputStream(一般)
几个特别的方法:writeInt:写入文件中的是32位数据,即返回int型,不是字节,操作基本数据类型。
write:写入文件中的是数据的最低8位,即字节。writeLong、writeChar、writeFloat等同理。
writeObject(Object obj):写入文件中的是一个对象包括对象中的数据。
注:被操作的对象需要实现序列化接口Serializable(标记接口:接口中没有方法可覆盖),系统会自定给该类成员变量加上一个UID标记作为序列号,保证其唯一性。static final long serialVersionUID = 51L;
该对象中只有一般成员变量才能被序列化(即存储在堆内存中),放在方法区中的方法和static修饰的成员变量不能被序列化。另外被transient修饰的一般成员变量也不能被序列化。
|--PipedOutputStream(一般,比较特殊的流对象)
|--FileOutputStream(常用)
|--FilterOutputStream
|--BufferedOutputStream(常用)(同BufferedWriter,没有方法newLine)
|--PrintStream(常用)
其中有方法:write、print、println、close、flush、append,这些方法都不需要进行处理或抛出异常,方法本身已经覆盖父类方法并且进行了处理。其中只是构造函数和一些特定方法要抛出异常或进行处理。构造函数可以接受的参数有(file对象、字符串路径、字节输出流OutputStream/System.out);
|--DataOutputStream(常用)
专门用于操作基本数据类型的输出流,写入文件的全部是二进制表现形式,文件再经过指定编码表解码变成一些对应的字符显示在文件中(一般都是乱码)。
方法:writeUTF():该方法调用的是UTF-8的修改版,一个汉字占4个字节。
字节流和字符流的操作步骤基本一样。
2、问题:字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。
答:因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1。那么就出现数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0(通过将读取的原字节数据&255来实现),变成了int类型的数值。
而在写入数据时,只写该int类型数据的最低8位。
四、特殊流:RandomAccessFile(特殊类,重点掌握)
特点:该类不是IO体系中子类,而是直接继承自Object,但是它是IO包中成员,因为它具备读和写功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。getFilePointer获取指针位置,seek改变指针的位置。
RandomAccessFile(File file, String mode)
RandomAccessFile(String name, String mode)
通过构造函数可以看出,该类只能操作文件。而且操作文件还有模式(mode):只读r,读写rw,rws和rwd。
模式只读 r:不会创建文件,会去读取一个已存在文件,如果该文件不存在,则会出现异常。
模式 rw:操作的文件不存在,会自动创建,如果存则不会覆盖。
总结该类三大特点:
1>模式(mode):r、rw、rws、rwd。
2>将读和写操作封装进同一个类中,且可直接读取和写入基本数据类型。writeLong,readLong等。
3>seek(int pointer):同个该方法可以改编指针的位置,实现对指定位置数据的读取和写入操作,但是要对数据分段,即数据要有规律。
如写入:李斯,57
王五,23
张晓轩,32
前2者是有规律(字段大小一样)的数据写入,但是最后一个与前面的不存在规律性。
用法:通过seek设置可以实现多个线程对数据的分段存储而互不干扰(针对同一个文件)。下载文件,就是应用的分段存储原理。
五、字符编码:
编码表:将各个国家的文字用数字来表示,并一一对应,形成一张表。
编码:字符串变成字节数组。OutputStreamWriter
String-->byte[]; str.getBytes(charsetName); charsetName:字符集,即编码表
解码:字节数组变成字符串。InputStreamReader
byte[] -->String: new String(byte[],charsetName);
常见码表:
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
ISO8859-1:拉丁码表,欧洲码表。用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符,最少用一个字节表示字符。如ASCII码表中的字符。。
注:GBK或UTF-8和ISO8859-1进行可以进行护编解码,但GBK和UTF-8两者不可逆编解码。如:用记事本写“联通”(编码为GBK),记事本会自动调用UTF-8来解码,出现乱码。
六、IO流需求:
1、流操作的基本规律:通过三个明确来完成(重点)。
1>明确源和目的。
源 :输入流:InputStream Reader
目的:输出流:OutputStream Writer。
2>操作的数据是否是纯文本?
是:字符流。
否:字节流。
注:前两用来明确体系。
3>当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分:
源设备 :内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
注意:有时候源和目的可能只有其一。
2、需求
2.1:将一个图片文件中数据存储到另一个文件中,复制文件。要按照以上格式完成三个明确。
分析:这个需求中有源和目的都存在。
1>源:InputStream Reader。
2>因为图片不是纯文本,选择 InputStream。
这样体系就明确了。
3>明确需要使用的对象。
明确设备:硬盘,一张图片。InputStream体系中可以操作文件的对象是 FileInputStream
是否需要提高效率:是!加入InputStream体系中缓冲区 BufferedInputStream.
FileInputStream fis = new FileInputStream("sex.jpg");
BufferedInputStream bufis = new BufferedInputStream(fis);
1>目的:OutputStream Writer
2>不是纯文本!OutputStream。
3>设备:硬盘,一张图片。OutputStream体系中可以操作文件的对象 FileOutputStream。
是否需要提高效率:是!加入OutputStream体系中缓冲区 BufferedOutputStream
FileOutputStream fos = new FileOutputStream。("sex_copy.gif");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
2.2:将键盘录入的数据保存到一个文件中。要按照以上格式完成三个明确。
分析:这个需求中有源和目的都存在。
1>源:InputStream Reader
2>是纯文本:Reader
3>设备:键盘,对应的对象是 System.in.
疑问:不是选择Reader吗?System.in对应的不是字节流吗?
答案:为了操作键盘的文本数据方便,转成字符流按照字符串操作是最方便的,即将键盘录入的字节流数据转换成字符流来操作。使用了Reader体系中转换流:InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要! BufferedReader
BufferedReader bufr = new BufferedReader(isr);
1>目的:OutputStream Writer
2>是存文本!Writer。
3>设备:硬盘,一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("GBK.txt");
需要提高效率吗?需要! BufferedWriter
BufferedWriter bufw = new BufferedWriter(fw);
***************************
扩展,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
1>目的:OutputStream Writer
2>是存文本!Writer。
3>设备:硬盘,一个文件。使用 FileWriter,但FileWriter使用的默认编码表是GBK,怎么解决?
答案:指定的编码表只有转换流可以指定,所以要使用的对象是 OutputStreamWriter。该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流按指定的编码表输出。使用FileOutputStream创建文件。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF-8.txt"),"UTF-8");
需要高效吗?需要。 BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
注:记住转换流什么使用,字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。
2.3:将一个文本数据打印在控制台上。要按照以上格式完成三个明确。
分析:这个需求中有源和目的都存在。
1>源:InputStream Reader
2>是纯文本!Reader
3>设备:硬盘,文本文件。使用 FileReader.
需要提高效率吗?需要! BufferedReader
FileReader fr = new FileReader("Demo.txt");
BufferedReader bufr = new BufferedReader(fr);
1>目的:OutputStream Writer
2>是纯文本!Writer。
3>设备:控制台,对应的对象是System.out。
为了方便操作,其中可能含有中文字等,所以选择Writer中的转换流 OutputStreanWriter
OutputStreanWriter osw = new OutputStreanWriter(System.out);
需要提高效率吗?需要! BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
七、示例:
示例1:复制一个图片。
通过缓冲区字节数组临时存储,然后在复制,很快。
public static void copy throws IOException { FileInputStream fis = new FileInputStream("m.jpg"); FileOutputStream fos = new FileOutputStream("m_copy.gif"); byte[] by = new byte[1024]; int len = 0; //字节数组的有效长度 while ((len=fis.read(by))!=-1) { fos.write(by,0,len); } fis.close(); fos.close(); }
示例2:将键盘录入的数据保存到一个文件中。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); 扩展:按照指定的编码表将录入数据存入文件中,OutputStreamWriter具备此功能 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("UTF-8.txt"),"UTF-8")); String line = null; while ((line=bufr.readLine())!=null) { if ("over".equals(line)) //输入over为结束符 break; bufw.write(line); //将键盘录入的数据写入输出流的缓冲区中 bufw.newLine(); bufw.flush(); //刷新缓冲区 } bufr.close(); bufw.close();
总结:前面提到java中对数据的操作都是通过流的方式,所以这章非常重要,实际开发中都离不开都数据的处理。掌握字节流和字符流的操作步骤,他们之间的转换桥梁:InputStreamReader和OutputStreamWriter。以及字节流和字符流中一些特有的方法,如BufferedReader的特有方法readLine:返回一行,不返回回车符,打印要用println方法,结束标记返回:null。IO流涉及计到的是从内存、硬盘、键盘到内存、硬盘、控制台9种类型操作,一般从硬盘、键盘到硬盘、控制台最寻常。
其次注意RandomAccessFile这个特殊类,是唯一一个同时具备输入输出流的对象的。以及其三大特点,及其应用领域。
相关文章推荐
- 黑马程序员-IO流操作规则
- 黑马程序员 Java面向对象——IO流(字节流缓冲区)
- 黑马程序员——Java基础--------IO流(一)
- 黑马程序员——JAVA笔记之IO流(二)
- 黑马程序员_学习笔记第17天——IO流、字符流
- 黑马程序员-------IO流
- 黑马程序员——Java基础---异常、IO流
- 黑马程序员--第二十天:io流的第三天
- 黑马程序员——IO流(一)
- 黑马程序员-java基础(七)-IO流
- 黑马程序员——Java基础——IO流(上)
- 黑马程序员_IO流(一)
- 黑马程序员_毕向东JAVA基础_IO流(一)
- 黑马程序员_温习 IO流五 (个人笔记)摘要(字符编码)
- 黑马程序员---黑马IO流学习笔记
- 黑马程序员——Java之IO流(一)
- 黑马程序员---IO流
- 黑马程序员——Java IO流
- 黑马程序员 IO流(二)
- 黑马程序员 IO流 流操作的基本规律