黑马学习日记_IO篇(第一部分)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 黑马学习日记_IO篇(第一部分)

黑马学习日记_IO篇(第一部分)

 2014/4/3 9:11:09  小驴变黑马  程序员俱乐部  我要评论(0)
  • 摘要:----------------------android开发、java培训、期待与您交流!----------------------IO:主要用来处理设备之间的数据传输(如硬盘上的文件,内存中的数据),java对数据的操作是通过流的方式,java操作流的对象存在IO包中,流按数据分为两种,字节流和字符流。字符流的数据字节流其实都能处理,因为无论什么在计算机上最后都是以字节存在的,但是其中有一部分数据它是以文本形式存在的,所以为了方便有了字符流,字符流里融合了编码表,而只有文字用到了编码表
  • 标签:学习
----------------------class="Apple-converted-space">?android开发、java培训、期待与您交流! ---------------------- ? IO:主要用来处理设备之间的数据传输(如硬盘上的文件,内存中的数据),java对数据的操作是通过流的方式, java操作流的对象存在IO包中,流按数据分为两种,字节流和字符流。 ?字符流的数据字节流其实都能处理,因为无论什么在计算机上最后都是以字节存在的,但是其中有一部 ?分数据它是以文本形式存在的,所以为了方便有了字符流,字符流里融合编码表,而只有文字用到了 ?编码表,所以字符流用来处理文本形式的数据。 ? 按方向分的话有输入流和输出流之分。 字符流: ?????????????字节流: ?Writer ??Reader ???InputStream ?OutputStream? 这四个基类的子类名称都是以父类的名称为后缀,如FileReader,FileInputStream, 在写有关IO流程序的时候,首先要注意: ?1.要注意一定要记得导包,import java.Io.*; ?2.记得要进行异常处理,和IO流有关的都会抛异常,原因:例如FileWrite("C:\\abc.txt"); ???因为括号里的文件名会有可能出错,比如写成(K:\\abc.txt) ?3.最后一定要进行关闭流的操作。因为它底层调用的其实是window资源,所以要关闭。 ? --------------------------------------------------------------------------------------------- ? 下面是IO异常处理方式: 例如; ?
FileWriter fw = null;//2.所以一般在外面定义引用在try内初始化,这样fw就作用于整个程序中,
 try
 {
  //1.因为会抛异常所以要进行try处理,但是如过把下面这句放在try代码块里面定义fw,那么
  //在别的代码块里会访问不到(比如finaly里关流的时候)
     //FileWriter fw = new FileWriter(c:\\abc.txt); 
    fw = new FileWriter(c:\\abc.txt); // 代码1
  fw.Write("abcdef");  //代码2
 }
 catch(IOException e),
 {
  //异常处理
 }
 finaly
 {
  try
  {//一定要对关闭的流对象进行判断是否为空
   if(fw != null)//写这句的原因:因为如果“代码1”处出现异常被处理了,那么代码里面fw里面也就
       //没有被写进东西,所以fw为空。
    fw.close();//如果为空的话则不能调用这句,所以要进行下是否为空判断
  }
  catch(IOException e),
  {
   //异常处理
  }
 }
?? ? 字符流:writer(写) ?根据以往经验,要想了解一个体系,是不是都要先从最顶端的开始了解啊?字符流写的方法最顶端的 ?父类就是writer,它里面有append(),close(), write() 等方法,可以知道它的子类中肯定也都具有 ?这些功能。既然是字符流,那么它操作的最基本数据就是字符, FileWriter 里的主力方法就是write ?方法,就是往文件里写数据的方法,既然是操作字符了,那肯定忘里写单个字符啊字符数组啊,字符串 ?啊都行。 ? ?字符流---创建文件 ?异常处理如上: ? ?FileWriter fw = new FileWriter("Demo.txt");// ?在此目录下创建一文件,如果已经存在会被覆盖掉。 ?FileWriter fw = new FileWriter("Demo.txt",true);//不覆盖原文件,在末尾处添加 ?fw.write("abcdefg");//调用write()方法,其实是存在了流(内存)中 ?fw.flush();//将流对象中缓冲区里的刷新数据至目的地中 ?fw.close();// close()特点:刷新一次数据然后关闭流 ? ?其实,我们不用java也能创建一个文件往里写数据,也就是说windows系统本身就具有这个动作,java能往 ?windows的文件系统中写入数据,是不是代表着java在调用windos中那个写的动作?这个就是我们所说的流 ?资源。其实java本身是不能往硬盘里写数据的,我们知道windows和linux系统它们写数据的方式是不是不一 ?样啊?所以java得靠系统本身的方式来完成对数据的书写。总的来说就是java写数据什么的是不是在调用 ?windows的系统资源用完了要怎么办?是不是要释放出来,所以close动作是一定要做的。 ? ?文件的续写: ??建个文件往里面写数据,但是那个文件里已经有数据了该怎么往里续写数据呢?写一次刷新一次,通过 ??查看API我们发现FileWriter类有一种构造函数 ??FileWriter(String fileName, boolean append) ??参数: fileName - 一个字符串,表示与系统有关的文件名。 ???append - 一个 boolean 值,如果为 true,则将数据写入文件末尾处,而不是写入文件开始处。? --------------------------------------------------------------------------------------------- ? 字符流 Reader(读) ?说完写该说读了,查看API发现Reader类里也有很多和Writer方法,如close()等,但是它里面没有flush(); ?另外它里面有一群读的方法(read),如读单个字符,或把数据读入到一个数组,另外读文件的话是不是先把 ?文件传给他啊,所以在创建对象的时候要把指定文件与它相关联。如果不存在会发生文件未找到异常。 ? ?字符流---读取文件1 下面是没有进行异常处理的 ? ?FileReader fr = new FileReader("Demo.txt");//文件不存在会抛异常 ?int x = fr.read();//一次读一个会自动往下读,如果在调用一次read方法和打印方法,打印的则是下一个 ?System.out.println(char(x));//因为返回的是int型,所以要进行类型转换。 ?//一个文件里面显然不会只有一个字符,像上面所说读一个重写一次方法,会很麻烦,所以会想到循环,如下: ????int x = 0; ?while((x=fr.read()) != -1)//文件读取到末尾如果没有的话会返回-1 ?{ ??System.out.println((char)x); ?} ? ??字符流---读取文件2 通过字符数组进行读取,下面是没有进行异常处理的 ?FileReader fr = new FileReader("Demo.txt");//创建一个文件读取流对象和指定文件相关联 ?//定义一个字符数组 ?char[] ch = new char[1024]//一般数组大小会定为1024的整数倍 ?int num = fr.read(ch);//将读取到的文字存放在数组中,则返回的是字符里面的个数 ?System.out.println(new String(ch));//将数组变成字符串打印 ?fr.close();//这一步没有刷新数据,读取文件不用刷新 ? ?文件读取2的完整代码: ? ?
FileReder fr = null
  try
  {
  fr = new FileReade();
  char[] ch = new char[1024];
  int num = 0;
  while((num = fr.read(ch))!=-1)
  {
   //打印数组中的有效位,如果数组中只有三个字符,就没必要把1024个全打印出来
   System.out.println(new String(buf,0,len)); 
  }
  }
  catch (IOException e)
  {
   //异常处理
  }
  finally
  {
   try
   {
   if (fr !=null)
   {
    fw.close();
   }
   }
   catch (IOException e)
   {
   //异常处理
   }
  }
?? ?注意: ??定义文件路径时,可以用“/”或者“\\”。? ??在创建一个文件时,如果目录下有同名文 件将被覆盖。 ? ??在读取文件时,必须保证该文件已存在, 否则出异常。 ? 练习:复制文件 ?部分代码: ??
FileWriter fw = new FileWriter("copy.txt");//向目的文件中写入数据
  FileReader fr = new FileReader("Demo.java");//读取文件中的数据写入流中
 
  char[] buf = new char[1024];
 
  int len = 0;
  while((len=fr.read(buf))!=-1)
  {
   fw.write(buf,0,len);
  }
?? --------------------------------------------------------------------------------------------- 字符流的缓冲区: BufferedWriter ?BufferedReader ? ?字符流中的读写,如上面方法的话,都是一个一个的读或写,为了提高效率出现了缓冲区,就像 ?用杯子接水滴,等接满了一杯再喝会比接一滴喝一滴舒服。 ?像迅雷,BT这些软件它们在下载过程中都有自己的缓冲区,比如它们在服务器下载东西,每次下 ?载一次性两兆再写到硬盘上从,比每次从服务器下载一点就往硬盘上写一点快吧。这边一顿狂读, ?这后到这边再一顿狂写,省的磁头来回的切换,这样效率就提升了很多。 ? ?缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。 ?该缓冲区中提供了一个跨平台的换行符。newLine(); ? ?我们创建一个流对象之后,然后把它当参数传给缓冲区的构造函数,因为缓冲区已经和流相关联了, ?所以然后直接用缓冲区的方法就可以了。 ? ?字符写入流缓冲区: BufferedWriter ? ??????既然缓冲区是为了提高流的效率,那么它存在的前提是要有流。 ? ????例如: ??FileWriter fw = new FileWriter("Demo.txt"); ??//只需将需要被提高效率的流当参数传入给缓冲区的构造函数即可 ??BufferedWriter bfw = new BufferedWriter(fw); ??//然后下面就可以用缓冲区的方法了(BufferedWriter也是Write的子类,所以也能用它的方法) ??bfw.write("abcde"); ??bfw.flush();//只要用到缓冲区就要刷新 ??bfw.close();//关闭缓冲区其是就是关闭了流对象,所以fw.close()就不用再写了 ? ?缓冲区有一个新的方法:newLine()这个方法是跨平台的,在window上"\r\n"是换行而在linux上"\n"是换行 ?只有用到缓冲区对象的时候才能用newLine()方法 ?例如: ??for(intx =0;x<5;x++) ??{ ??bfw.write("abcde"); ??bfw.newLine(); ??//为什么要写一次刷新一次? 因为在写的过程中可能会出现一些状况如停电,如果在写好多的情况下 ??// 停电了没刷新那么文件里面一点也不会有 ??bfw.flush(); ??} ? --------------------------------------------------------------------------------------------- ? 字符读取流缓冲区: BufferedReader ? ?该缓冲区提供了一次读一行的方法:readLine()因为一行有很多字符。所以它返回的是字符串,读到流的 ?末尾返回的是null,readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。 ?readLine()方法最终都是从硬盘上一个一个的读取所以最终使用的还是read方法一个一个的读的。 ? ?//创建一个读取流对象和文件相关联。 ?FileReader fr = new FileReader("Demo.txt"); ?//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。 ?BufferedReader bfr = new BufferedReader(fr); ?//下面使用BufferedReader的方法 ?String s = null; ?while((s=bfr.readLine()) !=null) ?{ ??System.out.print(s); ?} ?bfr.close(); ? ?缓冲区特点: ??缓冲区的出现提高了对数据的读写效率。? ??缓冲区要结合流才可以使用。? ??在流的基础上对流的功能进行了增强。 --------------------------------------------------------------------------------------------- ? 装饰设计模式: ?一个类的功能如果需要加强,可以在定义一个类来写加强的功能,然后将需要被加强的类 ?当参数传入加强类,通过构造方法来接收被加强的类。如BufferedReader(FlieRader fr). ? ?模式例如: ?
class OldMethod   //1.
 {
  public void fuction
  {
   //原有的功能
  }
 }
 class SuperMethod  //2.
 {
  private OldMethod om;
  SuperMethod(OldMethod om)
  {
   this.om = om;
  }
  public void superFuction
  {
   //基于原有而加强的功能
   //如果有用到原来的东西,直接调用:om.fuction()
  }
 }
?? --------------------------------------------------------------------------------------------- ? 疑问:为什么类2不继承类1呢? ??例如下面类OldMethod有三个子类,比如在开发的过程中我们发现这三个子类里面的功能效率有点低我 ??们想要重写个类来加强一下它们的功能,这时会想到用缓冲技术,那么如果要用继承的话,就会像下 ??面这样,在后期OldMethod可能还会再增加好多子类,那么在这样写的话整个体系就会显得非常臃肿,所 ??以要进行优化。 ?? OldMethod ?|--OneMethod ??|--OneBufferMethod ?|--TwoMethod ??|--TwoBufferMethod ?|--ThreeMethod ??|--ThreeBufferMethod 怎么优化呢?既然它们都需要缓冲,所用的技术也都一样,那么就没必要一个一个的写缓冲类来继承了,可以 专门定义一个缓冲类,OldMethod的哪个子类需要缓冲就把哪个当参数传进来。如下: class MyBufferMethod { ?MyBufferMethod(OneMethod one) ?{ ?} ?MyBufferMethod(TwoMethod two) ?{ ?} ?MyBufferMethod(ThreeMethod three) ?{ ?} ????......//但是这样扩展型还是不太好 } ? 这时可以发现,无论是哪个类需要缓冲,他们都是OldMethod的子类,这样就想到了多态,我们可以这样定义 一个类来继承. class MyBufferMethod extends OldMethod//既然MyBufferMethod里的功能和只是那三个子类功能的加强, { ????????//所以它也应该属于OldMethod参看下面的(看这里) ?MyBufferMethod(OldMethod old)//多态,技能传OneMethod也能传TwoMethod... ?{ ?} } ? 最后这个体系就变成了这样: OldMethod ?|--OneMethod ?|--TwoMethod ?|--ThreeMethod ?|--MyBufferMethod --------------------------------------------------------------------------------------------- 我们可以看出装饰模式比继承更灵活,降低了类与类之间的关系 装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了加强功能。所以装饰类 和被装饰类属于同一个体系就像BufferedReader与FileReader同是Reader的子类 --------------------------------------------------------------------------------------------- ? LineNumberReader: 也是一个装饰类,BufferedReader的子类,所以它也有readLine()方法, ???????????????????另外还有setLineNumber()和getLineNumber(),意为设置和获取行号。 ? 使用方法如下(没有进行异常处理): ?FileReader fr = new FileReader("Demo.txt"); ????LineNumberReader lnr = new LineNumberReader(fr); ?String s = null; ?lnr.setLineNumber(10);//可以设置行号的起始值 ?while((x=lnr.readLine()) != null) ?{ ??System.out.println(lnr.getLineNumber()+"::"+x); ?} ? --------------------------------------------------------------------------------------------- ? ? 字节流:基本操作与字符流差不多,别说它里面的write,read方法和字符流里的基本一样,它也能一个一个 的往文件里写数据,也能把数组中的数据一下写到文件中,既能一个一个的读,也能把数据读入到一个数组 中,唯一的区别是字符流写进的是char[],而字节流是往byte[]数组中读或写。另外字节流不仅操作字符, 还可以操作其他媒体文件 ? 基类 InputStream读 OutputStream写 ?? 字节流--文件写入,与字符流一样也要处理异常。 ?FileOutputStream fos = new FileOutputStream("Test.txt");//创建一个字节写入流,与文件相关联 ?//里面要么写单个字节,要么写字节数组,写字符串的话要把它转成字节类型的 ?fos.write("abcde".getBytes());//不需要刷新,因为是直接对字节最小单位操作,中间不需要任何转换 ?fos.close();//关闭流 ? 字节流--文件读取1,一个一个的打印 ?FileInputStream fis = new FileInputStream("Test.txt"); ?int ch = 0;//调用read()方法返回的是整数,流末尾返回的是-1; ?while((ch=fos.read())!=-1) ?{ ??System.out.println(char(ch));//因为返回的是整数,所以要把它转成字符型打印 ?} ?fos.close();? 字节流--文件读取2,将数据读进一个字节数组 ?FileInputStream fis = new FileInputStream("Test.txt"); ?byte[] buf = new Byte[1024]; ?int len = 0; ?while((flen=os.read(buf))!=-1) ?{ ??//把数组转换为字符串,按范围打印出来 ??System.out.println(new String(buf,0,len)); ?} 字节流--文件读取3,这一种是字节流特有的 ?FileInputStream fis = new FileInputStream("Test.txt"); ?//int num = fis.available();调用这个方法可以算出文件中的字符数 ?byte[] buf = new Byte[fis.available()];//所已就可以定义一个刚刚好的数组了,也就不用循环了 ?fos.read(buf);//读取文件中的字节存在数组buf中 ?System.out.println(buf);//不用循环,直接把数组里面的全打印出来 ?fis.close(); --------------------------------------------------------------------------------------------- ?注意: ??字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。 ??因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1. ??那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。 ??所以,为了避免这种情况将读到的字节进行int类型的提升。 ??并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。 ? ??而在写入数据时,只写该int类型数据的最低8位。 ? --------------------------------------------------------------------------------------------- 字节流缓冲区 ??//例:通过字节流的缓冲区来完成 Mp3的复制: ?BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3")); ?BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3")); ?????int by=0; ?while((by=bufis.read())!=-1) ?{ ??fos.write(by);//把从文件中读取的数据写进目的文件 ?} ? ?fos.close();//有多少流就关多少流 ?fis.close(); ? ? 自定义字节流缓冲区: ?字节流缓存区的原理是,把一些数据先存进一个数组中,然后在一下取出来。自定义缓冲区的话,思路 ?就是:要先定义一个数组,然后再把数组中的数据一个一个往外取。用到了数组,怎么往里存呢?我们 ?知道read(arr)返回的是数组里元素的个数, ?那取的时候read方法 ?是一个一个的往下读的,所以就用到了指针,那什么时候停呢?就是取到数组末尾的时候,就是count=0的时候, ?那怎么往数组里面存呢?
 class MyBufferInputStream extends 
 {
  private InputStream ips;//定义一个InputStream引用
  private byte[] buf = new byte[1024*4];
   
  private int pos = 0,count = 0;//定义一个指针和数据个数的变量
  MyBufferInputStream(InputStream ips)//把需要缓存的文件当参数传给缓冲器的构造函数
  {
   this ips = ips;
  }
 //要对外提供一个read方法,就像BufferInputStream,一次读一个字节(从缓冲区即字符数组中读取)
  public int myRead()throws IOException//进行异常处理
  {
   //通过in对象读取硬盘上数据,并存储buf中。
   if(count==0)//5.所以当数组中元素为0的时候,是先存再取
   {
    count = ips.read(buf);//1.把数据读取到数组中,返回的是数组里元素的个数
    if(count<0)//
     return -1;
    pos = 0;//
    byte b = buf[pos];//2.往数组里存满了是不是就该把数组里的数据取出来放缓冲区里啦
 
    count--;//3.把数组里的数据往缓冲区里装的时候是不是装一个,数组里就少一个啊?
    pos++;//4.一个一个的把数组里的取出来,是不是就是指针越来越往后移啊
    return b&255;
   }
   else if(count>0)//6.而当数组里有数据的时候直接取
   {
    byte b = buf[pos];
 
    count--;
    pos++;
    return b&0xff;
   }
   return -1;
  }
 }
?? 读取键盘录入: ?System.out:对应的是标准输出设备,控制台。 ?System.in:对应的标准输入设备:键盘。in 是标准输入流对应的是InputStream,所以能用read()等方法 ?例如: ?InputStream in = System.in;//System调用in方法之后返回的是一个字节读取流 ?int by = in.read();//读取一个字节字符流字节流读取一个数据返回的都是int型 ?System.out.println(by);//控制台将会等待输入运行代码 ? ?部分代码:
 import java.io.*;
 class IODemo 
 { 
  public static void main(String[] args) throws IOException
  {
   InputStream ins = System.in;
   
   StringBuilder sb = new StringBuilder();
   while(true)
   {
    int ch  = ins.read();
    if(ch=='\r')
     continue;
    if(ch=='\n')
    {
     String s = sb.toString();
     
     //sb.delete(0,sb.length());
     if("over".equals(s))
      break;
     System.out.println(s.toUpperCase());
     sb.delete(0,sb.length());
    }
    else
     sb.append((char)ch);
   }
  }
 }
??然后发现以上代码与我们自定义 BufferedReader时写的ReaderLine代码差不多,这时就考虑能不能 ?直接拿过来用呢?但是 BufferedReader是字符流,而InputStream是字节流,它是字节流要用字符流 ?的东西,怎么办?是不是要看看有没有能把字节流转为字符流的东西啊?通过查看java API发现,还 ?真有个转换流,下面请看java io(2)。 ----------------------?android开发、java培训、期待与您交流! ----------------------
发表评论
用户名: 匿名