副标题#e#
11.3.4 留意问题
上面先容了IO类的根基利用,熟悉了实体流和装饰流的根基利用,可是在IO类实际利用时,照旧会碰着一系列的问题,下面先容一些大概会常常碰着的问题。
11.3.4.1 类的选择
对付初次打仗IO技能的初学者来说,IO类体系博大博识,类的数量较量复杂,在实际利用时常常会无所适从,不知道该利用那些类举办编程,下面先容一下关于IO类选择的一些能力。
选择类的第一步是选择符合的实体流。
选择实体流时第一步是凭据毗连的数据源种类举办选择,譬喻读写文件应该利用文件流,如FileInputStream/FileOutputStream、FileReader/FileWriter,读写字节数组应该利用字节数组流等,如ByteArrayInputStream/ByteArrayOutputStream。
选择实体流时第二步是选择符合偏向的流。譬喻举办读操纵时应该利用输入流,举办写操纵时应该利用输出流。
选择实体流时第三步是选择字节约或字符流。除了读写二进制文件,或字节约中没有对应的流时,一般都优先选择字符流。
颠末以上步调今后,就可以选择到符合的实体流了。下面说一下装饰流的选择问题。
在选择IO类时,实体流是必须的,装饰流是可选的。别的在选择流时实体流只能选择一个,而装饰流可以选择多个。
选择装饰流时第一步是选择切合要求成果的流。譬喻需要缓冲流的话选择BufferedReader/BufferedWriter等,有些时候也大概只是为了利用某个装饰流内部提供的要领。
选择装饰流时第二步是选择符合偏向的流,这个和实体流选择中的第二步一致。
当选择了多个装饰流今后,可以利用流之间的多层嵌套实现要求的成果,流的嵌套之间没有顺序。
11.3.4.2 非依次读取流数据
由于IO类设计的特点,在实际读取时,只能依次读取流中的数据,并且在凡是环境下,已经读取过的数据无法再举办读取。假如需要反复读取流中某段数据时,一般的做法是将从流中读取的数据利用数组存储起来,然后按照需要读取数组中的内容即可,可是有些时候,照旧有一些非凡的环境的,IO类对付这些都举办了支持。
1、中断性的读取流中的数据
对付某些非凡名目标文件,譬喻字体文件等,在实际读取数据时不需要顺序举办读取,而只需要按照内容的位置举办读取。这样可以利用流中的skip要领实现。譬喻:
int n = fis.skip(100);
该行代码的浸染是,以流fis当前位置为基本,当前位置可以是流中的任何位置,向后跳过100个单元(字节约单元为字节,字符流单元是字符),假如再利用read要领继承读取,就是读取跳跃今后新位置的内容,也就相当于跳过了100个单元的内容。
而实际在利用时,实际真正跳过的单元数量作为skip要领的返回值返回。
#p#副标题#e#
2、反复读取流中某段数据
当必需反复读取流中同一段数据时,假如对应的流支持mark(标志)的话,则可以反复读取同一段数据。
下面以反复读取节制台输入流System.in为例子,来先容mark的利用,示例代码如下:
import java.io.*;
/**
* mark利用示例
*/
public class MarkUseDemo {
public static void main(String[] args) {
byte[] b = new byte[1024];
try{
//读取数据
int data = System.in.read();
//输出第一个字节的数据
System.out.println("第一个字节:" + data);
//判定该流是否支持mark
if(System.in.markSupported()){
//影象当前位置,可以从当前位置
//向后最多读取100个字节
System.in.mark(100);
//读取数据
int n = System.in.read(b);
//输出读取到的内容
System.out.print("第一次读取到的内容:");
for(int i = 0;i < n;i++){
System.out.print(b[i] + " ");
}
System.out.println();
//回到标志位置
System.in.reset();
//反复读取标志位置今后的内容
n = System.in.read(b);
//输出读取到的内容
System.out.print("第二次读取到的内容:");
for(int i = 0;i < n;i++){
System.out.print(b[i] + " ");
}
System.out.println();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
在该示例中,首先挪用System.in流中的read要领,读取流中的第一个字节,并把读取到的数据赋值给data,然后将读取到的第一个字节的数据输出出来。
然后挪用System.in流中的markSupported判定该流是否支持mark成果,假如支持的话则markSupported要领将返回true。
#p#分页标题#e#
假如流System.in支持mark,则标志当前位置,并答允从当前位置开始最多读取后续100个字节的数据,其实IO类内部的只读取这些数据,而不真正从流中将这些数据删除。
后续继承读取流中的数据,假如读取的数据高出100个字节,则mark标志失效,并把读取到的有效数据输出到节制台。
假如需要从标志位置反复读取已经读取过的数据,则只需要挪用流工具中的reset要领重置流的位置,使流可以回到mark的位置,假如继承读取的话,则从该位置开始可以向后读取。这样就可以从mark的位置开始,再次读取后续的数据了。
譬喻在节制台输入123456789,则该措施的执行功效是:
第一个字节:49
第一次读取到的内容:50 51 52 53 54 55 56 57 13 10
第二次读取到的内容:50 51 52 53 54 55 56 57 13 10
个中输入的第一个字节是1,读取时该字符的编码是49,尔后续的内容就是流的布局,个中流末端的13和10是在输入时,添加的回车和换行字符。
11.3.4.3 中文问题
由于JDK设计时,对付国际化支持较量好,所以JDK在实际实现时支持许多的字符集,这样在举办特定字符集的处理惩罚时就需要出格小心了。
其实在举办中文处理惩罚时,只需要留意一个原则就可以了,这个原则就是将中文字符转换为byte数组时利用的字符集,需要和把byte数组转换为中文字符串时的字符集保持一致,这样就不会呈现中文问题了。
虽然,假如不想手动实现字符串和byte数组的转换,可以利用DataInputStream和DataOutputStream中的readUTF和writeUTF实现读写字符串。
11.4 总结
关于IO类的利用,还需要在实际开拓进程中多举办利用,从而更深入的体会IO类设计的初志,并把握IO类的利用。
别的,IO类是Java中举办网络编程的基本,所以熟悉IO类的利用也是进修网络编程必需的一个基本。