黑马程序员->IO

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

................IO(Input Output)流
//  IO是用来处理设备之间的数据传输。 java对数据的操作是通过流的方式。 Java用于操作流的对象都在IO包中。
  流安操作数据分为两种:字节流与字符流。 流安流向分为:输入流和输出流。
        //IO 常用基类
   字节流的抽象基类: InputStream , OutputStream
   字符流的抽象基类: Reader , Writer
  //由这四个类派生出来的子类对象都是以父类名作为子类名的后缀。
           InputStream ---> 子类 FileInputStream
           Reader      --->  FileReader
1.0.........FileWriter
   //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
   //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
   FileWriter fw = new File Writer("demo.txt");//其实该步就是在明确数据要存放的目的地。
   fw.write("dfdf");//调用write方法,将字符串写入到流中。
   fw.flush();//该步将刷新对象中的缓冲数据到目的地中。
   fw.close();//关闭数据流,但是在关前会刷新数据到目的地中。
      //和 flush 区别,flush 刷新后,流可以继续使用。close 刷新后,会将流关闭。
2.0.....IOException
      FileWriter f = null;//因下面finally要关闭流,为避免找不到对象 f,所以先在外面定义。
     try{
      f = new FileWriter("a.txt");// 23行
      f.write("dfdjfk");
     }
     catch (IOException e)
     {}//为简化编译,该处先不写处理内容。
     finally{
      try{
       if(f!=null)//如果上面 23 行抛出异常,下面的关闭语句将出现找不到对象错误,
            //所以要在此处判断一下对象是否存在。
       f.close();//因该处会抛异常,所以写在 try 内。
      }
      catch (IOException e)
      {}    //简单的IO异常处理机制就写好了。 
2.1.文件的续写
    在创建对象的时候, FileWriter f = new FileWriter("a.txt",true);//该处重载方法支持 boolean 来决定是否覆盖。
    传入 true 就是表示有该文件的话,就不覆盖。并在数据结尾处 .Write 数据。
           //如没有则创建文件。
    f.write("dd\r\ndd"); //如要换行写数据,要用 \r\n 。单用\n的h话,windows的记事本不支持。
2.2.文本读取方式 1
    FileReader fr = new FileReader("a.txt");//和FileWriter 一样,只是和他反着,是读取流。
     //创建一个文件读取流,和指定的文件名关联。要保证该文件已存在,否则会出 FileNotFoundException (文件找不到)异常。
    fr.read();//调用读取流对象的read方法, 返回值为 int 型。
       read();一次只读一个字符,而且会自动往下读。如到文件结尾,则返回 -1 。
2.3.文本读取方式 2
    //.read(字符数组):read还可以接受一个字符数组。返回的是读到的个数 int 型。
    char[] buf = new char[1024];//定义一个字符数组,用于存储读到的字符。
    int num = 0; //建议数组大小定位 1024 的倍数。
    while((num=fr.read(buf))!=-1)//如果值不为-1即为 true,则继续循环。
    {
     System.out.println(new String(buf,0,num));//String 还可以接受角标位,打印从第几位到第几位。
    }
3.0..字符流的缓冲区
    //缓冲区提高了对数据的读写效率。
    对应类: BufferedWriter   BufferedReader
   // 缓冲区要结合流才可以使用。   在流的基础上对流的功能进行了增强。   
    FileWriter fw = new FileWriter("a.txt");//在创建缓冲区之前,必须要先有流。
       BufferedWriter bufw = new BufferedWriter(fw);
          //需要将被提高效率的流对象作为参数传递给缓冲区的构造函数。
    bufw.close();//关闭缓冲区就会关闭流------》所以不用再写 fw.close(); 了。
    bufw.newLine();//缓冲区提供的跨平台的换行符。
        \r\n 用于windows 平台 \n 用于linux 平台 ,如同newLine 的话它自己会选择相应平台。
    FileReader fr = new FileReader("a.txt");
    BufferedReader bufr = new BufferedReader(fr);//同写入流一样,只是同他相反。
    String s = bufr.readLine();//读一行,缓冲区特有方法。如到结尾,则返回 null。
    bufr.close();
3.1..装饰设计模式
//   当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
//   那么自定义的该类就称为装饰类。
   装饰类通常会通过构造方法接受被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。
         就像 BufferedReader(); 就装饰了 FileReader();
//   装饰和继承的区别 
      1. 装饰模式比继承要灵活,避免了继承体系臃肿。而且降低了类与类之间的关系。
      2.装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。
       So ,装饰类和被装饰类通常是都属于一个体系中的。
3.2....LineNumberReader
      带行号的读取。 属 BufferedReader 的子类。
4.0....字节流
     InputStream -->读   OutputStream -->写
     FileInputStream   FileOutputStream
  //同字符流操作方式一样。  FileInputStream fis = new FileInputStream("fis.txt");
    fis.available(); 可以获取要操作的文件的的大小(有多少个字节)。
    byte[] buf = new byte[fis.available()];//定义一个刚好文件大小的缓冲区,不再用循环了。
    fis.read(buf);
    S.op(new String(by));

    这里面定义的 byte 数组长度为 .available() ,是因为这样读出的数据和接受数据的数组大小一样,正好可以
   装下所有数据,因此不用再 while 遍历读取了,可以全部存下,然后打印。
     如果用【1024】大小的数组的话,不用遍历,会将全部 1024 个字符打印出去,包括没有字符的空数组。
    必须要用 while 和 -1 来判断读取全部有用字符。
4.1.字节流的缓冲区
   new BufferedInputStream(new FileInputStream("a.txt"));
   new BufferedOutputStream(new FileOutputStream("a_copy.txt"));
   //和字符流的用法基本一样。
4.2.读取键盘录入
   System.out :对应的是标准输出设备,控制台。
   System.in  :对应的标准输入设备,键盘。  
   InputStream in = System.in;//in接收键盘输入,返回的是InputStream 类型的字节流。
   int by = in.read();     //用字节流的读取方法,读出输入的内容。 为 int 型。
   S.op((char)by);      //把 int 型强转回 char 类型。
4.3.转换流         
   键盘录入要涉及到录入一行并打印,要涉及判断 /r /n ,否则将是一个一个字符打印,所以就是读一行的原理。
   而readLine()方法是字符流 BufferedReader 类中的方法,键盘录入的read方法是字节流 InputStream 方法。
   这时,就要使用 字节流 和 字符流 转换的方法。
   InputStreamReader   是字节流通向字符流的桥梁。 //都是对应的。InputStream 对应 Reader ,OutputStream 对应 Writer
   OutputStreamWriter 字符通向字节流的桥梁。
    BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in()));//键盘输入的常见写法。
    BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
    String line = null;
    while ((line=bufr.readLine())!=null)
    {
     if("over".equals(line))
      break;
     bufw.write(line.toUpperCase());
     bufw.newLine();
     bufw.flush();
    }
4.4.流操作规律
//    由于流对象过多,而不清楚要使用哪一个。所以要有三个明确:
    三个明确: 1. 明确源和目的。   源 :输入流: InputStream  Reader
             目的:输出流: OutputStream Writer
            2. 操作的是否为纯文本。  是: 字符流
//              不是: 字节流
      3. 体系明确后,再明确要使用哪个具体的对象。
        通过设备来进行区分:   源设备: 内存,硬盘,键盘。
              目的设备: 内存,硬盘,控制台。
   如果,
    存储时,要加入指定编码表 utf-8 ,只有转换流可以指定编码表,就要用 OutputStreamWriter
    而转换流对象需要接受一个字节输出流,而且是可以操作文件的字节输出流 FileOutputStream
     OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
     BufferedWriter bufw = new BufferedWriter(osw);
    //如果不指定编码,转换流默认的是 GBK 编码。
  还可以改变标准输入输出设备。
     System.setIn(new FileInputStream("a.txt"));
     System.setOut(new PrintStream("b.txt"));
4.5.异常日志信息
    log4j;
   
5.0.......................................File 类
//   用来将文件或者文件夹封装成对象。  方便对文件与文件夹的属性信息进行操作。
//    File 对象可以作为参数传递给流的构造函数。
   File 类常见方法
    1.创建  boolean createNewFile();//在指定位置创建文件,如果已存在,则不创建。返回 false.
            //和输出流不一样,输出流对象一创建文件,如果以存在,将会覆盖。
      boolean mkdir(); //创建文件夹
      boolean mkdirs();//创建多级文件夹
    2.删除  boolean delete();//删除失败返回false,如果文件正在被使用,则删除不了,返回 false.
      void deleteOnExit();//在程序退出时,删除指定文件。
    3.判断  boolean exists(); //文件是否存在。
      isFile();//  是否为文件
      isDirectory();//是否为目录
      isHidden();// 是否是隐藏文件
      isAbsolute();// 是否为绝对路径
    4.获取信息   getName();// 获取名字
        getPath();// 获取路径
        getParent();// 获取父目录,对象创建时没有写明父目录的话(相对路径),返回为 null
        getAbsolutePath();// 获取绝对路径
        long lastModified();// 最后一次修改时间
        long length();//  获取文件大小
5.1.....File 类--文件列表
      File f = new File("c:\\a.txt");
      String[] names = f.list();//调用list方法的file对象必须是封装了一个目录,该目录还必须存在。
      for (String name: names)//list 方法是返回所在目录的列表。该列表是一个字符数组,所以用String接受。
      {  //后用 forecho 来遍历输出。
       S.op(name); 
      }
      File[] files = File.listRoots();//获取到本机所有根目录(盘符)。
  递归:
    列出指定目录下文件或者文件夹,包含子目录中的内容。就是列出指定目录下所有内容。
   因为目录中还有目录,只要使用同一个列出目录功能的函数即可。
//   如列出过程中出现的还是目录的话,还可以再次调用本功能。也就是函数自身调用自身。
   这种表现形式,或者变成手法,称为递归。
  递归注意:
     1.限定条件。
     2.要注意递归的次数,尽量避免内存溢出。
   public static void show(File dir){
    File[] files = dir.listFiles();
    for (int x=0; x<files.length; x++)
    {
     if(files[x].isDirectory())
     show(files[x]);
     S.op(files[x]);
    }
5.2.Properties 类
    Properties 是hashtable 的子类。
    也就是说他具备 Map 集合的特点,而且他里面存储的键值对都是字符串。是集合中和 IO 技术相结合的集合容器。
    该对象的特点:可以用于键值对形式的配置文件。
    那么在加载数据时,需要数据有固定格式: 键 = 值。
  
  继承至 Hashtable ,是 Map 集合的一种。用 setProperty(); 方法可以直接设置键和值。用 getProperty(); 方法通过键获得值。

  本类 1.6 新加入方法 stringPropertyNames(); 可以返回 String 类型的 Set 集合,获取所有键。在用 getProperty() 方法

  获取对应的值即可。

  Properties 可以从配置文件中读取数据。定义一个文件读取字节流,并关联响应配置文件。用 load(你定义的读取流); 方法。

  用 list(); 可以获取取出的存入 Properties 中的键值数据。
   
  用 store(FileOutputStream); 可以将改动保存到文件中。要 new 输出流并关联要保存的文件。

5.3.打印流
//    该流提供了打印方法,可以将各种数据类型的数据都按原样打出。
    PrintStream  构造函数可以接受的参数类型: 1. file对象 , File
             2. 字符串路径。 String
             3. 字节输出流。 OutputStream
   PrintWriter  构造函数可以接受的参数类型: 1, file对象, File
               2, 字符串路径, String
               3, 字节输出流, OutputStream
               4, 字符输出流, Writer
5.4.SequenceInputStream 合并流

   //可以将多个流合并成一个流,既是合并文件。
   SequenceInputStream 构造函数可以接收,两个 InputStream 流,或一个 InputStream 对象的 Enumeration 参数。
      //将这两个流合并成一个流,或将 Enumeration 的元素合并成一个文件。
   '只有 Vector 集合有获得 Enumeration 方法,Enumeration 是老的枚举,jdk 1.0 版本,已过时,不再使用。
                  
  Vector<FileInputStream> vector = new Vector<FileInputStream>();
            //因只有 Vector 有该方法,定义一个 Vector 集合。
  vector.add(new FileInputStream("first.txt"));//泛型限制只接受 FileInputStream 流对象。      
  vector.add(new FileInputStream("second.txt"));
            //为 Vector 添加两个本地文件。
  Enumeration<FileInputStream> enumeration = vector.elements();
           //调用 Vector 的方法生成 Enumeration 对象。
  SequenceInputStream sequenceInputStream = new SequenceInputStream(enumeration);
            //将 Enumeration 传递给 SequenceInputStream 。
  FileOutputStream fileOutputStream = new FileOutputStream("third.txt");
            //定义输出流,接收合并后的文件。
  int len = 0;  byte[] buf = new byte[1024];
            //字节流读取方法。
  while((len=sequenceInputStream.read(buf))!=-1){
   fileOutputStream.write(buf,0,len);
  }
   fileOutputStream.close();
   sequenceInputStream.close();

5.5.切割流

5.6.操作对象 ---对象的序列化
   ObjectInputStream
   ObjectOutputStream
//   被操作的对象要实现  serializable
   ObjectOutputStream oos =
    new ObjectOutputStream(new FileOutputStream("某个类.object"));
   oos.writeObject('某个类');
   oos.close();
   //可以将对象持久化存储。但该对象要实现 serializable 接口,该接口称为 标记接口 ,没有任何方法需要去覆盖。
   //该接口会使对象序列化,序列化方法由各成员变量决定,如成员有改变,则序列化ID 也会改变。
   想要某个成员不被序列化,可在前加入 transient 修饰符,另,静态成员不会被序列化。

5.7.管道流
    PipedInputStream
    PipedOutputStream
   //一般数据读取,需先存入数组中,在对数组进行操作,使用该类的话,可同时对数据进行操作。所以容易造成死锁,
   需用多线程技术,分开线程调用该输入流和输出流。
//    两管道流间用输入流的  .connect(输出流); 来进行接通。
   
6.随机访问流
   RandomAccessFile
   该类是 Object 的子类,但是他是 IO包中的成员,因为他具备读和写功能。内部封装了一个数组,而且通过指针对数组

  对数组的元素进行操作。可以通过 getFilePointer 获取指针位置,同时可以通过 seek 改变指针的位置。
        //其实完成读写的原理就是内部封装了字节输入流和输出流。
  通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式:只读 r ,读写 rw 。

  如果模式为只读 r ,不会创建文件,回去读取一个已存在的文件。如果该文件不存在,则会出现异常。

  如果模式为 rw ,操作的文件不存在,会自动创建。如果存在则不会覆盖。

6.1.....操作基本数据类型的留对象
   DataOutputStream  DataInputStream
   //该流对象可以直接操作基本数据类型
   DataOutputStream 中的 writeInt();  writeBooleam();  writeDouble();  writeLong();
          writeUTF(); //等....
    //直接按响应格式写入,不用转换。

6.2.....ByteArrayInputStream
    操作字节数组 ByteArrayInputStream 和 ByteArrayOutputStream
    操作字符数组 CharArrayReader 和 CharArrayWriter
    操作字符串   StringReader 和  StringWriter
    
   ByteArrayInputStream, 在构造的时候,需要接收数据源,而且数据源是一个字节数组。

   ByteArrayOutputStream, 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是
        //数据目的地。
   //因为这两个六队西哪个都操作的数组,并没有使用系统资源,所以,不用关闭流。
6.3..字符编码
  '字符流的出现是为了方便操作字符。    更重要的是加入了编码转换。
  通过子类转换流来完成 : InputStreamReader
          OutputStreamWriter
  //在两个对象进行构造的时候可以加入字符集。
  '编码表的由来
     计算机只能识别二进制数据,早期由来是电信号。
     为了方便应用计算机,让他可以识别各个国家的文字。
     就将各个国家的文字用数字来表示,并一一对应,形成一张表。//就是编码表。
   
   ASCII -- 美国标准信息交换吗,用一个字节的7位可以表示。
   ISO8859-1 - 拉丁码表。 欧洲码表。用一个字节的8位表示。
   GB2312    - 中国的中文编码表。
   GBK       - 中国的中文编码表升级,融合了更多的中文字符号。
   Unicode   - 国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java 语言使用的就是 UNICODE
   UTF-8     - 最多用三个字节来表示一个字符。

 

 

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值