Java基础--------IO流

来源:互联网 发布:淘宝视频制作教程 编辑:程序博客网 时间:2024/04/29 17:47

                                            

                               IO流(一)


IO概述:IO(Input/Output),即输入/输出;泛指对某个设备或环境进行数据的数据或输出。

 例如:对硬盘进行输入输出,对视频设备进行输入输出,对网络主机进行输入输出等。

    我们可以想象,因设备或环境的不同,会有各式各样的输入输出问题与解决方案。对于输入输出问题,Java将之抽象为流对象来解决。对不同的输入输出问题,会有相应的流对象提供解决方案。


IO流:IO流用来处理不同设备间的数据传输。Java中用于操作流的对象都封装在IO包中。


IO流分类:
A:按操作数据不同:字节流和字符流
B:按数据的流向不同:输入流(读取数据)和输出流(写入数据


这点儿注意啦:不知道有没有和我一样的,老是记反,总是觉得输入流就是往里面写入数据的,输出流才是读取数据,看过视频后终于明白了,一定要明白自己站的角度,咱们是Java程序的编写者,始终都是从某个地方读取数据,然后再写入到指定的地方。


字节流比字符流出现事的要早,而且以后对字符流搞不懂的话,永远用字节流它也肯定不会报错,因为没有字符流的时候,字节流也什么都能做。说到这儿,肯定会有人问那字符流有什么用呢?

    字符流一次能读一个字符,相当于两个字节,说白了就是一个汉字,而字节流一次只能读8个字节,也就是一个字符,所以字符流的出现就是为了解决文本数据的问题。有时候为了操作的方便,我们使用字符流。


那到底什么时候使用字符流呢?  通过windows自带的记事本,能够把这个文件打开,并且里面的内容你还能够读懂,这样的文件就可以使用字符流 。否则使用字节流。


在正式了解Java中如何处理文件的输入输出之前,我们需要了解Java是如何表示一个文件的:

    我们硬盘上数据最常见的方式就是以文件存在的,而文件本身有很多的属性,比如说:文件大小,是否可读啊,是否隐藏啊。那么,java为了方便操作这些文件,Java就在IO包中提供了File类对文件本身进行封装。

    File类中定义了一些与平台无关的方法供我们来操作文件。例如创建、删除、重命名文件等。在Java中,目录也是用File类来进行封装的。


File对象可以作为参数传递给流对象的构造方法。


下面我们一起通过学习API,来掌握File类常见方法的使用吧~~


File既可以表示文件,也可以表示文件夹。(目录)
 1)构造方法:

     File(String pathname):根据指定的路径创建File对象。
     File(String parent, String child):根据指定的父文件夹和子文件或者文件夹创建File对象
     File(File parent, String child):根据指定的父文件夹对象和子文件或者文件夹创建File对象


在这儿写一个小的Demo来帮助记忆:

public class FileDemo {public static void main(String[] args) {// 方式1File file = new File("d:\\a.txt");File file2 = new File("d:\\aaa");// 方式2File file3 = new File("d:\\", "a.txt");File file4 = new File("d:\\", "aaa");// 方式3File file5 = new File("d:\\");File file6 = new File(file5, "a.txt");File file7 = new File(file5, "aaa");}}


2)成员方法:

    1:创建功能

                创建文件:public boolean createNewFile()     -- -- -- 如果指定的文件不存在,就创建。如果存在,就不创建。
            创建文件夹:public boolean mkdir()       -- ---- -- 创建指定的目录,如果存在,就不创建。

                                                                            当且仅当已创建目录时,返回true;否则返回false
                               public boolean mkdirs() --- -- --创建指定的目录,如果存储,就不创建。

                          这个时候注意,如果父目录不存在,它也会自动创建。


         在这儿引用老师的一句话:你要创建什么,自己最清楚。也就是说你要调用哪个方法,你自己必须明白,如果你不明白,就会出问题的!

       

               什么问题呢? 就是如果你明明想创建文件,却调用了创建创建文件夹的方法,最终也会创建成功,但是却是文件夹。所以大家有时候在网上看到例如.txt 结尾的,未必是文件,也有可能是文件夹。就像骑白马的不一定是王子,可能是叫花子。哈哈哈哈~~~~  好了,下面言归正传:

     

        绝对路径:以盘符开始的路径。
        相对路径:不以盘符开始的路径。


附个小练习,帮助理解:

public class FileDemo {public static void main(String[] args) throws IOException {//创建文件File file=new File("d:\\a.txt");        System.out.println("createNewFile():"+file.createNewFile()); //file.createNewFile():true                // 创建文件 忘了写路径名称了,以当前项目路径所在路径为父目录        File file1=new File("b.txt");        System.out.println("createNewFile():"+file1.createNewFile());//file1.createNewFile():true               // 创建目录        File file2=new File("ccc");        System.out.println("mkdir():"+file2.mkdir()); //mkdir():true             // 创建多级目录 如果想创建一个指定的目录或者文件,要求父目录必须存在。所以下面打印的是false        File file3=new File("bbb\\ccc");        System.out.println("mkdir():"+file3.mkdir());  //mkdir():false             // 解决方案:        File file4=new File("bbb");        File file5=new File(file4,"ccc");        System.out.println("mkdir:" + file4.mkdir());//mkdir:true        System.out.println("mkdir:" + file5.mkdir());//mkdir:true    // 但是如果目录过多,这样做就太麻烦。肿么办呢?          File file6=new File("ddd\\eee");        System.out.println("file6.mkdirs()"+file6.mkdirs());                //创建文件           File file7=new File("f.txt");        System.out.println("file7.mkdir()"+file7.mkdir());        } }


下面是运行后的结果:

                 

2:删除功能

          public boolean delete():既可以删除文件,也可以删除文件夹。取决于你使用的对象。


删除功能比较好理解,但是有两点需要特别注意:

            A:如果你删除的目录下还有内容,那么,必须先把所有内容删除完毕后,再删除目录。
            B:java语言的删除不走回收站。


下面附上小练习:(接着上面的创建过的文件夹和文件,做的删除)


import java.io.File;public class FileDelete {public static void main(String[] args) {// 需求:我要删除a.txtFile file = new File("b.txt");System.out.println("delete:" + file.delete());// 需求:我要删除aaaFile file2 = new File("ccc");System.out.println("delete:" + file2.delete());// 需求:我要删除bbbFile file3 = new File("bbb");System.out.println("delete:" + file3.delete());} }
运行后结果为:

                                                                               

    大家可以对比上面两次截图,可以发现,前两个删除成功,最后一个没有删除掉,这是因为bbb目录下面还有东西,必须删除所有内容后,目录bbb才能删除成功。

 3:判断功能

   boolean exists(): 判断file对象是否存在
 
      boolean isFile(): 判断file对象是否是文件
 
      boolean isDirectory(): 判断file对象是否是文件夹
 
      boolean isAbsolute(): 判断file对象是否是绝对路径
 
       boolean canRead(): 判断file对象是否可读
 
      boolean canWrite(): 判断file对象是否可写
       boolean isHidden(): 判断file对象是否隐藏

4:获取功能

       String getAbsolutePath(): 绝对路径
       String getPath(): 相对路径
       String getName(): 文件名称
       long length(): 文件大小,单位是字节
       long lastModified(): 上次修改时间的毫秒值。

5:获取功能(特殊且重要)

       public static File[] listRoots():  列出可用的系统文件根目录
       public String[] list():  返回的是指定目录下所有文件或者文件夹的名称数组
       public File[] listFiles():  返回的是指定目录下所有文件或者文件夹对象数组


最后综上,写几个案例:1、获取指定目录下所有.mp4文件的名称。

import java.io.File;/** * 需求:获取指定目录下所有的.mp4文件的名称。 * 思路: 1、封装指定目录 *        2、获取指定目录下所有的文件或者文件夹File数组 *        3、遍历该对象是否是文件 *        4、判断该对象的后缀名是否是以.mp3结尾。 */      public class FileTest {public static void main(String[] args) {//1、封装指定目录File f=new File("f:\\");// 2、获取指定目录下所有的文件或者文件夹File数组File[] fileArray=f.listFiles();//3、遍历File数组,获取得到每一个File对象for(File file:fileArray){//判断该对象是否是文件if(file.isFile()){String fileName=file.getName();//判断该对象的后缀名是否是.mp3结尾的if(fileName.endsWith(".mp3")){System.out.println(fileName);}}}}}


输出结果:



方法二:用文件名称过滤器改进版:

import java.io.File;import java.io.FilenameFilter;/** * 获取指定目录下指定后缀的文件名称: * 1、先获取指定目录下的所有文件或者文件夹的File数组,然后再遍历的时候判断,满足条件的就输出。 * 2、直接获取指定目录下所有满足条件的File数组,然后遍历数组即可。 *   文件名称过滤器:FilenameFilter * public String[] list(FilenameFilter filter) */public class FileTest1 {public static void main(String[] args) {//封装文件目录File file=new File("d:\\");//获取满足条件的数组String[] strArray=file.list(new FilenameFilter() {@Overridepublic boolean accept(File dir, String name) {File f=new File(dir,name);// d:\我的文档//判断文件是否以.mp3结尾boolean flag=f.isFile();boolean  flag1=name.endsWith(".mp3");return flag&&flag1;}});//遍历字符串数组,输出所有满足条件的目录for(String str: strArray){System.out.println(str);}}}


2、删除指定的目录(目录里面带有目录或文件)。

import java.io.File;/** * 需求:删除指定目录(目录里面带有目录或文件) * 思路: *    1、封装目录 *    2、获取该目录下的所有文件或文件夹的File数组  *    3、遍历File数组,获取每一个File对象 *    4、判断该File对象是否为目录 *                        是:返回第二步 *                        否:删除文件  */public class FileDelete1 {public static void main(String[] args) {File file=new File("ddd");deleteFiles(file);}private static void deleteFiles(File file) {File[] fileArray=file.listFiles();if(fileArray!=null){for(File f:fileArray){if(f.isDirectory()){deleteFiles(f);}else{System.out.println(f.getName()+"***"+f.delete());}}// 如果for循环结束,就表示目录下的文件被删除完毕。System.out.println(file.getName()+"***"+file.delete());}}}


运行结果(没刷新之前)为:

                                               

刷新之后:

                          


介绍完File类,接下来才真正进入IO流的详细讲解啦~~

  1)IO流的分类:

                字节流  

                           字节输入流     读取数据       InputStream

                           字节输出流     写入数据      OutputStream

               字符流                                       
                            字符输入流     读取数据      Reader
                            字节输出流     写入数据      Writer

  注:本来想画个图呢,这样会更清晰,看视频上老师讲课时都会画图,帮助理解,但试了几次都不好看,算了,有机会再练练~~~  

FileWriter:

    下面来写一个练习来用一下:

  需求:我要把一句话:"为自己加油!!!  再默默坚持一下,黑马,我马上就来了! "写入一个test.txt中。

<span style="font-size:14px;">import java.io.FileWriter;import java.io.IOException;/** * 需求:我要把一句话:"为自己加油!!!  再默默坚持一下,黑马,我马上就来了! "写入一个test.txt中。 * 分析: * A:由于我们是写数据,所以使用OutputStream或者Writer。 * B:由于我们要写入到一个文本文件中,所以最终选择了Writer。 * 通过查看API,我们发现,Writer是一个抽象类。那么,怎么办呢? * 只能找子类使用。又由于我们是对文件操作,我们猜测了这个子类的名称是:FileWriter */public class FileWriterDemo {public static void main(String[] args) throws IOException {//创建字符输出流对象      FileWriter fw=new FileWriter("c.txt");/* * <span style="color:#cc0000;">创建字符输出流对象做了几件事情? A:调用系统功能创建了文件 B:创建字符输出流对象 C:把字符输出流对象指向创建的文件</span>*///调用写数据的功能// public void write(String str)fw.write("为自己加油!!!  再默默坚持一下,黑马,我马上就来了!");/* * <span style="color:#cc0000;">字符流 1字符 = 2字节 文件数据底层单位是字节,而我们现在是字符,所以它不能直接把数据写入文件。 把字符输出存储到缓冲区里面。</span> *///刷新缓冲区// public void flush()fw.flush();//释放资源// public void close()fw.close();/* * <span style="color:#cc0000;">为什么要close()呢?</span> * <span style="color:#cc0000;">1:让流对象变成垃圾。</span> * <span style="color:#cc0000;">2:通知系统去释放和文件相关的资源。</span> */  }}</span>

  

运行后结果为:

分析一下程序:上面用红色标记的字,都是在写的过程中,遇到的问题以及有疑问的地方,老师都讲到了,觉得写在出问题的代码旁,更容易理解。

下面是通过上面的程序总结的一些笔记:

字符输出流操作步骤:

    A:创建字符输出流对象 

    B:调用对象的写入数据方法,并刷新缓冲区

    C:释放资源

问题1:为什么FileWriter没有无参构造方法?
                因为写数据的时候,一定要明确写到哪里去。

问题2:flush()和close() 都有刷新功能,它们有什么区别呢?

              flush():只刷新缓冲区,流对象还可以继续使用。

              close() :先刷新缓冲区,再关闭流对象。流对象不可以继续被使用。

问题3:难道每次调用方法的时候,都需要刷新吗?或者说,不用刷,直接等到close() 来解决,行不行?                                                                   

       这两种方式都不可取。    

FileWriter的追加与换行:

  写入数据的方式,有5种:

         write(int ch)

         write(char[] chs,int index,int len)

         write(char[] chs) 

         write(String str,int index,int len)    

         write(String str)

在练习的时候遇到的问题:


为什么连续两次没有换行呢? 如果想换行,怎么办呢?

 因为你没让它换行,所以没有换行。那就给出换行符\n不就可以了吗 ?不行,不同的操作系统,对换行符的要求不一样:

 windows:\r\n     linux:\n   mac:\r

而有些软件在制作的时候,为了通用,对任何换行符都是可以识别的。


在不断的往下写的时候,本来想着往里面追加,结果新写入的每次都把以前的给覆盖了,如果我想追加写入怎么办?

   查API,构造的时候用带两个参数的就可以实现追加了:

      public FileWriter(String fileName,boolean append)

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


FileWriter写入数据加入异常处理(把上面的代码改进了一下):

import java.io.FileWriter;import java.io.IOException;/* * 加入异常处理的代码 */public class FileWriterDemo4 {public static void main(String[] args) {FileWriter fw = null;try {fw = new FileWriter("c.txt");fw.write("为自己加油!!!  再默默坚持一下,黑马,我马上就来了!");fw.flush();} catch (IOException e) {e.printStackTrace();} finally {if (fw != null) {try {fw.close();} catch (IOException e) {e.printStackTrace();}}}}}

  

FileReader:

字符输入流读取数据步骤:

              A:创建字符输入流对象

              B:调用读取数据功能,并显示

              C:释放资源


下面写一下刚看API学的时候的过程:

字符输入流读取数据方式一:一次读取一个字符

import java.io.FileReader;import java.io.IOException;/* * 字符输入流读取数据步骤: * A:创建字符输入流对象 * B:调用读取数据功能,并显示 * C:释放资源 *  * 一次读取一个字符。 */public class FileReaderDemo {public static void main(String[] args) throws IOException {// 创建字符输入流对象// FileReader fr = new FileReader("a.txt");FileReader fr = new FileReader("FileWriterDemo.java");// 调用读取数据功能,并显示// public int read()// int ch = fr.read();// // System.out.println(ch);// System.out.print((char) ch);//// ch = fr.read();// // System.out.println(ch);// System.out.print((char) ch);//// // read()方法读取数据返回int类型,并自动移动到下一个数据位置等待读取。// // 我们发现数据的读取和显示操作是重复的,所以我们决定用循环改进。// // 关键是:循环的结束条件是什么// ch = fr.read();// System.out.println(ch);//// ch = fr.read();// System.out.println(ch);// 通过测试,我们发现,如果数据没有了,读取的时候,将返回-1//int ch = fr.read();//while (ch != -1) {//System.out.print((char) ch);//// 重新读取一次//ch = fr.read();//}//开发写法int ch = 0;while((ch=fr.read())!=-1){System.out.print((char) ch);}// 释放资源fr.close();}}

运行后结果:




字符输入流读取数据方式一:一次读取一个字符串



开发中的代码运行结果:


复制文本文件:

import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;/** * 需求:我要把项目路径下的FileWriterDemo.java复制到f:\\Copy.java中 * 分析: *    数据源: *        读取数据: *   FileWriterDemo.java-- Reader -- FileReader *    目的地: *        写入数据: * f:\\Copy.java-- Writer -- FileWriter * 下面我用两种方式来做: */public class CopyFileDmeo {  public static void main(String[] args) throws IOException {//封装数据源  FileReader fr=new FileReader("E:/JavaSE-2015/StringDemo/src/cn/itcast02/ExceptionDemo.java");//封装目的地  FileWriter fw=new FileWriter("f:\\Copy.java");      //读取数据  //方式一:一次读取一个字符//  int ch=0;//  while((ch=fr.read())!=0){//  fw.write(ch);//  fw.flush();//  }  //方式二:一次读取多个字符  char[] chs=new char[1024];  int len=0;  while((len=fr.read(chs))!=-1){  fw.write(chs,0,len);  }    fw.close();  fr.close();  }}
运行结果:

                     


先到这儿吧,东西太多了,有些理解的不对的地方,真诚地希望大家帮我指正出来,谢谢!!!



0 0