IO流总结

  • Post author:
  • Post category:其他





一:IO流概念:


1、IO流:即InputOutput的缩写。


2、特点:


1)IO流用来处理设备间的数据传输。


2)Java对数据的操作是通过流的方式。


3)Java用于操作流的对象都在IO包中。


4)流按操作数据分为两种:字节流和字符流。


5)流按流向分为:输入流和输出流。


注意:流只能操作数据,而不能操作文件。


3、IO流的常用基类:


1)字节流的抽象基流:InputStream和OutputStream


2)字符流的抽象基流:Reader和Writer





二、IO流中重要概念




1、根据处理的数据不同;分为:字节流和字符流。


所有的数据都是以字节体现的;后期产生了字符流。


因为字符数据涉及到了编码问题;所以在字符流对象中加入了编码机制。


字符流体系中:有两个基类。


Reader


Writer


2、字符流的缓冲区:是为了提高效率而存在。



BufferedWriter、

BufferedReader


缓冲区提供了比以前流对象功能更强的函数。





3、装饰设计模式


装饰设计模式是一种解决某一类问题的思想;该类问题的有效解决方案。解决给类提供增强型功能的问题。


示例:


class Person{
       void chi(){
              System.out.println("chifan");
       }
}
class NewPerson //装饰Person对象的类。称为装饰类,只为增强Person的功能而出现。
{
       private Person p;
       NewPerson(Person p){
              this.p = p;
       }
       void newChi(){
              System.out.println("来一杯");
              p.chi();
              System.out.println("甜点");
              System.out.println("来一根");
       }
}
class  PersonDemo{
       public static void main(String[] args) {
              Person p = new Person();
              p.chi();
//           NewPerson np = new NewPerson(p);
//           np.newChi();
       }
}


当对类的功能进行增强时,可称之为对该类的装饰。


同时它的出现具备灵活性。


Writer


|–TextWriter


|–MediaWirter


该体系的出现已经可以完成对文本数据和媒体数据的写操作。


但是发现。效率较低。为了提高效率,就加入了缓冲技术。


|–文本写入需要缓冲


|–媒体写入需要缓冲


按照面向对象的思想,为了提高扩展,通过继承的方式完成。


Writer


|–TextWriter


|–BufferedTextWriter


|–MediaWirter


|–BufferedMedieWriter


这就完成了文本和媒体数据写操作效率提高。


当该体系加入一个子类 BaseWriter,而且该子类也许要效率提高。


Writer


|–TextWriter


|–BufferedTextWriter


|–MediaWirter


|–BufferedMedieWriter


|–BaseWriter


|–BufferedBaseWriter


如果体系扩展,都需要定义一个该子类具备高效缓冲功能的子类。


这样做体系扩展很麻烦;解决办法及优化如下:


我们发现,这些子类使用的缓冲技术都是一样的;缓冲区其实就是定义了临时存储容器将数据进行临时缓冲,


至于具体的写操作,还是Writer的子类对象完成的,比如 TextWriter. MediaWriter等。


所以:我们将缓冲技术单独封装成一个对象,要对哪个具体对象进行缓冲技术的使用,只要将该对象传递给缓冲区对象即可。

/对缓冲区对象进行单独描述。
classBufferedWriter extends Writer{
       BufferedWriter(Writer w){
       }
//    BufferedWriter(TextWriter tw)
//    {}
//    BufferedWriter(MediaWriter dw)
//    {}
}


当缓冲技术单独封装成了对象后,它具备的还是写功能,只不过可以其他对象的写功能进行高效。


所以它还是Writer类中的一员。


所以这时体系变成了


Writer


|–TextWriter


|–MediaWirter


|–BufferedWriter:这是一个提供增强功能的类。就把这种优化方式,定义成一种最终的解决该问题的解决方案


并起个名字:装饰设计模式。


和原来的体系,变的很清爽。


Writer


|–TextWriter


|–BufferedTextWriter


|–MediaWirter


|–BufferedMedieWriter


装饰设计模式的出现可以对一组类进行功能的增强;而且装饰类本也是该体系中的一个子类。


代码体现:


通常情况下,


装饰类一般不单独存在,


都是通过构造函数接收被装饰的对象,


基于被装饰的对象的功能,并对外提供增强行的功能。


装饰

设计

模式和继承的区别:


继承会让体系变得臃肿,


装饰更为灵活。


在IO中装饰设计模式用的很多。


比如:


BufferedWriter


BufferedReader


明确了BufferedReader是一个装饰类后,发现它有一个增强的功能,readLine。


而且readLine的原理是:调用基础流对象的read方法,一次读一个字符,并把该字符进行了临时存储。直到读到回车换行符为止,将存储的数据作为字符串返回。


定义一个装饰类实现一次读一行的功能如下代码:(供参考)

import java.io.*;
classMyBufferedReader //extends Reader//自定义装饰类,模拟BufferedReader{
       private Reader r;
       MyBufferedReader(Reader r){
              this.r = r;
       }
       //读一行的方法。
       public String myReadLine()throwsIOException{
              StringBuilder sb = new StringBuilder();
              int ch = 0;
              while((ch=r.read())!=-1){
                     if(ch=='\r')
                            continue;
                     if(ch=='\n')
                            returnsb.toString();
                     else
                            sb.append((char)ch);
              }
              if(sb.length()!=0)
                     return sb.toString();
              return null;
       }
       public void myClose()throws IOException{
              r.close();
       }
}



4、字节流


InputStream


OutputStream


通过一个字节流示例记住

class  FileOutputStreamDemo{
       public static void main(String[] args)throws IOException{
              FileOutputStream fos = newFileOutputStream("fos.txt");
              byte[] buf ="abcedf".getBytes();
              fos.write(buf);//字节流的写入方法,直接将数据写到了目的地。因为该对象中不存在缓冲区。
              fos.close();//关闭资源。
       }
}


5、字符流和字节流的关系:


字符流:


FileReader


FileWriter


BufferedReader


BufferedWriter


字节流:


FileInputStream


FileOutputStream


BufferedInputStream


BufferedOutoutStream


通过转换流将两个流进行关联起来的:


InputStreamReader:字节流通向字符流的桥梁


OutputStreamWriter:字符流通向字节流的桥梁


流的操作规律:因为io包中的对象很多,最重要的是要知道完成数据处理是,要使用哪个对象最合适。


如何判断要使用哪些对象呢?


通过几个明确来判断对象的使用:


1,明确数据源,和 数据目的(数据汇)


数据源:InputStream   Reader


数据目的:OutputStream  Writer


2,明确数据的内容是否是纯文本。只要是纯文本数据,就使用字符流。


数据源: 是: Reader。


数据目的:是:Writer


如果不是,就使用InputStream或者OutputStream


如果数据不能明确,只有使用字节流。


这样就可以将四个基类,进行确定,要使用哪一个。


3,明确具体设备。


数据源:键盘(System.in) ,内存(数组), 硬盘(File开头的流对象)。


数据目的: 控制台(System.out),内存(数组),硬盘(File开头的流对象)。


4,明确是否需要提高效率?


是:使用带Buffer对象。


5,是否需要一些特殊场景的操作,来完成数据的特殊处理。


举例1:复制一个文本文件。


1,数据源:InputStream,Reader


数据目的:OutputStream ,Writer


2,是否是纯文本。


是。


数据源:Reader


数据目的:Writer


3,明确设备:


数据源:是一个文件,硬盘设备。 FileReader


数据目的:是一个文件。硬盘设备。 FileWriter.


代码就已经出来了。


FileReader fr = newFileReader(“a.txt”);


FileWriter fw = newFileWriter(“b.txt”);


4,需要高效吗?


需要。


FileReader fr = newFileReader(“a.txt”);


BufferedReader bufr  = new BufferedReader(fr);


FileWriter fw = newFileWriter(“b.txt”);


BufferedWriter bufw = newBufferedWriter(fw);


举例2:将键盘录入的数据存储到一个文件中。


1,数据源:InputStrea,Reader


数据目的:OutputStream ,Writer


2,是否是纯文本?


是。


数据源:Reader


数据目的:Writer.


3,设备:


数据源:System.in;为了方便于操作数据源的字节数据,对其进行转换。使用转换流。


数据目的:硬盘文件。FileWriter.


发现一个问题,就是数据源是一个字节流。


因为纯文本使用字符流操作最方便,


所以,将数据源设备对应的字节流转成字符流。


InputStreamReader isr = newInputStreamReader(System.in);


FileWriter fw = newFileWriter(“a.txt”);


4,需要高效吗?需要。


BufferedReader bufr = newBufferedReader(new InputStreamReader(System.in));


BufferedWriter bufw = newBufferedWriter(new FileWriter(“a.txt”));


举例3:将一个文本文件打印到控制台


1,数据源:InputStrea,Reader


数据目的:OutputStream ,Writer


2,是否是纯文本?


是。


数据源:Reader


数据目的:Writer.


3,数据源:硬盘文件 FileReader


数据目的:控制台 System.out.因为目的是字节流,而操作的是字符流,所以要将字符流转成字节流到目的中。


使用到了转换流。 OutoutStreamWriter


FileReader fr = newFileReader(“a.txt”);


PrintStream ps = System.out;


FileReader fr= newFileReader(“a.txt”);


OutputStreamWriter osw = newOutputStreamWriter(System.out);


需要缓冲高效吗?需要。


BufferedReader bufr = newBufferedReader(new FileReader(“a.txt”));


BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(System.out));


6、关于编码转换问题的应用举例:


举例1:复制一个文本文件。将一个GBK编码的文件,复制到另一个用UTF-8编码的文件中。


1,数据源:InputStream,Reader


数据目的:OutputStream ,Writer


2,是否是纯文本?


是。


数据源:Reader


数据目的:Writer.


3,设备:


数据源:硬盘文件


数据目的:硬盘文件。


涉及到编码数据。


源:是gbk FileReader


目的:因为是UTF-8,所以只能使用转换流。转换流中需要明确具体的字节流和编码。


编码是UTF-8,字节流就是对应硬盘设备的FileOutputStream。


FileReader fr = newFileReader(“a.txt”);


OutputStreamWriter  osw = new  OutputStreamWriter(newFileOutputStream(“b.txt”),”utf-8″);


需要高效就加上buffer


Writer


|–OutputStreamWriter


|–FileWriter


Reader


|–InputStreamReader


|–FileReader


转换流其实就是将字节流和编码表相结合。将字节流中的字节数据,去查了具体的编码表。所以转换流才可以获取一个中文字符。


那么转换流的子类用于操作文件的对象FileReader 就直接使用父类的具有转换功能的read方法。就可以一次读一个字符。


FileReader fr =new FileReader(“a.txt”);//该对象中已经内置了本机默认的字符编码表,对于简体中文版的机器默认编码表是GBK.


//通过字节读取流读取a.txt中中文数据,按照GBK编码表的来获取中文字符。


InputStreamReaderisr = new InputStreamReader(newFileInputStream(“a.txt”),”GBK”);


InputStreamReader isr= new InputStreamReader(newFileInputStream(“a.txt”),”GBK”);


FileReader fr =new FileReader(“a.txt”);


这两个句代码的功能是一样一样一样的。


区别:


第一句可以指定编码表。


第二句,固定本机默认编码表。


如果操作中文数据,仅使用本机默认码表,那么第二句书写简单。


如果操作中文数据,使用指定码表,必须使用第一句。 而且要将指定码表作为字符串传递到构造函数中。




7、数据存放的形式最常见就是文件:


那么文件的属性较多,如文件名称,路径,大小等属性。


为了方便与操作java就将其视为对象;通过File类对其描述。


提供了多个属性和行为;便于我们的对文件的使用。


而流对象只能用于操作文件中的数据。


对于文件的属性,都通过File对象来完成。


File类是可以是文件对象,也可以是文件夹对象。


常见功能:


1)创建:


booleancreateNewFile();


boolean mkdir()


boolean mkdirs()


2)删除:


boolean delete():


void deleteOnExit()


void show(){


创建一个文件。


deleteOnExit();//告诉jvm,程序退出,一定要把该文件删除。


操作这个文件。


//删除这个文件。


}


3)判断。


boolean isFile();


booleanisDirectory();


booleanisAbsolute();


boolean exists();判断file对象封装的内容是否存在。


booleancanExecute():判断文件是否可以执行。


File f = newFile(path);


Runtime r =Runtime.getRuntime();


if(f.canExecute())


r.exec(path);


booleanisHidden():判文件是否是隐藏文件。


4)获取。


String getAbsolutePath();


String getPath();


String getParent();


String getName();


5)重命名。


boolean removeTo(File)


6)文件列表:


static File[] listRoots():获取有效盘符。


String[] list():获取的是当前目录下文件或者文件夹的名称。


File[] listFiles():获取的是当前目录下文件或者文件夹对应的对象。


如果仅获取文件名称,就用list方法。如果还要获取文件的其他信息,最好使用listFiles。因为它可以获取到文件对象。


这样就可以通过文件对象的方法,获取其他的内容。比如;文件大小,文件名称。修改时间等信息。

class  FileDemo{
       public static void main(String[] args)throws IOException{
//method_1();    
              method_9();
       }
       public static void method_9(){
              File dir = newFile("c:\\");
              String[] names = dir.list();//获取当前目录下的文件夹和文件的名称包含隐藏文件。如果File中封装的是一个文件,那么返回的数组为null。所以此处最好为了安全性做一个判断。
//           System.out.println(names);
              for(String name : names){
                     System.out.println(name);
              }
       }
       //获取文件列表
       public static void method_8(){
              File[] roots = File.listRoots();//获取到系统中可以用的盘符。
              for(File root : roots){
                     System.out.println(root);
              }
       }
       //重命名
       public static void method_7(){
              File f= new File("qq.txt");
              File f1 = newFile("c:\\ww.txt");
              f.renameTo(f1);//将f的文件名改成f1的文件名,可以进行文件的移动(剪切+重命名)。
       }
       public static void method_6(){
              File f = newFile("a.txt");
              long time = f.lastModified();
              Date d = new Date(time);
DateFormatdf=DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
              String s = df.format(d);
              System.out.println("lastModified():"+s);
              System.out.println("exists:"+f.exists());
              System.out.println("length:"+f.length());//返回的是该文件的字节数。//该方法针对文件而言,文件夹没有大小。
              System.out.println("getName:"+f.getName());
              System.out.println("getParent:"+f.getParent());
              System.out.println("getAbsolutePath:"+f.getAbsolutePath());//获取的封装内容的绝对路径,也就是完整路径。
              System.out.println("getPath:"+f.getPath());//获取file内封装的路径内容。
       }
       //判断
       public static void method_5()throwsIOException{
              File f = newFile("xx.txt");
              f.mkdir();
              //f.createNewFile();
              System.out.println("exists:"+f.exists());
              //不需要想当然的认为xx.txt一定是文件。
              //想要判断file是封装的是文件还是目录,必须要确定该内容是存在的。才可以判断。
              System.out.println("isFile:"+f.isFile());
              System.out.println("isDirector:"+f.isDirectory());
              System.out.println("isAbsolute:"+f.isAbsolute());
       }
       //删除文件或者文件夹。
       public static void method_4(){
              File f = newFile("f.txt");
              boolean b1 = f.delete();//java中的删除不走回收站 。
              System.out.println("b1="+b1);
              File dir = newFile("abc");
              File dir1 = newFile("abc1");
              boolean b2 = dir.delete();
              boolean b3 = dir1.delete();//注意大家:删除目录时,如果目录中有内容,应该先将内部内容删除,在删该目录。                                        
              //windows删除就是从里往外删。
              System.out.println("b2="+b2);
              System.out.println("b3="+b3);
       }
       //创建文件夹。
       public static void method_3(){
              File f = newFile("abc\\mm\\nn\\xx\\aa\\qq\\ll\\pp");
//boolean b = f.mkdir();//只能创建单个目录。如果已存在不创建。
              boolean b = f.mkdirs();//可以创建多级目录。可以在已存在目录继续创建目录。
              System.out.println("b="+b);
       }
       //创建文件。
       public static void method_2()throwsIOException{
              File f = newFile("f.txt");
              boolean b = f.createNewFile();//如果f这个文件不存在,该方法会对其进行创建。如果f已经存在,该方法不会创建。而输出流创建文件,如果该文件存在,会覆盖。但是,如果输出流的构造函数传入参数为true。不覆盖文件 ,可以完成续写
              System.out.println("b="+b);
       }
       public static void method_1(){
              File ff = newFile("abc"+File.pathSeparator+"kkk");
              System.out.println(ff.toString());
              //将指定文件封装成File对象。
              File f = newFile("c:"+File.separator+"2.bmp");
              //System.out.println(f);
              File f5 = newFile("c:\\abc\\a.txt");
              File f1 = newFile("c:\\","a.txt");
              File dir = newFile("c:\\");
              File f2 = newFile(dir,"a.txt");
Filef3=newFile("c:"+File.separator+"abc"+File.separator+"kkk"+File.separator+"aa"+File.separator+"a.txt");
       }
}


8、递归作为一种编程手法。


当一个功能在被重复使用时,该功能的参数在随着功能变化。这时可以使用递归完成.


需要注意:


1,需要控制递归次数,不要过大。


2,递归必须要有条件。


否则,会出现栈内存溢出。

class DiGuiDemo {
       public static void main(String[] args) {
              toBin(6);
              int num = getSum(9000);
              System.out.println("num="+num);
       }
       public static int getSum(int num){
              if(num==1)
                     return 1;
              return num+getSum(num-1);
       }
       public static void toBin(int num){
              if(num>0){
                     toBin(num/2);
                     System.out.println(num%2);
              }
       }
}


9、IO中的其它流:


PrintStream:字节流中的打印流,可以直接操作设备的流对象。


构造函数的参数特点:


1,字符串路径。


2,File对象。


3,字节输出流。


PrintWriter:字符流中的打印流。


构造函数的参数特点:


1,字符串路径。


2,File对象,


3,字节输出流。


4,字符输出流。


打印流可以直接操作文件。算是较为常用流对象。


注意打印的特点在于提供了N多的print方法。


可以打印任意数据类型。

import java.io.*;
class  PrintWriterDemo{
       public static void main(String[] args)throws IOException{
              BufferedReader bufr = newBufferedReader(new InputStreamReader(System.in));
              PrintWriter pw = newPrintWriter(new FileWriter("pw.txt"),true);//目的是一个文件,还想要自动刷新。
              String line  = null;
              while((line=bufr.readLine())!=null){
                     if("over".equals(line))
                            break;
                     pw.println(line.toUpperCase());
                     //pw.flush();
              }
              pw.close();
              bufr.close();
       }
}


管道流:


读取流和写入流可以进行连接。


但是需要被多线程操作。


因为read方法是阻塞式方法。


容易引发死锁。


Map


|–Hashtable


|–Properties


Properties:该集合中存储的键和值都是字符串类型的数据,通常用配置文件的定义。


将硬盘上的数据进行集合的存储,希望在运算后,将改变后的结果,重新存回配置文件中。


其实load方法很简单,就是通过流对象,读取文本中一行数据 。


在将该行数据通过=进行切割。左边作为键,右边作为值。


存入到Properties集合中。


使用集合的特有方法load,将流的特定规则信息存储到集合中,注意:流中的信息必须有规则是键值对。用=分隔


演示SequenceInputStream将多个读取流变成一个读取流;多个源对应一个目的。


可是实现数据的合并。


特点:


1)即可以读,又可以写。


2)内部封装了一个大的byte类型的数组,这就说明


该对象操作的数据是字节数据。


说名其中封装了字节的读取流和写入流。


而且可以使用内部的指针对这个数组进行数据的操作。


3)提供了getFilePointer方法获取指针的位置,


还提供了seek方法设置指针的位置。


4)通过该对象的构造函数可以得知,该对象只能操作文件。


也就说源和目的都是一个文件。


并通过构造函数的另一个参数来确定,访问方式。


该变量只能接收四个值。


r:只读,rw:读写。rws。rwd。


5)该对象中的方法可以操作基本数据类型。


6)注意被操作的文件数据,希望有规律。这样可以通过数据的整数倍来控制指针的偏移;对数据进行操作,达到,随机访问的效果。


可以应用于多线程对大数据的写入。同时写入,只要给每一个线程分配


起始索引位,就可以完成多线程随机写入;提高了写入效率。


使用的前提:


1,必须是文件。


2,数据有规律。比如等长数据。

classRandomAccessFileDemo {
       public static void main(String[] args)throws IOException{
              writeDemo3();
//           readDemo2();
       }
       //对已有数据进行修改。
       public static void writeDemo3()throwsIOException{
              RandomAccessFile raf = newRandomAccessFile("info.txt","rw");
              raf.seek(8*3);//从指针索引位8开始进行写入。
              raf.write("赵六".getBytes());
              raf.writeInt(72);
              raf.close();
       }
       既然能写,那么读也应该没有问题。
       通过指针的操作,完成读取的随机效果。
       public static void readDemo2()throwsIOException{
              RandomAccessFile raf = newRandomAccessFile("info.txt","r");
              raf.seek(8*1);
              byte[] buf = new byte[4];
              int len = raf.read(buf);
              String s= new String(buf,0,len);
              System.out.println("name="+s);
              int age = raf.readInt();//一次读四个字节并转成int数值。
              System.out.println("age="+age);
              raf.close();
       }
       //通过seek方法指定指针的位置,进行数据写入。
       发现RandomAccessFile操作的文件如果已经存在,不会再次创建,直接操作已有文件。
       发现通过seek的指针定位,就可以完成数据的随机写入;它可以完成已有数据的修改。
       public static void writeDemo2()throwsIOException{
              RandomAccessFile raf = newRandomAccessFile("info.txt","rw");
              raf.seek(8*2);//从指针索引位8开始进行写入。
//           raf.write("李四".getBytes());
//           raf.writeInt(67);
              raf.write("王武".getBytes());
              raf.writeInt(68);
              raf.close();
       }
       通过该对象写点数据;数据: 人员信息: 姓名,年龄
       public static void writeDemo()throwsIOException{
              RandomAccessFile raf = newRandomAccessFile("info.txt","rw");  
              raf.write("张三".getBytes());
              //raf.writeBytes("张三");//解析出了问题。
              //raf.writeChars("张三");//解析出了问题。
              //raf.write(65);//write:只将一个int整数的最低字节写出。
              raf.writeInt(65);
              raf.close();
       }
       public static void readDemo()throwsIOException{
              RandomAccessFile raf = newRandomAccessFile("info.txt","r");
              byte[] buf = new byte[4];
              int len = raf.read(buf);
              String s= new String(buf,0,len);
              System.out.println("name="+s);
              int age = raf.readInt();//一次读四个字节并转成int数值。
              System.out.println("age="+age);
              raf.close();
       }
}


对象的持久化存储。


也就是将对象中封装数据保存到持久化的设备上比如硬盘。


那么其他应用程序都需要建立该对象,直接读取设备上的对象即可


ObjectInputStream


ObjectOutputStream


专门用于操作对象的流;肯定封装了直接操作对象的方法。


注意:


对象中的静态数据是不会被持久化的。


那么非静态数据,也有不想被持久化的,怎么办?


只要将不需要被持久化的非静态数据进行transient关键字修饰即可


Serializable:


用于给类文件加一个UID。就是一个序列号。


该序列通过类中的成员的数字签名完成运算得来的。


当类中的成员发生大的改动时类会重新编译,生成带有新的UID的序列号。


这样就和曾存储的原来的类生成的对象的序列号不匹配。


这样就可以让使用者必须重新对新类产生的对象进行存储。


避免新类接收老对象出现安全隐患,这就是序列号的功能所在。


如果是类中没有成员大的改动,只是只是有个别的修改和已存储的对象没有太大影响。


就需要重新进行存储。希望可以用新的类接收读到的老对象。


这时可以在定义类时指定序列化,而不让jvm自动算该序列化。

classObjectStreamDemo {
       public static void main(String[] args)throws Exception{
//           writeObj();
              readObj();
       }
       //读取对象。
       public static void readObj()throws Exception{
              ObjectInputStream ois =
                     new ObjectInputStream(newFileInputStream("obj.txt"));
              Person p =(Person)ois.readObject();//ClassNotFoundException
              System.out.println(p.toString());
              ois.close();
       }
       //写入对象。
       public static void writeObj()throwsIOException{
       ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("obj.txt"));
            oos.writeObject(newPerson("lisi",20));//如果一个对象要被写入,必须具备序列化功能,也就是说必须要实现Serializable接口
              oos.close();
       }
}


ByteArrayInputStream与ByteArrayOutputStream


操作数组流对象。它对应的设备就是内存。


ByteArrayOutputStream:内部封装了一个可变长度的字节数组。


关闭它是无效。因为该对象根本就没有调用过底层资源。


可以通过toByteArray()或者toString获取数组中的数据。


ByteArrayInputStream负责数据源:在初始化的时候, 必须要有一个数据源内容。


因为操作的是数组,所以源就是一个字节数组。


注意:该对象中不会有异常发生,因为没有调用过底层资源。


直接操作byte[]不就的了吗?


干嘛还要使用流对象来完成呢?


因为数组的操作,无非就是数组中的元素进行设置和获取。


这个操作正好符合了读和写的操作。


使用流的操作思想在操作数组。

import java.io.*;
class  ByteStreamDemo{
       public static void main(String[] args) {
              ByteArrayInputStream bis = newByteArrayInputStream("abcde".getBytes());
              ByteArrayOutputStream bos = newByteArrayOutputStream();
              int ch = 0;
              while((ch=bis.read())!=-1){
                     bos.write(ch);
              }
              String s = bos.toString();
              System.out.println(s);
       }
}


字符流 = 字节流+编码表;能指定编码表的是转换流。


内部默认了编码表的是转换流的子类FileReader,FileWriter。默认的是本机码表。


OutputStreamWriter osw = new OutputStreamWriter(newFileOutputStream(“gbk.txt”));


OutputStreamWriterosw1=newOutputStreamWriter(newFileOutputStream(“gbk.txt”),”GBK”);


FileWriter fw =new FileWriter(“gbk.txt”);


以上三句都是一回事,都是在使用默认的GBK表,在操作gbk.txt文件。


将数据按照指定的编码表GBK将数据存储到目的中。



版权声明:本文为yuan_dailin原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。