天天看点

黑马程序员_java_io(上)

------- android培训、java培训、期待与您交流! ---------- 

        java_ io(上)

 io流是一组有序的数据序列,根据操作的类型,可分为输入流和输出流两种io(Inpout/Output)liu

同了一条通道程序,可以使用这条通道吧源中的字节序列送到目的地,虽然io流经常与词牌文件存取有关,

但是程序的源和目的地也可以是键盘鼠标,内存或者显示器窗口等.

 java有数据流处理输入/输出模式,程序与从指定源的输入流中读取源中的数据,源可以是文件.网络.压缩包

或者其他数据

 java语言定义了许多专门负责各个方式的输入/输出,这些类都被放在java.io包中.其中所有输入流

类都是抽象类InputStream(字节输入流)或者抽象类Reader(字符输入流)的子类;而所有输出流都是抽象

类OutputStream(字节输出流)或者抽象类Writer(字符流输出流)的子类.

 字节流两个基类:

  InputStream   OutputStream

 字符流两个基类:

  Reader Writer

 注由这四个类派生出来的子类名称都是 以其父类名作为子类名的后缀。

 如:InputStream的子类FileInputStream。

 如:Reader的子类FileReader。

//------------------------------------------------------------------------

构造方法:

FileWriter:用来写入字符文件的便捷类java.io Writer另请参见:

 FileWriter(String fileName, boolean append)

     根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

 FileWriter(File file)

     根据给定的 File 对象构造一个 FileWriter 对象。

 FileWriter(FileDescriptor fd)

     构造与某个文件描述符相关联的 FileWriter 对象。

 FileWriter(String fileName)

     根据给定的文件名构造一个 FileWriter 对象。

 FileWriter(File file, boolean append)

  示:fw=new FileWriter("demo.txt",true);//在已有文件续写.如果没有就文件就创建

      根据给定的 File 对象构造一个 FileWriter 对象。

常用方法:

 void write(String str):写入字符串。

 abstract  void flush():刷新该流的缓冲

 abstract  void close():关闭此流,但要先刷新它。

  //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。

  //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。

  //其实该步就是在明确数据要存放的目的地。

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

  //调用write方法,将字符串写入到流中。

  fw.write("abcde");

  //刷新流对象中的缓冲中的数据。

  //将数据刷到目的地中。

  //fw.flush();

  //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。

  //将数据刷到目的地中。

  //和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。

  fw.close();

 ps:\r\n:回车符.在windows里面需要两个代表回车符.在linux系统\n代表回车符.

//-------------------------------------------------------------------------                      

IO异常的处理方式续写和回车符:

示例:

import java.io.*;
class FileWriterDemo2 
{
 public static void main(String[] args)
 {
  FileWriter fw=null;//需要在代码块外边建立引用.
  try
  {
   fw=new FileWriter("demo.txt",true);
   fw.write("accd\r\nde");  
  }
  catch (IOException e)
  {
   System.out.println(e.toString());
  }
  finally
  {
   if(fw!=null)//判断fw是否为空.如果输入盘符错误的话.fw会是null;将执行不到close所以要判断
    try
    {
     fw.close();
    }
    catch (IOException e)
    {
     System.out.println("关闭资源失败");
    }  
  } 
 }
}
           

//---------------------------------------------------------------------

构造方法:

FileReader:用来读取字符文件的便捷类java.io Reader另请参见:

  FileReader(File file)

          在给定从中读取数据的 File 的情况下创建一个新 FileReader。

  FileReader(FileDescriptor fd)

          在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。

  FileReader(String fileName)

          在给定从中读取数据的文件名的情况下创建一个新 FileReader。

常用方法:

  abstract  void |close() 关闭该流并释放与之关联的所有资源。

  void |mark(int readAheadLimit) 标记流中的当前位置。

  boolean |markSupported() 判断此流是否支持 mark() 操作。

  int |read() 读取单个字符。

  int |read(char[] cbuf) 将字符读入数组。

  abstract  int |read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

  int |read(CharBuffer target) 试图将字符读入指定的字符缓冲区。

  boolean r|eady() 判断是否准备读取此流。

  void |reset() 重置该流。

  long |skip(long n) 跳过字符。

 第一种取出方式: 

  //创建一个文件赌球流对象,和指定名称的文件相关联.

  //要保证该文件时已经存在的,如果不存在,会发生异常FileNotFoundException

FileReader fr=new FileReader("demo.txt");
  int ch=0;
  /*
  调用读取流对象的read方法
  read():一次读一个字符,而且会自动往下读.
  */
  while((ch=fr.read())!=-1)
  {
  System.out.println("ch="+(char)ch);
  }
  /*
  while(true)
  {
   int ch=fr.read();
   if(ch==-1)
    break;
  System.out.println("ch="+(char)ch);
  }
  */
           

 第二种出去方式:

fr=new FileReader("FileWriterDemo.java");
  //定义一个字符数组.用于存储到字符.
  //该read(char[])返回的是读到的个数
  char[] buf=new char[1024];
  //定义一个变量来记住个数
  int num=0;
  //用while循环来判断结尾是否读到的个数为-1
  while((num=fr.read(buf))!=-1)
  {
   //打印个数和字符数组.new String(buf,0,num)是Sting类中打印数组从0开始.到nun结束
   System.out.print(num+"....."+new String(buf,0,num));
   //注意输出语句没加ln.是因为数组的长度是1024,如果到了1024就会换行.所以不加.
  }
           

练习:拷贝文件

/*
需求:拷贝文本文件.
1.在D盘创建一个文件,用于存储c盘文件中的数据
2.定义读取流和c文件箱关联.
3.通过不断的读写完成数据存储.
4.关闭资源
*/
import java.io.*;
class  CopyText
{
 public static void main(String[] args) 
 {
  copy_2();
 }
 public static void copy_2()//建立字符数组集体拷贝
 {
  FileReader fr=null;//在代码块外边给fr初始化.要不然在代码块里面建立对象别的地方会访问不到
  FileWriter fw=null;
  try
  {
   fr=new FileReader("MathDemo.java");//建立对象并指定好目录
   fw=new FileWriter("MathDemo_copy.txt");
   char[] buf=new char[1024];//建立字符数组,用来储存数据

   int len=0;//定义一个变量来记住字符数
   while((len=fr.read(buf))!=-1)//因为字符数到末尾会是-1.进行判断
   {
    fw.write(buf,0,len);//写出数据.并从零开始.到字符数那里结束
   }
  }
  catch (IOException e)//路径不存在抛异常
  {
   throw new RuntimeException("路径不存在");
  }
  finally
  {
   try
   {
    if(fr!=null)//对close判断.是否为空如果建立对象不成功的话close根本不识别.
     fr.close();
   }
   catch (IOException e)
   {
    System.out.println("写入失败");
   }
   try
   {
    if(fw!=null)
     fw.close();
   }
   catch (IOException e)
   {
    System.out.println("读取失败");
   }
  }
 }
 public static void copy_1()//一个字符一个字符的拷贝
 {
  FileReader fr=null;
  FileWriter fw=null;
  try
  {
   fr=new FileReader("SystemDemo.java");
   fw=new FileWriter("System_copy.txt");

   int ch=0;
   while((ch=fr.read())!=-1)
   {
    fw.write(ch);
   }
  }
  catch (IOException e)
  {
   throw new RuntimeException("路径不存在");
  }
  finally
  {
   try
   {
    if(fr!=null)
     fr.close();
   }
   catch (IOException e)
   {
    System.out.println("写入失败");
   }
   try
   {
    if(fw!=null)
     fw.close();
   }
   catch (IOException e)
   {
    System.out.println("读取失败");
   }
  }
 }
}
           

//--------------------------------------------------------------------------

BufferedWriter类与BufferedReader类

 Bufferedwriter类和BufferedReader类分别继承了Reader类和Writer类.这两个类同样具备了内部缓存机制.

可以可进行单位进行输入输出.

 在使用BufferedWriter类的Writer()方法时,数据并没有立即写入至输出流中.而是首先进入缓存区中.

如果想理解将缓存区中个的数据写入输出流中,一定要动用flush()方法.

 缓冲区的出现提高了对数据的读写效率。

 对应类

 BufferedWriter

 BufferedReader

 字符输出流缓冲区:

  缓冲区要结合流才可以使用。

  在流的基础上对流的功能进行了增强

  缓冲区的出现是为了提高流的操作小路而出现的.

  所以在创建缓冲区之前,必须要先有流对象.

  该缓冲区提供了一个夸平台的换行符.

  newLine();

 字符读取流缓冲区:

  该缓冲区提供了一个一次读一行的方法 readLine,方便与对文本进行数据的获取.

  当返回null时候,表示读到文件末尾.

示例:

/*
需求:复制一个java文件
*/
import java.io.*;
class  CopyTextBuf
{
 public static void main(String[] args) 
 {
  BufferedReader bufr=null;
  BufferedWriter bufw=null;
  try
  {
   //为了提高效率.加入缓冲技术,将字符读取流对象作为参数传递给缓冲区的构造函数.
   //建立缓冲区,创建流对象和文件相关联的
   bufr=new BufferedReader(new FileReader("BufferedReaderDemo.java"));//字符读取流

   bufw=new BufferedWriter(new FileWriter("BufferedReaderDemoCopy_1.txt"));//字符输出流
   String s=null;//因为读取一行到末尾的时候会返回null.就可以以null作为循环条件来循环
   while((s=bufr.readLine())!=null)
   {
    bufw.write(s);//读取一行.输出一行
    bufw.newLine();//换行
   }
  }
  catch (IOException e)
  {
   throw new RuntimeException("文件路径错误");
  }
  finally
  {
   try
   {
    if(bufr!=null)
     bufr.close();
   }
   catch (IOException e)
   {
    System.out.println("读取关闭文件失败");
   }
   try
   {
    if(bufw!=null)
     bufw.close();
   }
   catch (IOException e)
   {
    System.out.println("输出关闭文件失败");
   }
  }
 }
}
           

//-------------------------------------------------------------------

装饰设计模式:

 以前是通过继承将每一个子类都具备缓冲功能。

 那么继承体系会复杂,并不利于扩展。

 现在优化思想。单独描述一下缓冲内容。

 将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。

 这样继承体系就变得很简单。优化了体系结构。

 装饰模式比继承

  要灵活。避免了继承体系臃肿。

  而且降低了类于类之间的关系。

 装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。

 所以装饰类和被装饰类通常是都属于一个体系中的。

MyReader//专门用于读取数据的类。

            |--MyTextReader

                    |--MyBufferTextReader

            |--MyMediaReader

                    |--MyBufferMediaReader

            |--MyDataReader

                    |--MyBufferDataReader

class MyBufferReader

{

 MyBufferReader(MyTextReader text)

 {}

 MyBufferReader(MyMediaReader media)

 {}

}

上面这个类扩展性很差。

找到其参数的共同类型。通过多态的形式。可以提高扩展性。

class MyBufferReader extends MyReader

{

 private MyReader r;

 MyBufferReader(MyReader r)

 {}

MyReader//专门用于读取数据的类。

 |--MyTextReader

 |--MyMediaReader

 |--MyDataReader

 |--MyBufferReader

 LineNumberReader:

  BufferedReaderd 的子类,也属于装饰类跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int)

  和 getLineNumber(),它们可分别用于设置和获取当前行号.

  演示:

   FileReader fr=new FileReader("demo.txt");//建立输入流对象于文件相关联

   LineNumberReader lnr=new LineNumberReader(fr);//建立缓冲区.

   String line =null;

   lnr.setLinNumber(100);//设置行号

   while((line=lnr.readLine())!=null)

   {

    System.out.println(lnr.getLineNumber()+":"+line);//获取行号,和打印一行

   }

   lnr.close

演示:

/*
明白了BufferedReader类中特有方法readLine的原理后,
可以自定义一个类中包含一个功能和readLine一致的方法。
来模拟一下BufferedReader
*/
import java.io.*;
class MyBufferedReader extends Reader
{
 private Reader r;
 MyBufferedReader(Reader r)//建立构造函数.一开始就要有流
 {
  this.r = r;
 }
 //可以一次读一行数据的方法。
 public String myReadLine()throws IOException
 {
  //定义一个临时容器。原BufferReader封装的是字符数组。
  //为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
  StringBuilder sb = new StringBuilder();
  int ch = 0;
  while((ch=r.read())!=-1)
  {
   if(ch=='\r')
    continue;//判断如果是\r的话在运行.判刑下个\n,如果是最后一行了.返回字符串
   if(ch=='\n')
    return sb.toString();
   else
    sb.append((char)ch);
  }

  if(sb.length()!=0)
   return sb.toString();
  return null;  
 }

 /*
 覆盖Reader类中的抽象方法。
 */
 public int read(char[] cbuf, int off, int len) throws IOException
 {
  return r.read(cbuf,off,len) ;
 }
 public void close()throws IOException
 {
  r.close();
 }
 public void myClose()throws IOException
 {
  r.close();
 }
}
class  MyBufferedReaderDemo
{
 public static void main(String[] args) throws IOException
 {
  FileReader fr = new FileReader("buf.txt");

  MyBufferedReader myBuf = new MyBufferedReader(fr);//自定义的装饰类

  String line = null;

  while((line=myBuf.myReadLine())!=null)
  {
   System.out.println(line);
  }
  myBuf.myClose();//关闭资源
 }
}
           

//---------------------------------------------------------------------------

        字节流

基本操作与字符流类相同

但它不仅可以操作字符,还可以操作其他 媒体文件

 InputStream类是字节输入流的抽象类,是所有字节流输入流的父类,InputStream类的具体层次结构

 InputStream

          |--AudioInputStream

          |--ByteArrayInputStream

          |--FileInputStream

                    |--BufferedInputStream

                    |--DataInputStream

                    |--等等.详情参阅API  java.io包中

           |--FilterInputStream

           |--InputStream

           |--ObjectInputStream

           |--PipedInputStream

           |--SequenceInputStream

           |--StringBufferInputStream

 常用方法:

  int  |available() 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

  void |close() 关闭此输入流并释放与该流关联的所有系统资源。

  void |mark(int readlimit) 在此输入流中标记当前的位置。

  boolean | markSupported() 测试此输入流是否支持 mark 和 reset 方法。

  abstract  int| read() 从输入流中读取数据的下一个字节。

  int |read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

  int |read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。

  void|reset() 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。

  long| skip(long n) 跳过和丢弃此输入流中数据的 n 个字节。

 OutputStream类是字节输入流的抽象类,次抽象表示输出字节流的所有类的超类.OutputStream

  OutputStream

         |--ByteArrayOutputStream

         |--FileOutputStream

                 |--BufferedOutputStream

                 |--DataOutputStream

                 |--等等.详情参阅API  java.io包中

         |--FilterOutputStream

         |--ObjectOutputStream

         |--OutputStream

         |--PipedOutputStream

  常用方法:

   void |close() 关闭此输出流并释放与此流有关的所有系统资源。

   void |flush() 刷新此输出流并强制写出所有缓冲的输出字节。

   void |write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。

   void |write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

   abstract  void |write(int b) 将指定的字节写入此输出流。

 FileInputStream 与 FileOutputStream 类

   FileInputStream类与FileOutputStream类都是用来操作磁盘文件的,如果用户的文件读取需求比较简单,测可以使用FileInputStream类.该类继承自InputStream类

  FlieOutputSream类与FileInputStreamLEI对应提供了基本的文件写入能力,FileOutputStream类是OutputStream类的子类.

示例:

/*
需求:拷贝一个图片
1.创建一个字符输入流和图片相关联.
2.用字节写入流对创建图片文件,用于存储到图片数据.
3.通过循环续写,完成数据的存储.
4.关闭资源.
*/
import java.io.*;
class  CopyPic
{
 public static void main(String[] args) 
 {
  FileInputStream fis=null;
  FileOutputStream fos=null;
  try
  {
   fis=new FileInputStream("D:\\2.jpg");//建立字符输入流对象和文件相关联
   fos=new FileOutputStream("copy.jpg");//建立字符输出流对象指定路径和文件名字
   byte[] buf=new byte[1024];//创建一个字符数组.用来缓存

   int num=0;//定义一个变量用于判断结尾处是否是-1

   while((num=fis.read(buf))!=-1)
   {
    fos.write(buf,0,num); //循环一次.字符数组输出一次.
   }
  }
  catch (IOException e)//处理异常
  {
   throw new RuntimeException("路径错误");
  }
  finally
  {
   try
   {
    if(fos!=null)//判断创建文件失败是否为null;
     fos.close();
   }
   catch (IOException e)
   {
    System.out.println("输出关闭失败");
   }
   try
   {
    if(fis!=null)
     fis.close();
   }
   catch (IOException e)
   {
    System.out.println("输入关闭失败");
   }
  }
 }
}
           

//------------------------------------------------------

用缓冲区技术拷贝Mp3

  BufferedInputStream buis=null;

  BufferedOutputStream buos=null;

  try

  {

   buis=new BufferedInputStream(new FileInputStream("D:\\Maid with the Flaxen Hair.mp3"));

   buos=new BufferedOutputStream(new FileOutputStream("copy.mp3"));

   int num=0;

   while((num=buis.read())!=-1)

   {

    buos.write(num);

   }

  }

  buis.close();

  buos.colse();

//-------------------------------------------------

InputStreamReader和OutputStreamWriter

InputStreamReader :

是字节流通向字符流的桥梁。

每次调用 InputStreamReader 中的一个 read()

方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。

构造方法:

  InputStreamReader(InputStream in)

  InputStreamReader(InputStream in, String charsetName)

 示例:

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

OutputStreamWriter :

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

将要写入流中的字符编码成字节

每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。

为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。

构造方法:

  OutputStreamWriter(OutputStream out)

  OutputStreamWriter(OutputStream out, String charsetName)

 示例:

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

 System.in 默认设备为键盘

     System.setIn(InputStream in)\\ 重新分配“标准”输入流。

 System.out 默认设备为控制台

     System. setOut(PrintStream out) \\重新分配“标准”输出流。

 PrintStream 的构造方法:

 PrintStream(String fileName)\\ 创建具有指定文件名称且不带自动行刷新的新打印流。

---------------------------------------------------------------------

异常的日志信息

  printStackTrace()//将此 throwable 及其追踪输出至标准错误流。

  printStackTrace(PrintStream s)// 将此 throwable 及其追踪输出到指定的输出流。

示例:

import java.io.*;
import java.util.*;
import java.text.*;
class  ExceptionInfo
{
 public static void main(String[] args)throws IOException 
 {
  try
  {
   int[] arr = new int[2];
   System.out.println(arr[3]);
  }
  catch (Exception e)
  {
   
   try
   {
    Date d = new Date();//建立日期类
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化日期
    String s = sdf.format(d);

    PrintStream ps = new PrintStream("exeception.log");//设置异常文件
    ps.println(s);
    System.setOut(ps);

    
   }
   catch (IOException ex)
   {
    throw new RuntimeException("日志文件创建失败");
   }
   e.printStackTrace(System.out);//异常信息
  }
 }
}
           

---------------------------------------------------------------------

获取系信息

方法:

 list(PrintStream out)// 将属性列表输出到指定的输出流

示例:

import java.io.*;
import java.util.*;
class  SystemInfo
{
 public static void main(String[] args) throws IOException
 {
  Properties prop=System.getProperties();
  
  //System.out.println(prop);
  prop.list(new PrintStream("sysinfo.txt"));
  //Properties中的list方法PrintStream创建具有指定文件名称且不带自动行刷新的新打印流。
 }
}
           

------- android培训、java培训、期待与您交流! ----------