`
小驴变黑马
  • 浏览: 12073 次
文章分类
社区版块
存档分类

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

阅读更多
---------------------- android开发java培训、期待与您交流! ----------------------
转换流
 转换流是字符流与字节流之间的桥梁,是为了方便字符流与字节流之间的操作。
 当字节流中都是字符时,转成字符流操作更为高效,
 例如:能不能使用readLine方法完成键盘录入的一行数据的读取呢,但是readLine是BufferedReader的方法,
  而System.in是InputStream的方法,这样就用到了转换流(InputStreamReader)
 InputStreamReader是一个字符流,要想转换字节流那就要在构造函数的时候把字节流当参数传入
 读取转换流
  BfferedReader bufr =
    new BufferedReader(new InputStreamReader(System.in));
 写入转换流:字符转字节,比如录入的是字符,把它存到硬盘上是字节
  BufferedWriter bufw =
    new BufferedWriter(new OutputStreamWriter(System.out));
 
转换流规律:
 操作流的时候流对象有很多该用哪个呢?通过三个明确来完成。
 1.明确源和目的  有的时候可能只有源或目的,要先明确
  源:因为是源所以使用读取流,即 InputStream ,Reader
  目的: 写入流 即 OutputStream , Writer
 2.明确操作的数据是否为纯文本  即是明确用字节流还是字符流
  是:用字符流
  不是:用字节流
 3.明确设备  就是明确用那个对象,就是看用不用转换流
  源设备: 内存 ,硬盘 ,键盘
  目的设备:内存 ,硬盘,控制台
  然后再确定下需不需要提高效率,就是确定需不需要缓冲流。
 例如:
 1,将一个文本文件中数据存储到另一个文件中。复制文件。
  这个明确了源和目的都有,
  源:InputStream  Reader
  是纯文本吗?是。明所以用字符流 就是Reader
  源设备:硬盘  不需要转换流
  这时候就可以确定了用 FileReader
  是否需要提高效率?是。加入缓冲区 BufferedReader、
  FileReader fr = new FileReader("Demo.txt");
  BufferedReader bfr  = new BufferedReader(fr);
  目的:OutputStream    Writer
  是纯文本吗?是。所以用字符流 Writer.
  目的设备:硬盘  不需要转换流。
  所以就可以确定用 FileWriter了。
  是否需要提高效率?是。加入缓冲区 BufferedWriter
  FileWriter fw = new FileWriter();
  BufferedWriter bfw = new BufferedWriter(fw);
 2,需求:将键盘录入的数据保存到一个文件中。
  
  明确1这个既有源也有目的
  源: InputStream   Reader
  是否为纯文本?是,键盘录入的也是字符,用Reader
  源设备:键盘。对应的对象是 System.in。这时就想了上面不是明确了用Reader了吗,但是
  System.in是字节流啊,所以既然明确了用Reader这时就需要用转换流了InputStreamReader。
  需要提高效率吗?需要。所以要用BufferedReader。
  InputStreamReader isr = new InputStreamReader(System.in);
  BufferedReader bfr = new BufferedReader(isr);
  目的:OutputStream   Writer
  是否为纯文本?是, 用Writer
  目的设备:一个文件文件 在硬盘 不需要转换流,可以确定用FileWriter
  FileWriter fw = new FileWriter("Demo.txt");
  需要提高效率吗?需要。
  BufferedWriter bufw = new BufferedWriter(fw);
--------------------------------------------------------------------------------------------
 
 扩展:想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
  源和上面的一样,不变。
  目的:OutputStream  Writer
  是否为纯文本?是,Writer
  目的设备:硬盘 一个文件  用 FileWriter
  FileWriter是按默认的编码(GBK)存的。但是要求按照指定的编码(utf-8)存数据
  而指定编码表只有转换流能制定,所以使用的对象是OutputStreamWriter,而转换流
  又要接收一个字节流,而且该字节流还能操作文件,所以就是 FileOutputStream
  需要提高效率吗?需要。所以要用到BufferedReader
  OutputStreamWriter osw = 
    new OutputStreamWriter(new FileOutputStream("Demo.txt"),"UTF-8");
  所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
  需要用到转换流。
 改变标准输入输出流设备:
  系统默认的标准输入输出设备是 System.in 和 System.out
  但是可以通过System类中setIn,setOut方法对默认设备进行改变。
  System.setIn(new FileInputStream(“1.txt”));//将源改成文件1.txt。
  System.setOut(new FileOutputStream(“2.txt”));//将目的改成文件2.txt
---------------------------------------------------------------------------------------------------------------------------------
 
File类
 流在操作的只有数据,而数据最明显的体现形式就是文件,文件又包含了很多的属性和行为信息,
 比如说前缀名、扩展名、文件自己的大小时间等,所以文件是一个复杂的事物而这个事物有很多,
 所以java就对文件这类的事物进行了描述,也把它封装成了对象,方面了我们对文件或文件夹的
 属性进行操作。而File类的对象也主要用来获取文件本身的一些信息,如文件大小权限等,不涉
 及对文件的读写操作。
 查看API知道java提供了三种创建方法来生成一个文件对象。
 (1)根据参数指定的文件路径创建一个File文件对象,就是把某个文件封装成对象
  File file1  = new File("D:\\abc\\123.txt");
 (2)根据给定的目录创建一个File实体对象,其中"d:\\abc"为目录,"123.txt"为文件的名称
  File file2  = new File("D:\\abc","123.txt");
 (3)可以根据已知的目录文件对象File创建一个新的File实体对象
  File d = new File("D:\\abc");
  File file3 = new File(d,"123.txt");
 File类所提供的方法中,有的是针对文件的处理,有的是针对目录的处理,可以通过一些方法来
 判断文件是否存在以及文件的相对路径和绝对路径等,File类的常见方法有:
 1,创建。
  boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
      和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
  boolean mkdir():创建目录文件夹。
  boolean mkdirs():创建多级文件夹。
 2,删除。
  boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
  void deleteOnExit();在程序退出时删除指定文件。
 3,判断。
  boolean exists() :文件是否存在.
  isFile(): 是否为文件
  isDirectory();是否为目录
  isHidden();
  isAbsolute();
 4,获取信息。
  getName()://获取文件名
  getPath()://获取相对路径
  getParent()://返回的绝对路径的文件父目录
  getAbsolutePath() //获取绝对路径
  long lastModified() 
  long length() 
 部分代码:
  
class  FileDemo
  {
   public static void main(String[] args) throws IOException
   {
    File f = new File("abc.txt");//把文件封装成对象
     sop(f.createNewFile());//创建一个文件创建成功返回true,如果已存在创建不成功,返回false
    File f = new File("abc");
    sop(f.mkdir());//创建一个目录,mkdirs能创建多级目录
   //在判断文件对象是否是文件或者目录时,一定要先判断该文件对象封装的内容是否存在
    isexists();//因为封装了一个文件对象,如果没创建的话,系统里就没有的所以要先判断下。
    isFile();//判断你创建的是否为文件
    isDirectory();//判断是否为目录
    File f = new File("abc\\abc.txt");
    getParent();//获取绝对路径的文件父目录,你创建时是相对路径会返回null
       //如果相对路径中有上一层目录那么该目录就是返回结果。如上返回父目录abc
   
   }
   public static void sop(Object obj)
   {
    System.out.println(obj);
   }
  }
 文件列表:
 listRoots();//能列出我们机器里面有效的盘符,它是一个静态方法,返回的是File数组
 String[] list();//返回值类型是是String数组,
 File f = new File("d:\\");
 Stringp[] names = f.list();//打印的是d盘下所有文件和文件夹的名称,所以返回的是字符串数组
       //但是要确定调用list方法的File对象必须是封装了一个目录,并且该目录还必须存在  
 for(String name : names)//不然你封装了一个文件对象,那它返回的数组就为null,那就不能遍历数组了
 {
  System.out.println(name);
 }
 File[] files = f.listFile();
 for(String file : files)
 {
  System.out.println(file.getName()+"::"+file.length());//因为返回的是文件对象仍然能调用方法
 }
---------------------------------------------------------------------------------------------------------------------------------- 
 
递归:在遍历文件夹的时候,遍历的结果中仍有文件夹,这事是不是还要在遍历一次啊,比如说,你打开d盘
   里面是不是有很多文件夹啊,然后是不是就要点开看看啊,然后里面还有文件夹是不是还要打开?这
   样是不是在重复一个操作,就是遍历文件夹里的元素,里面有文件夹的话就再遍历....这样我们在
   写代码的时候是不是再重复用同一个方法,就是用一个方法遍历文件夹,如果里面有文件夹的话,就在
   调用本方法。也就是函数自身调用自身。这种编程手法就是递归。
   部分代码:
   
  
class  FileDemo
  {
   public static void main(String[] args) throws IOException
   {
    File dir = new File("f:\\javademo");
    showDir(dir);
   }
   public static void showDir(File dir)
   {
    File[] files = dir.listFiles();
    for(int x=0; x
    {
     if(files[x].isDirectory())//判断,如果便利中碰到文件夹
      showDir(files[x]);//就再调用此方法进行遍历
     else
      System.out.println(files[x]);
    }
   }
  }
   递归要注意:
  1,限定条件。没条件限定的话,函数里面又调用它自身不就相当于死循环啦。
  2,要注意递归的次数。尽量避免内存溢出。每次递归都会在栈内存中开辟空间,不限定的话会内存溢出
------------------------------------------------------------------------------------------------------------------------------------ 
 
Properties类:
 Properties是hashtable的子类。一个可以将键值进行持久化存储的对象。
 也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。
 是集合中和IO技术相结合的集合容器。
 
 该对象的特点:可以用于键值对形式的配置文件。
 那么在加载数据时,需要数据有固定格式:键=值。
 特点:
 1:可以持久化存储数据。
 2:键值都是字符串。
 3:一般用于配置文件。
   |-- load():将流中的数据加载进集合。
    原理:其实就是将读取流和指定文件相关联,并读取一行数据,因为数据是规则的key=value,所以获
  取一行后,通过 = 对该行数据进行切割,左边就是键,右边就是值,将键、值存储到properties集合中。
  |-- store():写入各个项后,刷新输出流。
  |-- list():将集合的键值数据列出到指定的目的地。
--------------------------------------------------------------------------------------------------------------------------------
 
IO包中的其他类:
 打印流 
  PrintWriter与PrintStream 可以直接操作输入流和文件。该流提供了打印方法,可以将各种数据类
  型的数据都原样打印。
  字节打印流:PrintStream  
   构造函数可以接收的参数类型:
   1,file对象。File
   2,字符串路径。String
   3,字节输出流。OutputStream
  字符打印流:PrintWriter
   构造函数可以接收的参数类型:
   1,file对象。File
   2,字符串路径。String
   3,字节输出流。OutputStream
   4,字符输出流,Writer。
-----------------------------------------------------------------------------------------------------------------------------------
 序列流  
  SequenceInputStream 对多个流进行合并。它的构造函数接收的是两个输入流,或者是接收一个输
   入流的枚举。
  比如说要把三个文件的内容复制到另一个文件中,是不是要一个一个的重复Copy文件的那个动作啊,
  就是每复制一个文件都要创建一个写入流和输出流,然后再进行读写操作,复制三个文件是不是就
  要重复三次啊,并且创建目的文件的时候还要写成可续写格式,不然就会被覆盖掉,而序列流就解
  决了这个问题,他可以把多个流合并在一起,然后再进行其他操作。
  
  //把三个文件复制到另一个文件中 部分代码:
 
 public static void main(String[] args) throws IOException
  {
   //枚举只有list集合里的vector有所以要创建一个集合来装输入流
   Vector v = new Vector();
   //把三个文件的读取流对象添加到集合里
   v.add(new FileInputStream("d:\\1.txt"));
   v.add(new FileInputStream("d:\\2.txt"));
   v.add(new FileInputStream("d:\\3.txt"));
   //获取集合的枚举Enumeration
   Enumeration en = v.elements();
   //将输入流的枚举传给序列流,之后操作这个流就行了
   SequenceInputStream sis = new SequenceInputStream(en);
   //创建一个写入流再然后进行频繁的读写就行了
   FileOutputStream fos = new FileOutputStream("c:\\4.txt");
   byte[] buf = new byte[1024];
   int len =0;
   while((len=sis.read(buf))!=-1)
   {
    fos.write(buf,0,len);
   }
   fos.close();
   sis.close();
  }
  能合并就能切割://切割一图片  
  public static void spilt() throws IOException
  {
   FileInputStream fis = new FileInputStream("E:\\0.PNG");
   FileOutputStream fos = null;
   byte[] arr = new byte[1024*1024];
   int len = 0;
   int x=1;
   //每一次循环是不是都创建了一个流就是创建了一个文件啊?
   while((len=fis.read(arr))!=-1)
   {
    fos=new FileOutputStream("E:\\spilte\\"+(x++)+".part");
    fos.write(arr,0,len);
    fos.close();
   }
   fis.close();
  }
 ------------------------------------------------------------------------------------------------------------------------------  
 
 操作对象的流
  ObjectInputStream与ObjectOutputStream 被操作的对象需要实现Serializable (标记接口);
  流是可以操作数据的,现在数据被封装成对象了,我们知道对象是存放在堆内存中的,用完之后
  就成了垃圾了,一被清理之后这个对象是不是就不存在了?而现在讲的这个流就可以操作对象,
  把这个对象的数据存放在硬盘上,对象里都封装了一些数据,那这些数据是不是就随着对象也存到
  了硬盘上啦?这样的话即使这个程序结束了对象被清理了,我们是不是仍然能够获得这个对象里的
  数据啊,因为它已经被存放到硬盘上了。
  另外操作的那个对象的类要能被序列化,某个类要想能被序列化,就得实现java.io.Serializable 接口。
 
  部分代码:
   ObjectOutputStream的目的是把对象和流相结合,是不是先把对先把流当参数传给它啊,所
   以ObjectOutputStream在构造函数时一定要接收个流,什么流呢?就是把对象怎么着的流?也
   就是目的。
   
   //既然要把对象写进文件那就要创建一个写入流
   FileOutputStream fos = new FileOutputStream("t.tmp");
   //把写入流当参数传给ObjectOutputStream
   ObjectOutputStream oos = new ObjectOutputStream(fos);
   //操作的这类person对象的类要实现Serializable接口
   oos.writeObject(new Person());//将指定对象写入ObjectOutputStream。
   oos.writeInt(12345);
   oos.close();
-----------------------------------------------------------------------------------------------------------------------------------------
 
 管道流
  PipedInputStream和PipedOutputStream输入输出可以直接进行连接,通过结合线程使用。
  管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据
  由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。
  不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在
  缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,
  则认为该管道已损坏。 
 -------------------------------------------------------------------------------------------------------------------------------------
 
 RandomAccessFile类
  该类不是算是IO体系中子类。而是直接继承自Object。但是它是IO包中成员。因为它具备读和写
  功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获
  取指针位置,同时可以通过seek改变指针的位置。
  其实完成读写的原理就是内部封装了字节输入流和输出流。
  通过构造函数可以看出,该类只能操作文件。而且操作文件还有模式:只读r,,读写rw等。
 
  如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
  如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。
  java语言提供了一个RandomAccessFile类来处理对一部分文件的输入/输出。RandomAccessFile类
  创建的流于前面的输入输出流不一样,它既不是输入流InputStream的子类也不是输出流类OutputS-
  -tream的子类,但是RandomAccessFile类创建的流的指向既可以做为源也可以作为目的,换句话说
  如果相对一个文件进行读取操作时,可以创建一个指向该文件的RandomAccessFile流,这样既可以
  从这个流中读取文件的数据,也可以从这个流中写入数据到文件。
  可以用以下两种方式打开一个随机存取文件:
 字符编码
  字符流的出现为了方便操作字符。更重要是的加入了编码转换。
  通过子类转换流来完成。 InputStreamReader OutputStreamWriter
  在两个对象进行构造的时候可以加入字符 集。
  编码:字符串变成字节数组。
  解码:字节数组变成字符串。
  String-->byte[];  str.getBytes(charsetName);
  byte[] -->String: new String(byte[],charsetName);
 部分代码:
  class  EncodeDemo
  {
   public static void main(String[] args)throws Exception 
   {
    String s = "哈哈";
    byte[] b1 = s.getBytes("GBK");
    System.out.println(Arrays.toString(b1));
    String s1 = new String(b1,"utf-8");
    System.out.println("s1="+s1);
    //对s1进行iso8859-1编码。
    byte[] b2 = s1.getBytes("utf-8");
    System.out.println(Arrays.toString(b2));
    String s2 = new String(b2,"gbk");
    System.out.println("s2="+s2);
    
   }
  }
 
---------------------- android开发java培训、期待与您交流! ----------------------
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics