JAVA学习之节点流和过滤流

节点流

文件节点流

FileInputStream FileOutputStream 是文件字节流,是一种节点流
文件字节输入流的构造方法:
  • FileInputStream("文件名称"),如果文件不存在则FileNotFoundException
  • FileInputStream(File)
文件字节输出流的构造方法 :
  • FileOutputStream(“文件名称”) 如果文件不存在则新建文件,如果文件存在则覆盖文件内容
  • FileOutputStream(String name文件名称, boolean append是否采用追加方式)
FileReader FileWriter 类似
FileInputStream FileOutputStream 两个类属于结点流,第一个类的源端和第二个类的目的端都是磁盘文件,它们的构造方法允许通过文件的路径名来构造相应的流。
如:
FileInputStream infile = new FileInputStream("myfile.dat");
FileOutputStream outfile = new FileOutputStream("results.dat");
要注意的是,构造 FileInputStream, 对应的文件必须存在并且是可读的,而构造 FileOutputStream 时,如输出文件已存在,则必须是可覆盖的。
要求:将 d 盘上的 TestFile.java 拷贝到 e 盘,并命名为 dd.txt
try (InputStream is = new FileInputStream("d:/TestFile.java"); 
        OutputStream os=new FileOutputStream("e:\\dd.txt"); ) {
        byte[] buffer=new byte[8192]; int len=is.read(buffer);
        while(len>0){ 
            os.write(buffer,0,len); 
            len=is.read(buffer); 
        } 
     }catch(IOException e){
            e.printStackTrace(); 
     }
构造输出文件流时可以使用两种不同的方式 
OutputStream os=new FileOutputStream("e:\\dd.txt"); 如果文件不存在则自动创建;
如果文件存在则进行覆盖 OutputStream os=new FileOutputStream("e:\\dd.txt",true),这里的boolean类型参数 
表示是否采用追加的方式写入文件

内存数组节点

如果文本则使用 char[] ,如果二进制则使用 byte[]
构造器方法
  • CharArrayReader(char[] buf)其中char[]就是数据的来源,也就是说Reader就是从char[]中读取数
  • CharArrayRead(char[] buf, int offset, int length)

CharArrayWriter用于实现向一个字符数组中写入数据,这个数组可以自动调整大小

ByteArrayInputStream ByteArrayOutputStream CharArrayReader 以及 CharArrayWriter 类似,支持操作的内容不同而已,操作 byte[] char[]

 

内存字串流

StringReader 用于从一个字串 String 中读取数据
String str="亚洲说:‘我爱小黑’"; 
StringReader sr=new StringReader(str); 
int cc; 
while((cc=sr.read())!=-1) 
    System.out.print((char)cc); 
sr.close();
StringWriter 用于给一个 StringBuffer 中写入数据,实现一个可边长的字串
Scanner sc=new Scanner(System.in); 
try(
    StringWriter sw=new StringWriter(); 
    Writer fw=new FileWriter("c:/console.txt") 
){ 
    String temp=sc.nextLine(); 
    while(!temp.equals("quit")){ 
          if(temp!=null && temp.trim().length()>0) 
              sw.write(temp+"\n");
          temp=sc.nextLine(); 
    }
    fw.write(sw.toString()); 
}

总结

  • 读写文件使用节点流FileInputStream/FileOutputStreamFileReader/FileWriter,如果操作文本文件,建议使用FileReader/FileWriter,如果操作二进制文件建议使用FileInputStream/FileOutputStream
  • 需要建立缓冲区(建立临时文件的方式效率低),可以考虑使用内存节点,例如 CharArrayReader/CharArrayWriterStringReader/StringWriterByteArrayInputStream/ByteArrayOutputStream
  • 如果需要一个二进制缓冲区可以使用ByteArrayInputStream/ByteArrayOutputStream,如果需要一个字符缓存可以使用CharArrayReader/CharArrayWriterStringReader/StringWriter
  • 如果数据量不是特别大使用CharArrayReader/CharArrayWriter更为方便,如果数据量大而且可能需要直接操作缓冲区则使用StringReader/StringWriter
  • StringWriter中提供了方法getBuffer():StringBuffer

过滤流类型

过滤流就是在节点流的基础上附加功能

过滤流

就是 decorate 模式中的抽象装饰角色
FilterInputStream/FilterOutputStream FilterReader/FilterWriter
public class FilterInputStream extends InputStream { //典型的装饰模式 
      protected volatile InputStream in; //被装饰目标 
      protected FilterInputStream(InputStream in) { //通过构造器组装被装饰对象 
         this.in = in; 
      }
      public int read() throws IOException {//调用Filter中的read方法时实际操作是由被装饰对象实现的 
      return in.read(); 
     } 
}
所谓的过滤流实际上就是类似上面的加密处理,在输入之后(后置处理,被装饰对象先执行)或者输出之前(前置处理,先处理然后被装饰对象执行)进行一下额外的处理,最终实际操作是调用被装饰对象 的方法完成工作,依靠这种装饰模式实现在节点流的基础上附加额外功能 . 当然也允许多个过滤流嵌套从 而达到功能累加的目的
FilterInputStream 实际上就是一个装饰抽象角色
自定义流实现循环 13 加密 :
读取数据不变 :FileReader---BufferedReader
写出数据自定义过滤流 SecurityWriter(FilterWriter)
public class SecurityWriter extends FilterWriter { 
      protected SecurityWriter(Writer out) { 
          super(out); 
      }
      public void write(int c) throws IOException { 
           if (c >= 'a' && c <= 'z') { 
               c = (c - 'a' + 13) % 26 + 'a'; 
           } else if (c >= 'A' && c <= 'Z') { 
               c = (c - 'A' + 13) % 26 + 'A'; 
           }super.write(c); 
      } 
}
public class SecurityReader extends FilterReader { 
       protected SecurityReader(Reader in) { 
           super(in); 
       }public int read() throws IOException { 
            int c = super.read(); 
            if (c >= 'a' && c <= 'z') { 
                c = (c - 'a' + 13) % 26 + 'a'; 
            } else if (c >= 'A' && c <= 'Z') { 
                c = (c - 'A' + 13) % 26 + 'A'; 
            }
            return c;
       }
} 
 

桥接转换流

InputStreamReader OutputStreamWriter java.io 包中用于处理字符流的最基本的类,用来在字节流和字符流之间作为中介:从字节输入流读入字节,并按编码规范转换为字符;往字节输出流写字符时 先将字符按编码规范转换为字节。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范, 以便把以字节方式表示的流转换为特定平台上的字符表示。
转换流可以在构造时指定其编码字符集
InputStreamReader 用于将一个 InputStream 类型的输入流自动转换为 Reader 字符流
OutputStreamWriter 用于将一个 Writer 字符输出流转换为 OutputStream 字节输出流

InputStreamReader构造器

  • InputStreamReader(InputStream)
  • InputStreamReader(InputStream, String)
  • InputStreamReader(InputStream, Charset)
  • InputStreamReader(InputStream, CharsetDecorder)
Reader r=new InputStreamReader(System.in); 
int kk=r.read(); //例如输入的是“中国”,这里实际读取的是"中" 
//因为这里读取的是一个字节,所以输入"中国",实际读取的是"中"的一个字节,输出显示为?
 kk=System.in.read(); 
System.out.println("输入的是:"+(char)kk);
InputSteram is=new InputStreamReader(System.in,”iso8859-1”);
Reader r=new InputStreamReader(System.in, "gbk"); 
int kk=r.read();//例如输入的是"中国",实际读取的是"中" 
System.out.println("输入的是:"+(char)kk);
注意:一般不建议自行设置编码字符集,除非是必须的

缓冲流

缓冲流是套接在响应的节点流之上,对续写的数据提供缓冲的功能,提高读写的效率,同时增加了一些新方法
以介质是硬盘为例,字节流和字符流的弊端:在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。为了解决以上弊端,采用缓存流
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。
InputStream is = new FileInputStream("d:\\FileTest.java"); 
long start=System.currentTimeMillis();//获取从1970-1-1 0:0:0到当前的毫米值 
int con = is.read(); 
while (con != -1) { 
       System.out.write(con); 
       con = is.read(); 
}
long end=System.currentTimeMillis(); 
is.close(); 
System.out.println("统计时间为:"+(end-start)+"ms"); 
60ms

构造方法

  • BufferedReader(Reader)不定义缓存大小,默认8192
  • BufferedReader(Reader in, int size)size为自定义缓冲区的大小
  • BufferedWriter(Writer)
  • BufferedWriter(Writer out, int size)size为自定义缓冲区的大小
  • BufferedInputStream(InputStream)
  • BufferedInputStream(InputStream in, int size)size为自定义缓冲区的大小
  • BufferedOutputStream(OutputStream)
  • BufferedOutputStream(OuputStream out, int size)size为自定义缓冲区的大小
InputStream is = new BufferedInputStream(new 
FileInputStream("d:\\FileTest.java")); 
long start=System.currentTimeMillis(); 
int con = is.read();//这里并不是直接从文件中进行读取,而是从缓存中进行读 
while (con != -1) { 
       System.out.write(con); 
       con = is.read(); 
}
long end=System.currentTimeMillis(); 
is.close(); 
System.out.println("统计时间为:"+(end-start)+"ms"); 
is.close(); 
10ms

缓冲输入流的方法

BuffedReader 提供了一个方法 readLine():String ,但是 BufferedInputStream 中并没有这个
  • BufferedReader提供了readLine方法用于读取一行字符串,以\r\n分割(换行符)
  1. 如果读取内容为null,则表示读取到了流的末尾
  2. readLine方法会自动剔除本行内容末尾的换行符
  • BufferedWriter提供了newLine方法用于写入一个行分隔符
对于输出的缓冲流,写入的数据会先在内存中缓存,使用 flush 方法会使内存中的数据立即写出

键盘录入

System.in:InputStream 用于指代系统默认的输入设备 键盘
方法 read():int 可以实现代码执行到这里则会阻塞等待,只要输入数据为止
BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
System.out.println("输入数据"); 
String temp=""; 
while((temp=br.readLine()).trim().length()>0){ 
       if("quit".equals(temp)) 
            break; 
       System.out.println(temp); 
}
br.close();
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); 
bw.write("只有缓冲区满才自动进行输出显示"); 
bw.flush(); //刷新缓冲区,否则看不到输出内容 
System.in.read(); 
bw.close(); //关闭输出时会首先自动进行刷新缓冲区

数据流

DataInputStream DataOutputStream 两个类创建的对象分别被称为数据输入流和数据输出流。这是很有用的两个流,它们允许程序按与机器无关的风格读写 Java 数据。所以比较适合于网络上的数据传 输。这两个流也是过滤器流,常以其它流如 InputStream OutputStream 作为它们的输入或输出
DataInputStram DataOutputStream 分别继承自 InputStream OuputStream ,属于过滤流,需要分 别套接在 InputStream OutputStream 类型的节点流上
  • 只有字节流,没有对应的字符流
DataInputStream DataOutputStream 提供了可以存取与机器无关的 Java 原始类型数据的方法
DataInputSteram DataOutputStream 构造方法为
  • DataInputStream(InputStream)
  • DataOutputStream(OutputStream)
1 、用数据输出流将菲波那契级数的前二十项存放在 fei.dat 文件中。
2 、从 fei.dat 文件中读出数列,显示输出,并计算累加和。
读取、写出一个 double 数据到文件中
//使用数据流就可以直接操作简单类型数据 
double dd=123.4567; 
FileOutputStream fos=new FileOutputStream("d:\\a.data"); 
fos.write((dd+"").getBytes()); 
fos.close(); 
//如果不使用数据流,则需要额外编码进行数据类型转换 
FileInputStream fis=new FileInputStream("d:/a.data"); 
byte[] buffer=new byte[8192]; 
int len=fis.read(buffer); 
fis.close(); 
String str=new String(buffer,0,len); 
double dd=Double.parseDouble(str); 
System.out.println(dd);
加入需要写一个 double ,然后一个 String ,然后再一个 int
需要将输入内容转换为 String ,并且为了区分数据需要引入特殊符号,例如 @@ ,输入数据为
123.456@@shi ya zhou@@12 。从功能角度上说没问题,但是编码太复杂了,所以引入 Data 类型的输入输出流
//这里不使用OutputStream定义变量的原因是:需要使用DataOutputStream中定义的特殊方法,而不是父类中定义的通用方法 
DataOutputStream dos=new DataOutputStream(new 
FileOutputStream("d:\\a.data")); 
dos.writeDouble(123.456); 
dos.writeChars("赵天爱小猴!"); 
dos.writeInt(12); 
dos.close();
由于读取出现问题,针对中间的 String 数据引入一个额外的数据,其中存储 String char 个数
写出数据
double salary=123.456; 
String ss="赵天爱小猴,小猿爱小主,小胡招小天"; 
int age=12; 
DataOutputStream dos=new DataOutputStream(new BufferedOutputStream(new 
FileOutputStream("d:\\aa.data"))); 
dos.writeDouble(salary); 
dos.writeInt(ss.length()); 
dos.writeChars(ss); 
dos.writeInt(age); 
dos.close();
读取数据
double salary=0; String str=""; 
int age=0; 
//读取数据的前提是必须知道数据的结构 
DataInputStream dis=new DataInputStream(new BufferedInputStream(new 
FileInputStream("d:\\aa.data"))); 
salary=dis.readDouble(); 
StringBuilder sb=new StringBuilder(); 
int len=dis.readInt(); 
for(int i=0;i<len;i++) 
sb.append(dis.readChar()); 
str=sb.toString(); 
age=dis.readInt(); 
System.out.println(salary+"---"+str+"---"+age);
注意:读取数据判断文件结束 EOFException ,这里没有 -1
在具体应用中建议针对字串使用 readUTF writeUTF
DataOutputStream dos=new DataOutputStream(new FileOutputStream("data2.txt")); 
dos.writeDouble(1234.56); 
String str="猴子愛小終,小終愛信心"; 
dos.writeUTF(str); 
dos.writeInt(99); 
dos.close();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值