黑马程序员-java基础(七)-IO流
来源:互联网 发布:印度 巴基斯坦 知乎 编辑:程序博客网 时间:2024/05/20 14:18
------- android培训、java培训、期待与您交流! ----------
IO流
1 IO流
IO流(Input Output)用来处理设备之间的数据传输。Java对数据的操作是通过流的方式。按操作数据分:字节流、字符流;字节流抽象基类:InputStream,OutStream;字符流抽象基类:Reader,Writer
按流向分:输入流,输出流
输入输出都是相对于内存而言:
输入:将外设中的数据读取到内存中
输出:将内存的数写入到外设中
p.s.
字符流其实其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。再对这个文字进行操作。简单说:字节流+编码表。
2 字符流
1、创建文件写入字符FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
import java.io.*;class Test{public static void main(String[] args) throws IOException{FileWriter fw=new FileWriter("Demo.txt"); //创建一个FileWriter对象,该对象一初始化被徐有明确被操作文件,有同名文件会直接覆盖fw.write("ok,success");//调用write方法,将字符串写进流,待刷新后写入目的地fw.close();//刷新流对象的缓存中的数据到目的地中,也可以用flush刷新,但是close刷新后会关闭流}}
2、文件续写
/*已有文件续写*/import java.io.*;class Test{public static void main(String[] args) throws IOException{FileWriter fw=new FileWriter("Demo.txt",true); fw.write("\r\nWrite again");fw.close();}}
3.IO异常处理:
/*IO异常处理方式*/import java.io.*;class FileWriterDemo2{public static void main(String[] args) throws IOException{FileWriter fw=null ; try{fw=new FileWriter("FileWriter2.txt");fw.write("ok,success");}catch (IOException e){System.out.println("catch:"+e.toString());}finally{try{if(fw!=null)fw.close();}catch (IOException e){System.out.println(e.toString());}}}}
4、字符流文件读取
第一种方式:读单个字符reader()
import java.io.*;class Test{public static void main(String[] args) throws IOException{FileReader fr=new FileReader("Demo.txt");//创建一个文件读取流对象,且保证文件存在while (true){int ch=fr.read(); //一次读一个字符,且会自动往下读,读到末尾则返回-1if (ch==-1)break;System.out.println("ch="+(char)ch);//强转为char型}fr.close();}}运行结果:
第二种方式:通过字符数组进行reader(char[] cbuf)
import java.io.*;class Test{ public static void main(String[] args) throws IOException { FileReader fr=new FileReader("Demo.txt"); char[] buf=new char[1024]; int len=0; while((num=fr.read(buf))!=-1)//read([])返回字符个数 { System.out.println(new String (buf,0,len)); } fr.close(); }}5、字符流缓冲区(BufferReader、BufferWriter)
在流的基础上对流的功能进行增强,提高对数据的读写效率
P.S.
缓冲区要结合字符流才可以使用
/*BufferedReader、BufferedWriter*/import java.io.*;class Test{public static void main(String[] args) throws IOException{FileWriter fw=new FileWriter("Demo.txt"); //建立字符写入流对象BufferedWriter bw=new BufferedWriter(fw);//建立字符写入流流对应的缓冲区对象for(int i=0;i<4;i++){bw.write("This is BufferedWriter"+i);//用字符缓冲区一次写入一个字符串bw.newLine();//写入一个行分割符}bw.close();FileReader fr=new FileReader("Demo.txt"); //建立字符读取流对象BufferedReader br=new BufferedReader(fr);//建立字符读取流对应的缓冲区对象String line;while((line=br.readLine())!=null){//一次读取一行System.out.println(line);}br.close();}}
P.S.
readLine()方法原理:
【自定义读一行】
/*自定义读一行 MyReaderDemo*/import java.io.*;class MyReader {private FileReader f;MyReader(FileReader f)//输入流对象{this.f=f;} public String MyReaderLine() throws IOException//读一行方法{StringBuilder sb=new StringBuilder();//定义一个临时容器StringBuilderint ch=0;while((ch=f.read())!=-1){ if(ch=='\r')continue;if(ch=='\n')//判断是否到行结尾return sb.toString();//将字符串输出 sb.append((char)ch);//读一个字符存入容器中} if(sb.length()!=0)//防止最后一行没有换行符,造成数据丢失 return sb.toString(); return null;}public void MyClose() throws IOException{f.close();}}class MyReaderDemo {public static void main(String[] args) throws IOException{FileReader fr=new FileReader("demo.txt"); MyReader mr=new MyReader(fr);String line=null;while((line=mr.MyReaderLine())!=null){System.out.println(line);//打印一行}mr.MyClose();}}6、装饰设计模式
在原有类进行功能改变,增强已有对象的功能(如上:自定义的可以读一行类)
/*装饰类和继承的区别*/class Person{ void chifan(){ System.out.println( "吃饭"); }}//采用装饰的方式增强Person类//这个类的出现是为了增强Person而出现的class NewPerson{ private Person p; NewPerson(Person p){ this.p = p; } public void chifan(){ p.chifan(); System.out.println( "开胃酒"); System.out.println( "甜点"); }}//采用继承的方式增强Person类class NewPerson2 extends Person{ public void chifan(){ super.chifan(); System.out.println( "开胃酒"); System.out.println( "甜点"); }}public class Test{ public static void main(String[] args){ Person p = new Person(); NewPerson np1 = new NewPerson(p); np1.chifan(); System.out.println( "---------------"); NewPerson2 np2 = new NewPerson2(); np2.chifan(); }}运行结果:
P.S.
装饰体系较继承体系灵活,避免了装饰体系的臃肿,降低了类与类之间的关系
3 字节流
1、基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。/*字节流输入、输出基本操作*/public class Test{ public static void main(String[] args)throws IOException { writeStream(); readStream1(); System.out.println(); System.out.println("--------"); readStream2(); System.out.println(); System.out.println("--------"); readStream3(); } public static void writeStream()throws IOException { FileOutputStream fos=new FileOutputStream("Demo.txt"); //getBytes()使用平台的默认字符集将此 String 编码为 byte 序列 fos.write("hallo java".getBytes());//字节为最小操作单位不用flush刷新,但要关流 fos.close(); } //读取方式一:一次读取一个字节 //比较慢 public static void readStream1()throws IOException { FileInputStream fis=new FileInputStream("Demo.txt"); int ch; while((ch=fis.read())!=-1){//从输入流中读取一个字节 System.out.print((char)ch); } } //读取方式二:定义一个1024的字节,一次读1024个字节 //较合理,建议使用 public static void readStream2()throws IOException { FileInputStream fis=new FileInputStream("Demo.txt"); byte[] buf=new byte[1024]; int len=0; while((len=fis.read(buf))!=-1){//从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中 System.out.print(new String(buf,0,len)); } } //通过available(),获取字节长度,定义一个刚好的字节数组存放 //如果字节长度过长,容易造成溢出 public static void readStream3()throws IOException { FileInputStream fis=new FileInputStream("Demo.txt"); byte[] buf=new byte[fis.available()]; fis.read(buf); System.out.print(new String(buf,0,buf.length)); }}运行结果:
/*复制一个图片*/import java.io.*;public class Test{ public static void main(String[] args)throws IOException { FileInputStream fis=new FileInputStream("123.jpg");//创建输入字节流,关联文件 FileOutputStream fos=new FileOutputStream("123_copy.jpg");//创建输出字节流,关联文件 byte[] buf=new byte[1024]; int len=0; while((len=fis.read(buf))!=-1){ fos.write(buf);//每次存储2kb数据 }}}
2、字节流缓冲区:
BufferedOutputStream、BufferedInputStream(和字符流缓冲区使用方法一致)
/* * 需求:拷贝一个mp3文件,并比较几种方式的效率 * */import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class Test1{ public static void main(String[] args) throws IOException { long s1=System.currentTimeMillis(); copy_1();//一次读取1kb到缓冲数组中,然后输出 long s2=System.currentTimeMillis(); copy_2();//一次读取一个字节,加入缓冲计数BufferInputStream long s3=System.currentTimeMillis(); copy_3();//一次读取一个节,不使用缓冲区 long s4=System.currentTimeMillis(); System.out.println("1:"+(s2-s1)+"ms...2:"+(s3-s2)+"ms...2:"+(s4-s3)+"ms"); } public static void copy_1() throws IOException { FileInputStream fis = new FileInputStream("1.mp3" ); FileOutputStream fos = new FileOutputStream("1_copy.mp3" ); byte[] buf = new byte[1024]; int len = 0; while((len = fis.read(buf)) != -1){ fos.write(buf,0,len); } fis.close(); fos.close(); } public static void copy_2() throws IOException { FileInputStream fis = new FileInputStream("2.mp3" ); BufferedInputStream bufis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream("2_copy.mp3" ); BufferedOutputStream bufos = new BufferedOutputStream(fos); int ch = 0; //一次读取一个 while((ch = bufis.read()) != -1){ bufos.write(ch); } bufis.close(); bufos.close(); } public static void copy_3() throws IOException { FileInputStream fis = new FileInputStream("2.mp3" ); FileOutputStream fos = new FileOutputStream("3_copy.mp3" ); int ch = 0; //一次读取一个 while((ch = fis.read()) != -1){ fos.write(ch); } fis.close(); fos.close(); }}运行结果
从以上结果,可以很明显看出拷贝效率:加入缓冲的字节数组>使用字节流缓冲区>字节流一次读取一个字节
3、读取键盘输入
System.in:标准输入设备:键盘
System.out:标准输出设备:控制台
/*获取用户键盘录入的数据并将数据变成大写显示在控制台上,如果用户输入的是over,结束键盘录入。1、键盘录入只读取一个字节,要判断是否为over,需要将读取的字节拼成字符串2、定义StringBuilder来存储3.在用户回车前,转换成字符串并判断*/import java.io.*;public class Test{ public static void main(String[] args)throws IOException { InputStream is=System.in;//System.in:返回标准输入流 StringBuilder sb=new StringBuilder(); int ch=0; while(true){ ch=is.read(); if(ch=='\r') continue; if(ch=='\n'){ String s=sb.toString(); System.out.println(s.toUpperCase());//转换为大写输出 if("over".equals(s))//判断是否输入的是over break; sb.delete(0, sb.length());//存入一行后要初始化一下 } else sb.append((char)(ch)); }}}
4、转换流
字符流和字节流之间的桥梁,方便字节流和字符流之间的转换
转换流:
InputStreamReader:字节到字符的桥梁,解码。
OutputStreamWriter:字符到字节的桥梁,编码。
转换流的应用:
字节流中的数据都是字符时,转成字符流操作更高效。
/*获取用户键盘录入的数据并将数据变成大写显示在控制台上,如果用户输入的是over,结束键盘录入。1、键盘录入是字节流,将字节流转换成字符流2、定义字符流的缓冲区,用readLine方法高效读取3、判断是否为over*/import java.io.*;public class Test{ public static void main(String[] args)throws IOException { InputStream is=System.in;//System.in:返回标准输入流 InputStreamReader isr=new InputStreamReader(is);//将字节输入流转换成字符输入流 BufferedReader br=new BufferedReader(isr);//建立字符输入流的缓冲区 while(true){ String line=br.readLine(); if("over".equals(line)) break; System.out.println(line.toUpperCase()); }}}P.S.
使用字节流读取一个中文字符需要读取两次,因为一个中文字符由两个字节组成,而使用字符流只需读取一次。
import java.io.*;public class Test{ public static void main(String[] args)throws IOException { //将键盘输入字节流转换成字符流,并创建字符读取缓冲区 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); String line; while((line=br.readLine())!=null){ if("over".equals(line)) break; bw.write(line.toUpperCase()); bw.newLine(); bw.flush(); }}}
5、改变标准输入输出设备
System类static void
setIn(InputStream in)
重新分配“标准”输入流。static void
setOut(PrintStream out)
重新分配“标准”输出流。
/*改变标准输入、输出设备*/import java.io.*;public class Test{ public static void main(String[] args)throws IOException { System.setIn(new FileInputStream("Demo.txt"));//改变标准的输入设备 System.setOut(new PrintStream("Demo_copy.txt"));//改变标准输出设备 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); String line; while((line=br.readLine())!=null){ if("over".equals(line)) break; bw.write(line.toUpperCase()); bw.newLine(); bw.flush(); }}}
P.S.
字符流继承体系简图
字节流继承体系简图
4 File类
File类用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。File对象可以作为参数传递给流的构造函数。
import java.io.*;import java.io.File;public class Test{ public static void main(String[] args){ constructorDemo(); } public static void constructorDemo(){ //可以将一个已存在的,或者不存在的文件或者目录封装成file对象 //方式一 File f1 = new File("d:\\demo\\a.txt" ); //方式二 File f2 = new File("d:\\demo" ,"a.txt" ); //方式三 File f = new File("d:\\demo" ); File f3 = new File(f,"a.txt" ); //考虑到Windows和Linux系统通用 File f4 = new File("d:" + File.separator + "demo" + File.separator + "a.txt" ); }}
【例】过滤指定目录中的文件
P.S
流只能操作数据不能操作文件
File.separator是与系统有关的默认名称分隔符。在 UNIX 系统上,此字段的值为 '/';在 Microsoft Windows 系统上,它为 '\\'。
/* 需求:获取指定目录下后缀名为java的文件。思路:用list(FilenameFilter filter)对文件进行过滤*/import java.io.*;public class Test{ public static void main(String[] args){ File dir=new File("f:\\WJava\\Day18");//指定目录 String[] list=dir.list(new FilenameFilter(){//定义内部类获取FilenameFilter对象 public boolean accept(File dir, String name){//dir:目录 name:文件名称,返回真则取出 return name.endsWith(".java");//过滤.java文件 } }); for(String name:list){ System.out.println(name);} }}
递归:
函数自身直接或者间接的调用到了自身。
一个功能在被重复使用,并每次使用时,参与运算的结果和上一次调用有关。这时可以用递归来解决问题。
P.S.
1、递归一定明确条件,否则容易栈溢出。
2、注意一下递归的次数。
/* 列出目录下所有内容*/import java.io.*;public class Test{ public static void main(String[] args) { File dir=new File("f:\\WJava\\exam"); showFile(dir); } public static void showFile(File f)//定义一个打印目录下所文件的方法 { File[] files=f.listFiles(); for(int i=0;i<files.length;i++){ System.out.println(files[i]); if(files[i].isDirectory()) showFile(files[i]);//如果是一个目录,递归调用该方法 } }}【例】
/* 需求:利用递归求1到10的和。*/import java.io.*;public class Test{ public static void main(String[] args) { System.out.println(getSum(10)); } public static int getSum(int num) { int sum=0; if(num>=1) sum=num+getSum(num-1); return sum; }}运行结果:
【例】 需求:对指定目录进行删除
/* 需求:删除一个带内容的目录 思考: 1、目录里面有内容是无法删除,原理上必须从内往外删 2、定义一个删除指定目录中文件的方法(当存在目录时递归此方法)*/import java.io.*;public class Test{ public static void main(String[] args) { File dir=new File("f:\\exam"); removeDir(dir); } public static void removeDir(File f) { File[] files=f.listFiles(); for(int i=0;i<files.length;i++){ if(files[i].isDirectory()) removeDir(files[i]); else System.out.println(files[i].toString()+"::"+files[i].delete());//将文件删除 } System.out.println(f.toString()+"::"+f.delete());//将文件夹删除 }}运行结果:
5 Properties类
一、概述
Properties是Hashtable的子类,它具备Map集合的特点。而且它里面还有存储的键值对,都是字符串,无泛型定义。是集合中和IO技术想结合的集合容器。
特点:
1)可用于键值对形式的配置文件
2)在加载时,需要数据有固定的格式,常用的是:键=值
二、特有方法
1、设置
Object setProperty(String key,String value);//设置键和值,调用Hashtable的方法put
2、获取
String getProperty(String key);//指定key搜索value
Set<String> stringPropertyName();//返回属性列表的键集,存入Set集合
3、加载流和存入流
void load(InputStream ism);//从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Readerreader);//从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
voidlist(PrintStream out);//将属性列表输出到指定的输出流
void store(OutputStreamout,String comments);//对应load(InputStream )将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments);//对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
package cn.swu1;/*练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。分析:很容易想到的是:计数器。可是该计数器定义在程序中,随着该应用程序的退出,该计数器也在内存中消失了。所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式。键值对数据是map集合。数据是以文件形式存储。使用io技术。那么map+io——>Properties。思路:1、用读取流关联文本信息文件。如果存在则读取,如果不存在,则创建 2、每次运行,将文件数据存入集合中,读取值,判断次数,如果小于等于5次,则次数增加1次,如果大于则输出提示信息。 3、将值小于等于5次的信息数据存入文件中*/import java.util.*;import java.io.*;class APPNum{public static void main(String[] args)throws IOException {int count=runCount();if(count>5)//如果程序被使用了超过5次,则终止使用,并提示{System.out.println("次数到了,交钱!!!!!");return ;}elseSystem.out.println("程序第"+count+"次Run!");}//获取程序运行的次数public static int runCount()throws IOException{Properties ps=new Properties();//创建集合对象File file=new File("info.ini");//将文件进行封装if(!file.exists())//判断是否存在file.createNewFile();FileReader fr=new FileReader(file);//将文件于读取流进行关联ps.load(fr);//加载流中的文件数据到集合中int count=0;//定义计数器String value=ps.getProperty("time");//获取次数值if(value!=null)//如过值不等于null,则将其赋值给count{count=Integer.parseInt(value);}count++;//每启动一次自增ps.setProperty("time",count+"");//将次数记录住集合FileWriter fw=new FileWriter(file);ps.store(fw,"");//将集合中的数据存入硬盘文件中fr.close();//关流fw.close();return count;//返回程序启动的次数}}
运行结果:
6 打印流
概述
1、打印流包括:PrintStream和PrintWriter
2、该流提供了打印方法,可将各种类型的数据都原样打印。
字节打印流:PrintStream
构造方法中可接收的参数类型:
1、File对象。File
2、字符串路径:String
3、字符输出流:OutputStream
字符串打印流:PrintWriter
构造方法中可接受的参数类型
1、File对象:File
2、字符串路径:String
3、字节输出流:OutputStream
4、字符输出流:Writer
import java.io.*;class PrintStreamDemo{public static void main(String[] args) throws IOException{//键盘录入BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//打印流关联文件,自动刷新PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);String line = null;while((line=bufr.readLine())!=null){if("over".equals(line))//结束字符break;out.println(line.toUpperCase());//out.flush();}//关流out.close();bufr.close();}}
总结
1、流的对象很多,开发是具体选择那类流:
a、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
b、明确数据是否是纯文本数据
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
c、明确具体的设备(通过setIn和setOut可以改变默认输入输出设备)
源设备:硬盘:File 键盘:System.in 内存:数组 网络:Socket流
目的设备:硬盘:File 控制台:System.out 内存:数组 网络:Socket流
d、是否需要其他额外功能
是否需要高效(缓冲区): 是,就加上buffer
- 黑马程序员-java基础(七)-IO流
- 黑马程序员七、IO流
- 黑马程序员---JAVA基础---异常(七)
- 黑马程序员——七、java基础之IO(10)
- 黑马程序员——Java基础视频笔记(七):IO操作
- 黑马程序员-----java基础十八(java之IO流)
- 黑马程序员--Java基础五(Java中的IO流)
- 黑马程序员-java基础 io字符流
- 黑马程序员-java基础 io字节流
- 黑马程序员--JAVA基础之IO流
- 黑马程序员JAVA基础-IO流
- 黑马程序员 Java基础 ---> IO流
- 黑马程序员 JAVA基础<五> IO流
- 黑马程序员-JAVA基础-IO流
- 黑马程序员 java基础回顾---IO流
- 黑马程序员 Java基础----IO流(2)
- 黑马程序员---java基础---5IO流
- 黑马程序员----Java基础之IO流
- MyBatis SqlSessionFactory的几种常见创建方式
- Objective-C Foundation框架实践——NSArray(一)
- 在ogre中加载 ogremax场景文件方法
- 汇编语言 第三版 王爽 实验12 编写0号终端的处理程序
- kendoui分级显示
- 黑马程序员-java基础(七)-IO流
- 第二章 构造函数语意学 成员们的初始化队伍
- [置顶]R语言 分层抽样---分层随机抽样(SRS)(二 )
- OGRE的主要渲染流程
- GPU渲染3D图形的粗略步骤,虽然粗略但也是通用步骤
- 1021. 个位数统计 (15)
- java实现内部类
- Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
- commons-fileupload源码分析