------- http://www.itheima.comjava培训、android培训期待与您交流!-------
IO流是用来处理设备之间的数据传输。简单的说,就是对一些文件的操作,文本、图片或媒体文件等。而java对数据的操作时通过流的方式实现的,这些用于操作流的对象都在IO包中。流按流分为输入流和输出流,按照操作数据的方式分为字节流和字符流。
一般来讲,字节流主要是处理媒体数据的(如MP3、stormplayer等)。
抽象基类(父类):InputStream、OutputStream
字符流主要是对文本文件数据的操作。
抽象基类:Reader、Writer
一般父类名作为子类名的后缀,而前缀名则是该流对象的功能。数据的最常见的体现方式为文件。
一、字符流的相关操作:
1、
FileWriter:用于在硬盘上向文本文件中写入文字数据。
步骤:
(1)创建对象( 该对象一旦被初始化,就必须要明确被操作的文件,也就是要明确数据要存放的路径[/size])
(2)调用FileWriter的writer()方法将数据写入
(3)刷新流对象中的缓冲区中的数据( 写入一次,刷新一次)
(4)关闭流资源( 关闭之前会刷新一次内存)
区别:
flush():刷新后流可继续使用
close();刷新后流关闭
需要注意的是, 在文件创建的时候,系统调用的是底层资源,这时会发生异常。所以,要添加处理异常方式。try{}catch(){}finally{}( 必须要关闭资源)
部分代码如下:
//创建对象引用,并初始化为null(或者FileReader fr ;) FileReader fr = null ; try { //创建要写入和读取的文件 fw = new FileWriter("f:\\filecopy_2.txt"); fw.write("你好吗?"); } catch (IOException e) { System.out.println(e.toString); } finally { if (fw!=null) { try { fw.close();[/align] }catch (IOException e) { } } }
文件的续写:FileWriter(File file, boolean append)
将指示是否附加写入数据的 boolean 值设定为true,则在已有数据末尾处添加数据。
即:FileWriter fw = new FileWriter("1demo.txt",true);
fw.write("wangting");
FileReader:用于从文本文件中读取数据。
如:将c盘的一个文本文件复制到d盘( FileWriter和FileReader)
步骤:
(1)在d盘新建一个文本文件,用于存储接收的c盘文本文件数据
(2)创建一个关联文件用于复制
(3)定义一个字符数组,用于读写要复制的数据(异常处理)
(4)关闭资源 fw fr
//从c盘读取一个字符就往f盘写入一个字符 public static void copy_1() throws IOException { //创建复制的路径 FileWriter fw = new FileWriter("f:\\demo_copy.txt"); //创建一个文件关联(要复制的文件数据路径) FileReader fr = new FileReader("c:\\demo.txt"); int ch = fr.read(); while (ch!=-1) { fw.write(ch); } fw.close(); fr.close(); } //从c盘读取一个字符数组,就往f盘写入一个字符数组 public static void copy_2() { //创建对象引用,并初始化为null(或者FileReader fr ;) FileReader fr = null ; FileWriter fw = null; try { //创建要写入和读取的文件 fw = new FileWriter("f:\\filecopy_2.txt"); fr = new FileReader("c:\\demo.txt"); //定义一个字符数组,用于读写数据 char[] buf = new char[1024]; int len = 0; while ((len = fr.read(buf))!=-1) //若读入的字符数不为-1 { fw.write(buf,0,len); //将缓冲区中的数据写入f盘下的filecopy_2.txt } } catch (IOException e) { throw new RuntimeException("读取失败"); } finally { if (fw!=null) { try { fw.close(); }catch (IOException e) { } } if (fr!=null) { try { fr.close(); } catch (IOException e) { } } }
2、字符流缓存区,用于提高对数据的读写效率。
BufferedWriter:
步骤:
(1)创建写入流对象( 字符流缓冲区只有结合流才能使用)
FileWriter fw = new FileWriter("demo.txt");
(2)创建字符流缓冲对象,将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
BufferedWriter bufw = new BufferedWriter(fw);
(3)刷新缓冲区( 只要用到缓冲区就要刷新)
bufw.flush();
(4)关闭缓冲区(也就是关闭流资源)
bufw.close();
bufw.newLine():跨平台换行符
BufferedReader:
步骤:
(1)创建读取流对象并关联文件
FileReader fr = new FileReader("demo.txt");
(2)创建缓冲区对象,将流对象作为参数传递给缓冲区的构造函数
BufferedReader bufr = new BufferedWriter(fw);
(3)读取数据(课一行行的读,且返回类型为String)
String s= null;
while ((s=bufr.readLine())!=-1){System.out.println(s);}
(4)关闭缓冲区资源
bufr.close();
3、装饰设计模式
使原有功能增强(在字符流缓冲区的读取方式上,一行行的读取比一次读取一个字符更加高效,但是一行行的读取是基于read方法的,readLine方法就是对read方法的增强)。
当想要对已有的对象进行功能增强时,可以定义类将已有对象作为参数传递给自定义的构造函数,基于已有功能并提供加强功能,那么自定义类就成为装饰类。
字符流缓冲区中的readLine()方法就是对read()方法功能的增强。
/* 模拟readLine()方法 基于read方法,自定义与readLine方法一致的方法 */ import java.io.*; //将该功能封装到一个类中 class MyBufferedReader extends Reader { //使用的是FileReader类中的基本方法 //定义一成员变量,作用于整个类 private Reader r; //该对象一初始化就可以接收一个流对象 MyBufferedReader(Reader r) { this.r = r; } //对外提供一个自定义方法,用于读取数据(一行一行的读) public String myReadLine() throws IOException { //定义一个临时容器,原BufferedReader封装的是字符数组 //定义一个StringBuilder容器,因为最终还是将数据转换成字符串 StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch=r.read())!=-1) { if (ch=='\r') continue; if (ch=='\n') return sb.toString(); else sb.append((char)ch); } //由打印结果来看,最后数据的后面有一个换行符,如果将换行符去掉, //则最后一行数据就会丢失,所以判断一下 if (sb.length()!=0) return sb.toString(); return null; } /* 自定义装饰类只要继承reader,并复写reader中的抽象方法即可 */ public void close() throws IOException { r.close(); } public int read(char[] cbuf, int off, int len) { return read(cbuf, off,len); } //自定义关闭流资源动作 public void myClose() throws IOException { //其实,缓冲区的底层就是调用了流的关闭动作 r.close(); } public static void main(String[] args) throws IOException { /*这里要写明文件的具体位置,若不指定盘符,则默认在当前目录下F:\java\day19寻找, 若找不到,报异常 F:\java\day19>java MyBufferedReader Exception in thread "main" java.io.FileNotFoundException: 123.txt (系统找不到指 定的文件。) */ FileReader fr = new FileReader("f:\\123.txt"); MyBufferedReader myBufR = new MyBufferedReader(fr); String line = null; while ((line=myBufR.myReadLine())!=null) { System.out.println(line); } myBufR.myClose(); } }
装饰类和继承的区别:
装饰类将原有继承体系优化,装饰类的设计使其变得更加灵活,避免的继承体系的臃肿,降低了类与类之间的关系。
装饰类和被装饰类通常都属于一个体系中。
4、LineNumberReader设置、获取行号
import java.io.*; class LineNumberReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("BufferedDemo.java"); LineNumberReader lnr = new LineNumberReader(fr); String line = null; //行号从201开始 lnr.setLineNumber(200); while ((line=lnr.readLine())!=null) { System.out.println(lnr.getLineNumber()+"::"+line); } } }
二、字节流的相关操作
字节流主要用于存储字节数据。
InputStream:读取流
OutputStream:写入流
1、字节流的读写操作
//一次写入一个字节 public static void writeFile() throws IOException { //默认情况下在当前目录下 f:\\java\\day19 FileOutputStream fos = new FileOutputStream("1.txt"); //将字符串转成字节 fos.write("wangtingting".getBytes()); //关闭资源 不必刷新 fos.close(); //为什么在1.txt中写入数据后再编译时,写入的数据消失? } //一次读取一个字节 public static void readFile_1() throws IOException { FileInputStream fis = new FileInputStream("1.txt"); int ch = 0; while ((ch=fis.read())!=-1) { System.out.println((char)ch); } fis.close(); } //一次读取一个字节数组 public static void readFile_2() throws IOException { FileInputStream fis = new FileInputStream("1.txt"); byte[] buf = new byte[1024]; int len = 0; while ((len=fis.read(buf))!=-1) { System.out.println(new String(buf, 0, len)); } fis.close(); } public static void readFile_3() throws IOException { FileInputStream fis = new FileInputStream("1.txt"); //int num = fis.available(); byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区 不用 再循环了 fis.read(buf); System.out.println(new String(buf)); //System.out.println("num = "+num);//若在文本中自定义输入一个字节q,则 num = 15 说明换行符占两个字节 fis.close(); }
2、拷贝MP3文件:通过字节流缓冲区复制MP3文件,提高读写效率。
public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); copyMp3(); long end = System.currentTimeMillis(); System.out.println(end - start); } public static void copyMp3() throws IOException { //要复制的路径 BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("你那么爱他.mp3")); //被复制的MP3 BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("李圣杰林隆璇 - 你那么爱她.mp3")); byte[] buf = new byte[1024]; int len = 0; while ((len=bufis.read(buf))!=-1) { bufos.write(buf,0,len); } bufos.close(); bufis.close(); }
当然,我们这里要进行异常处理,所以简单的将异常抛出了。
3、拷贝图片文件
下面我们写一个规范的复制文件代码:
public static void main(String[] args) { //初始化为空 FileInputStream fis = null; FileOutputStream fos = null; try { //创建文件读取字节流对象并明确要复制的图片路径 fis = new FileInputStream("2.jpg"); //创建文件写入字节流对象,用于图片复制的地方 fos = new FileOutputStream("copy.jpg"); //定义一个字节数组 byte[] buf = new byte[1024]; int len = 0; while ((len= fis.read(buf))!= -1) { fos.write(buf,0,len); } } catch (IOException e) { throw new RuntimeException("读写失败");//抛出新建异常对象 } finally { try { if (fis!=null) fis.close(); } catch (IOException e) { throw new RuntimeException("读取失败"); } try { if (fos!=null) fos.close(); } catch (IOException e) { throw new RuntimeException("写入失败"); } } }
4、读取键盘录入
System.out:对应的是标准输出设备--->控制台
System.in:对应的是标准输入设备--->屏幕
键盘录入要有结束标记,否则程序不能结束,只有强制结束:ctrl+c
/* 键盘录入的方式获取数据 System.out:对应的是标准的输出设备 控制台 System.in:输入设备 键盘 */ import java.io.*; class ReadIn { public static void main(String[] args) throws IOException { InputStream in = System.in; //键盘录入一个字符,就将该数据存储起来,因为长度不确定故用StringBuilder StringBuilder sb = new StringBuilder(); while (true) { int ch = in.read(); //如果读到\r,程序继续 if (ch=='\r') continue; if (ch=='\n') { //如果读到\n,将数据转换成字符串,再转换为大写输出 String s = sb.toString(); //读到over,程序停止 if ("over".equals(s)) break; System.out.println(s.toUpperCase()); //每次录入都要讲缓冲区清空 sb.delete(0,sb.length()); } //忘记写else ,录入后空一行再转换为大写,且程序不能停止 else sb.append((char)ch); } /* int ch = 0; while ((ch=in.read())!=-1) { System.out.println(ch); } 也可不管资源,录入结束程序结束 in.close(); */ /*只能键入一次 回车符也是字节\r 13 \n 10 int by = in.read(); int by1 = in.read(); int by2 = in.read(); System.out.println(by); System.out.println(by1); System.out.println(by2); System.out.println('\r'+0); System.out.println('\n'+0); */ } }
5、读取/写入转换流
通过刚才的键盘录入一行并打印其大写,发现其实就是读一行的原理,
也就是readLine方法
能不能直接使用readLine方法来完成键盘录入?
readLine是字符流BufferedReader类中的方法,
而键盘录入的read方法时字节流InputStream的方法
字节流-->字符流????
import java.io.*; class TransStreamDemo { public static void main(String[] args) throws IOException { //获取键盘录入对象 InputStream in = System.in; //将字节流对象转成字符流对象,将字节流作为参数传递给转换流的构造函数 InputStreamReader isr = new InputStreamReader(in); //字节流->字符流,就可以用字符流的操作规律操作,缓冲区技术 //将要被提高效率的流对象传递给BufferedReader的构造函数 BufferedReader bufr = new BufferedReader(isr); [b]//键盘录入最常见写法 //BufferedReader bufr = // new BufferedReader(new InputStreamReader(System.in));[/b] //写入转换流 OutputStream out = System.out; OutputStreamWriter osw = new OutputStreamWriter(out); BufferedWriter bufw = new BufferedWriter(osw); [b]//BufferedWriter bufw = // new BufferedWriter(new OutputStreamWriter(System.out));[/b] String line = null; while ((line=bufr.readLine())!=null) { if ("over".equals(line)) break; bufw.write(line.toUpperCase()); //newLine方法是BufferedWriter的方法,所以要将写入转换流装饰一下 bufw.newLine(); //若不刷新,没有数据 bufw.flush(); } bufr.close(); /* //转换完成,可以字符流的特点读取 String line = null; while ((line=bufr.readLine())!=null) { //如果读到结束标记,则程序停止 if ("over".equals(line)) break; //如果不判断结束标记程序不会停下来,只有强行停止 ctrl+c System.out.println(line.toUpperCase()); } bufr.close(); */ } }
6、流操作规律
对于流的操作只要明确源和目的就行。比如:
键盘录入:
源:键盘录入 目的:控制台
将键盘录入的数据写到一个文件中:源:控制台 目的:文件
将一文件种的数据打印到控制台 源:文件 目的:控制台
流操作规律:
(1)明确源和目的
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
(2)操作的数据是否是纯文本
是:字符流
不是:字节流
(3)当体系明确后,再明确要使用哪个具体对象
可以通过设备区分:
源设备:内存(ArrayStream)、硬盘(FileStream)、键盘(System.in)
目的设备:内存(ArrayStream)、硬盘(FileStream)、控制台(System.out)
7、
可以通过set方法改变输入或输出设备。
因为该类System中的方法都是静态的,所以直接调用即可。
8、异常日志信息/系统信息
异常日志信息:
我们在编写程序时,为了测试功能是否健全,会直接将信息打印在控制台上,但是在实际开发中,不可能说当用户使用产品的时候出现的问题直接打印给用户看,所以,这时就需要将这些出现的问题存储到一个文件中,方便程序员及时查看做出适当的解决方案。
import java.io.*; import java.util.*; import java.text.*; class ExceptionInfo { public static void main(String[] args){ try{ int[] arr = new int[2]; System.out.println(arr[3]); }catch (IOException e){ try{ Date d = new Date(); SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String s = sfd.format(d); PrintStream pf = new PrintStream("exception.log"); pf.println(s); System.set(ps); } catch (IOException ex){ throw new RuntimeException("日志文件创建失败。"); } e.printStackTrace(System.out); } } }
系统信息:
System类中的获取当前系统属性方法:getProperties()
Properties类中的方法list(PrintStream out) : 将属性列表输出到指定的输出流。
import java.util.*; import java.io.*; class SystemInfo { public static void main(String[] args) { PrintStream ps = null; try { //获取系统信息: Properties pop = System.getProperties(); //创建输出流对象,将输出流中数据存入指定文件中 ps = new PrintStream("systeminfo.txt"); //将属性列表输出到指定的输出流 pop.list(ps); } catch (Exception e) { throw new RuntimeException("获取系统信息失败。"); } } }
三、File
1、File类:文件和目录路径的抽象表现形式
特点:
1)用来将文件或文件夹封装成对象
2)方便于对文件与文件夹的属性信息进行操作
3)File对象可以作为多数传递给流的构造函数
2、File常见操作
创建File对象:
public static void sop(Object obj) { System.out.println(obj); }
//构造方法 字段 public static void constructionMethod() { //将file.txt作为参数传递给File对象 File f1 = new File("filedemo.txt");//相对路径 File f2 = new File("f:\\java\\day20","demo.txt"); //绝对路径 //File ff = new File("f:\\java\\day20\\demo.txt"); f2和ff指的的同一个文件 //可以将demo.txt写成变量 File f2 = new File("f:\\java\\day20",str); File fi = new File("f:\\java\\day20"); File f3 = new File(fi,"demo3.txt"); //封装的是什么打印的就是什么路径 sop("f1:"+f1); sop("f2:"+f2); sop("f3:"+f3); //跨平台分隔符 可以用“/” File f4 = new File("f:"+File.separator+"java"+File.separator+"day19/demo.txt"); sop("f4:"+f4); }
File的常见构造方法:
//创建 public static void method_1() throws IOException { //在当前目录下创建一个新文件,若文件已存在,则不允许再创建 File f = new File("file.txt"); sop("createNewFile:"+f.createNewFile()); //删除失败 返回false sop("delete:"+f.delete()); //sop("deleteOnExit::"+f.deleteOnExit());在退出时删除 一般用于临时文件删除 }
//判断 public static void method_2() throws IOException { File f = new File("java.txt"); f.createNewFile(); sop("exists---"+f.exists()); sop("是否双击可执行----"+f.canExecute()); sop("是否可读------"+f.canRead()); sop("是否可写------"+f.canWrite()); sop("是否是绝对路径----"+f.isAbsolute()); sop("是否是一个目录----"+f.isDirectory()); //在判断文件对象是否是文件或目录时,必须先判断该文件是否存在,用exists(); sop("是否是文件----"+f.isFile()); sop("是否是隐藏的----"+f.isHidden()); sop("----------------------------------"); File f1 = new File("1.txt"); //创建一级目录 sop(f1.mkdir()); File f2 = new File("f:\\java2\\java\\1.txt"); //创建多级目录 sop(f2.mkdirs()); }
//获取信息 public static void method_3() throws IOException { File f1 = new File("f:\\java\\day20\\inquire.txt"); File f2 = new File("inquire.txt"); sop(f2.getPath()+"---"+f1.getPath()); sop(f1.getAbsolutePath());//返回绝对路径 f:/java/day20/inquire.txt sop(f2.getParent());//若没有指定父目录则返回null 若运行f1 则返回 f:/java/day20 File f3 = new File("f:\\java\\day20"); sop(f3.lastModified());//返回最后一次修改的时间 sop(f3.length());//返回文件的长度 //sop(f.createNewFile()); }
//方法摘要 public static void method_4()throws IOException { File f =new File("f:\\java\\day20"); //列出该目录下的所有文件 File[] file= f.listFiles(); for (File name : file ) { System.out.println(name); } }
3、文件列表
相关的操作方式:
(1)static File[] listRoots():列出机器中的有效盘符(列出可用的文件系统根)
static (不需要创建对象): 不操作文件的特有数据,操作共享数据
且返回类型为 File[] 文件数组
作用(什么时候使用):当想要把程序安装到某个盘符中时。
(2)String[] list():用于列出当前目录下的所有文件(包括隐藏的文件)
file对象必须是封装了一个目录,该目录还必须是存在的
比如:File f = new File("f:\\java\\avc.txt"); 则空指针异常
(3)String[] list(FilenameFilter filter) : 文件名过滤
FilenameFilter:是一个接口。。
实现此接口的类实例可用于过滤器文件名接口中的方法只有一个:
boolean accept(File dir, String name) 测试指定文件是否应该包含在某一文件列表中。
File dir:表示文件的目录
String name:表示目录下的文件名称
(4) File[] listFiles():返回的是File对象,那么就可以调用getName等方法
而String[] list();返回的是文件目录名称
import java.io.*; class FileDemo2 { public static void main(String[] args) { listFilesDemo(); } public static void listFilesDemo() { //创建一个目录对象,用于遍历该目录下的文件 File dir = new File("f:\\java"); //列出该目录下的文件,并返回File[]类型 File[] files = dir.listFiles(); //由于该方法返回的是数组对象,所以,数据类型是File对象 for (File f : files ) { System.out.println(f.getName()+"---"+f.length()); } } public static void filterDemo() { File dir = new File("f:\\java"); //实现FilenameFilter接口,并覆盖其中的accept方法 String[] arr = dir.list(new FilenameFilter() { public boolean accept(File dir,String name) { return name.endsWith(".java"); /* //dir打印的是 f:/java 目录,name 打印的是该目录下的文件名 System.out.println(dir+"----"+name); if (name.endsWith(".java")) { return true; } else return false; */ } }); for (String names : arr ) { System.out.println(names); } } public static void listDemo() { //打印出f:/java/下的所有文件和目录 File f = new File("f:\\java\\"); String[] names = f.list(); for (String name : names) { System.out.println(name);//写names是不对的 } } public static void listRootsDemo() { File[] files = File.listRoots(); //遍历 //高级for循环 格式:for(数据类型 变量名 : 要操作(遍历)的集合或数组){ 打印变量 } //name 也可以是f for (File f : files) { System.out.println(f); } } }
4、列出目录下的所有内容(递归)
递归:调用自身方法。
如该实例,需要列出目录下的所有内容,也就是说文件夹1下有文件夹2,文件夹2下有文件,要遍历多级目录。在遍历多级目录的时候,使用的方法就是遍历一级目录的方法。
递归注意事项:
(1)要限定条件,是作为结束循环用的,否则是死循环。
(2)限定递归次数(如果递归的次数过多,栈内存中的某些方法还没有执行完就继续向下执行,会导致内存不够,即内存溢出)。
/* 列出目录下的所有内容(递归) */ import java.io.*; class FileDemo3 { public static void main(String[] args) { //创建一个目录,用于遍历其中的文件夹 //必须在主函数中创建 File dir = new File("f:\\java\\day20"); showDir(dir); } //定义一个功能,用于遍历文件夹(文件夹下包含文件,也就是遍历多级目录) public static void showDir(File dir) //接收一个目录,用于列出该目录下的文件 { //打印一下目录 System.out.println(dir); //调用listFiles()方法,用于列出该目录下的文件(files),其返回类型为 File[] 数组对象 File[] files = dir.listFiles(); for (int x =0; x
5、创建java文件列表
将一个指定目录下的java文件的绝对路径存储到一个文本文件中,建立一个文件列表。
如:f:\\java\\day20\\xxx.java ----> \\xxx.txt文件
步骤:
(1)对指定的目录进行递归
(2)获取递归过程中所有java文件的绝对路径
(3)将遍历的绝对路径存储到一个集合中
(4)将集合中的数据写入到一个txt文本文件中
import java.io.*; import java.util.*; class JavaFileList { public static void main(String[] args) throws IOException { File dir = new File("f:\\java\\day20"); Listlist = new ArrayList (); fileToList(dir,list); File file = new File(dir,"javalist.txt"); listToFile(list,file.toString()); //System.out.println(list.size()); } //定义一个功能(方法)用于遍历指定目录,将获取的绝对路径存到集合中 public static void fileToList(File dir,List list) { //调用listFiles()方法,用于列出目录下的文件 File[] files = dir.listFiles(); //f表示每遍历一次打印的路径(是变化的) files 表示列出的所有目录 for (File f : files ) { //如果该文件时目录,则遍历该目录 if (f.isDirectory()) { fileToList(dir,list); }else { //如果该文件不是目录,且后缀名为java,将该路径存储到集合中 if (f.getName().endsWith(".java")) { list.add(f); } } } } //定义一个方法,用于将获取的集合存储到一个文本文件中 //将数据复制到文本文件中,FileWriter ,要提高效率,则用字符流的缓冲区 BufferedWriter public static void listToFile(List list,String javaListFile) throws IOException { BufferedWriter bufw = null; try { bufw = new BufferedWriter(new FileWriter(javaListFile)); for (File f : list ) { String path = f.getAbsolutePath(); bufw.write(path); bufw.newLine(); bufw.flush(); } } catch (IOException e) { throw e; } finally { try { if (bufw != null) bufw.close(); } catch (IOException e) { throw e; } } } }
------- http://www.itheima.comjava培训、android培训期待与您交流!-------