IO流总结


一: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将数据存储到目的中。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值