黑马程序员—Java中的IO流

来源:互联网 发布:webshell密码破解 编辑:程序博客网 时间:2024/05/01 10:35

11. IO流

 

11.1IO流概述

 

IO流用来处理设备之间的数据传输。流按操作数据分为两种:字节流与字符流。

流按流向分为:输入流,输出流。

 

字节流的抽象基类:InputStream  OutputSream

字符流的抽象基类:Reader    Writer


11.2字符流

 

1FileWriter

import java.io.*;class FilerWriterDemo {public static void main(String[] args) throws IOException{/*创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件  而且该文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖。  其实该步就是在明确数据要存放的目的地*/FileWriter fw = new FileWriter("demo.txt");//调用write方法,将字符串写入到流中fw.write("abcde");//刷新流对象中的缓冲中的数据,将数据刷到目的地中fw.flush();/*关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据,将数据刷到目的地  和flush区别:flush刷新后,流可以继续使用。close刷新后,会将流关闭。*/fw.close();}}

IO异常处理方式:

import java.io.*;class FilerWriterDemo2 {public static void main(String[] args) {FileWriter fw = null;try{//在此处进行fw初始化,以免出现异常时,finally语句无法读取到fw对象fw = new FileWriter("demo.txt");fw.write("abcdefg");}catch (IOException e){System.out.println(e.toString());}finally{try{/*当上述语句出现异常时,fw不会创建,fw.close()语句将会出现fw类 文件不存在的异常,因此进行一次判定来解决*/if(fw!=null)fw.close();}catch (IOException e){System.out.println(e.toString());}}}}

对已有文件的数据续写:

import java.io.*;class FilerWriterDemo3 {public static void main(String[] args) {FileWriter fw = null;try{/*传递一个true参数,代表不覆盖已有的文件,  并在已有文件的末尾处进行数据的续写*/fw = new FileWriter("demo.txt",true);fw.write("\r\nhaha");}catch (IOException e){System.out.println(e.toString());}finally{try{if(fw!=null)fw.close();}catch (IOException e){System.out.println(e.toString());}}}}


2FileReader

import java.io.*;class FileReaderDemo {public static void main(String[] args) {/*创建一个文件读取流对象,和指定名称的文件相关联要保证该文件  是已经存在的,如果不存在会发生异常FileNotFoundException*/FileReader fr = null;try{fr = new FileReader("demo.txt");/*读取方法一:调用读取流对象的read方法  read()方法一次读一个字符,而且会自动往下读,已到末尾返回-1*/int ch = 0;while ((ch=fr.read())!=-1)System.out.println((char)ch);/*读取方法二:定义一个字符串数组,用于存储读到字符。该read(char[])  返回的是读到字符个数*/char[] buf = new char[1024];int num = 0;    while ((num=fr.read(buf))!=-1){System.out.println("num="+num+"..."+new String(buf,0,num));}}catch (IOException e){System.out.println(e.toString());}finally{try{if(fr!=null)fr.close();}catch (IOException e){System.out.println(e.toString());}}}}

3)拷贝文本文件

import java.io.*;class CopyText {public static void main(String[] args) {copy_2();}//复制方式一:从C盘读一个字符,就往D盘写一个字符public static void copy_1(){//创建目的地FileWriter fw = null;//与已有文件关联FileReader fr = null;try{fw = new FileWriter("RuntimeDemo_copy.txt");fr = new FileReader("RuntimeDemo.java");int ch = 0;while ((ch = fr.read())!=-1){fw.write(ch);}}catch (IOException e){throw new RuntimeException("读写失败");}finally{try{if(fr!=null)fr.close();}catch (IOException e){throw new RuntimeException("读取关闭失败");}finally{try{if(fw!=null)fw.close();}catch (IOException e){throw new RuntimeException("写入关闭失败");}}}}//复制方式二:从C盘读取一段,再存到D盘中public static void copy_2(){//创建目的地FileWriter fw = null;//与已有文件关联FileReader fr = null;try{fw = new FileWriter("SystemDemo_copy.txt");fr = new FileReader("SystemDemo.java");char[] buf = new char[1024];int len = 0;while ((len = fr.read(buf))!=-1){fw.write(buf,0,len);}}catch (IOException e){throw new RuntimeException("读写失败");}finally{try{if(fr!=null)fr.close();}catch (IOException e){throw new RuntimeException("读取关闭失败");}finally{try{if(fw!=null)fw.close();}catch (IOException e){throw new RuntimeException("写入关闭失败");}}}}}


11.3字符流的缓冲区

 

缓冲区的出现提高了对数据的读写效率,缓冲区要结合流才可以使用,在创建缓冲区之前,必须要先有流对象


1)  BufferedWriter

该缓冲区中提供了一个跨平台的换行符:newLine();

import java.io.*;class BufferedWriterDemo {public static void main(String[] args) throws IOException{//创建一个字符写入流对象FileWriter fw = new FileWriter("buf.txt");/*为了提高字符写入流效率,加入缓冲技术,只要将需要被提高效率的流对象  作为参数传递给缓冲区的构造函数即可*/BufferedWriter bufw = new BufferedWriter(fw);for (int x = 1;x<5 ;x++ ){bufw.write("abcd"+x);bufw.newLine();bufw.flush();}//只要用到缓冲区,就要记得刷新bufw.flush();//关闭缓冲区就是在关闭缓冲区中的流对象bufw.close();}}

2)  BufferedReader

该缓冲区提供了一个一次读一行的方法,方便于对文本数据的获取:readLine()。当返回null时表示读到文件末尾,返回的时候只返回回车符之前的数据内容。

import java.io.*;class BufferedReaderDemo {public static void main(String[] args) throws IOException{//创建一个读取流对象和文件相关联FileReader fr = new FileReader("buf.txt");/*为了提高效率,加入缓冲技术,将字符读取流对象  作为参数传递给缓冲对象的构造函数*/BufferedReader bufr = new BufferedReader(fr);String line = null;while ((line = bufr.readLine())!=null){System.out.println(line);}bufr.close();}}


LineNumberReader类:是BufferedReader类的子类,有两个新方法

getLineNumber():获得当前行号

setLineNumber():设置当前行号



11.4装饰设计模式

 

当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类称为装饰类

装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。

 

装饰模式比继承更灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常都属于一个体系中。


装饰类和被装饰类都是,被装饰类父类的一个子类。创建自定义装饰类时,要继承父类,那么需要复写父类中的抽象方法


11.5字节流


1)  FileInputSream ()

public static void readFile_3() throws IOException{FileInputStream fis = new FileInputStream("fos.txt");//定义一个刚刚好的缓冲区,不用再循环了,数据不大时使用。byte[] buf = new byte[fis.available()];     //该文件可使用的容量fis.read(buf);System.out.println(new String(buf));fis.close();}public static void readFile_2() throws IOException{FileInputStream fis = new FileInputStream("fos.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();}


2)  FileOutputSream ()

public static void writeFile() throws IOException{FileOutputStream fos = new FileOutputStream("fos.txt");//字节流不能写入字符串,通过String.getBytes()方法将字符串转成byte数组写入fos.write("abcde".getBytes());/*不需要flush()。因为字符流也是写入字节,但是需要将写入的字节先临时缓存。  查完表后通过flush()再写入字符。而字节流不需要缓存,直接就将字节写入*/fos.close();}


11.6字节流的缓冲区

 

BufferedOutputStream

BufferedInputStream

//通过缓冲区拷贝mp3文件:import java.io.*;class CopyMp3 {public static void main(String[] args) throws IOException{long start = System.currentTimeMillis();copy_1();long end = System.currentTimeMillis();System.out.println((end-start)+"毫秒");}//通过字节流缓冲区完成复制public static void copy_1() throws IOException{BufferedInputStream bufis = <span style="white-space:pre"></span>new BufferedInputStream(new FileInputStream("mp3.mp3"));BufferedOutputStream bufos = <span style="white-space:pre"></span>new BufferedOutputStream(new FileOutputStream("mp3_copy.mp3"));int by = 0; while ((by=bufis.read())!=-1){bufos.write(by);}bufos.close();bufis.close();}}


11.7读取键盘录入

 

System.in:对应的标准输入设备:键盘

 

1)  InputStreamReader

是字节流通向字符流的桥梁,将字节流对象转成字符流对象。

 

2)  OutputStreamWriter

字符流通向字节流的桥梁。

/*通过键盘录入数据,当录入一行数据后,就将该行数据进行打印  如果录入的数据是over,那么停止录入*/import java.io.*;class ReadIn {public static void main(String[] args) throws IOException{//获取键盘录入对象InputStream in =System.in;//将字节流对象转成字符流对象,使用转换流InputStreamReaderInputStreamReader isr = new InputStreamReader(in);//为了提高效率,将字符流进行缓存区技术高效操作,使用BufferedReaderBufferedReader bufr = new BufferedReader(isr);//获取输出对象OutputStream out = System.out;//将字节流对象转成字符流对象,使用转换流OutputStreamWriterOutputStreamWriter osw = new OutputStreamWriter(out);BufferedWriter bufw = new BufferedWriter(osw);String line = null;while ((line=bufr.readLine())!=null){if("over".equals(line))break;bufw.write(line.toUpperCase());bufw.newLine();bufw.flush();}bufr.close();bufw.close();}}


11.8流操作规律

 

1)  明确源和目的

源:输入流。InputStream  Readerr

目的:输出流 OutputStream Writer

2)  操作的数据是否是纯文本

是:字符流

不是:字节流

3)  当体系明确后,再明确要使用哪个具体的对象

通过设备来进行区分

源设备:内存ArrayStream,硬盘 FileStream,键盘 System.in

目的设备:内存 ArrayStream,硬盘 FileStream,控制台 System.out


改变标准输入输出设备:

//将输入设备由键盘改成PersonDemo.java文件,需要建立一个字节流对象FileInputStream

System.setIn(new FileInputStream(“PersonDemo.java”)) 

//将输出设备由控制台改成zz.txt文件,需要建立一个字节输出流子类对象PrintStream

System.setOut(new PrintStream(“zz.txt”))


11.9File类

 

用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作

File类常见方法:

1)  创建

boolean mkdir():创建文件夹,只能创建一级目录

boolean mkdirs():创建多级目录,包括所有必需但不存在的父目录

boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立就会创建文件,而

且文件已经存在,会覆盖。File类要调用方法才创建文件。

 

2)  删除

boolean delete():如果此句前出现异常将不会执行到,文件就无法删除

void deleteOnExit():在程序退出时删除。在程序运行出现异常的时候也能删除文件。

3)  判断

boolean canExecute():判断文件是否可执行

boolean exists():判断文件是否存在

boolean isDirectory():           判断文件对象是否是文件或者目录时,必须要先判断

boolean isFile():               该文件对象封装的内容是否存在,通过exists判断

boolean isHidden():判断文件是否隐藏

4)  获取信息

getName()

getPath()

getParent()                该方法返回的是绝对路径中的父目录,如果File对象封装的是相对路径,返回null。如果相对路径中有上一层目录那么该目录就是返回结果

getAbsolutePath()    获取绝对路径

long lastModified()   获取文件最后被修改的时间

long length()

boolean renameTo()     f1.renameTo(f2),变更文件名,还会将文件剪切到指定目录下

File[] listRoots()         列出可用的系统盘符

String[] list()           列出目录下的文件和子目录。调用list方法的file对象必须是封装了一个目录,该目录还必须存在

File[] listFiles()         列出目录下的文件,返回的是File对象的数组

列出指定目录下文件或者文件夹,包含子目录中的内容(带层次):import java.io.*;class FileDemo3 {public static void main(String[] args) {File file = new File("c:\\java001");showDir(file,0);}public static void showDir(File dir,int level ){System.out.println(getLevel(level)+dir.getName());//level只对应于调用的函数中,递归调用时对应的是函数中相应的值level++;File[] files = dir.listFiles();for (int x = 0; x<files.length;x++ ){//如果是文件夹,可以调用方法本身继续遍历文件夹if(files[x].isDirectory())showDir(files[x],level);elseSystem.out.println(getLevel(level)+files[x].getName());}}public static String getLevel(int level){StringBuilder sb = new StringBuilder();//文件夹及文件名前带|--sb.append("|--");for (int x=0;x<level ;x++ ){//子级目录缩进sb.insert(0,"  ");}return sb.toString();}}

函数自身调用自身,这种表现形式称为递归。使用时需要注意:

1)限定条件

2)要注意递归的次数,尽量避免内存溢出



11.10Properties类

 

Properties是hashtable的子类,具备map集合的特点,它里面存储的键值对都是字符串。是集合中和IO技术相结合的集合容器。该对象的特点:可以用于键值对形式的配置文件。

Properties中的方法:

setProperty(String key, String value)       向集合中存入键值对

String  getProperty(String key)           获取对应键的值

Set<String>  stringPropertyNames()      获取Properties对象中键的集合

 

list(PrintStream out)

list(PrintWriter out)

load(InputStream inStream)

load(Reader reader)

store(OutputStream out, String comments)       将Properties中的键值对存储到配置文件中

store(Writer writer, String comments)            并且加入注释信息comments。

import java.io.*;import java.util.*;class  PropertiesDemo{public static void main(String[] args) throws IOException{//method_1();PropertiesMethod();}//load,list,store方法应用public static void PropertiesMethod() throws IOException{FileInputStream fis = new FileInputStream("Info.txt");Properties prop = new Properties();//将流中的数据加载进集合prop.load(fis);//设置配置文件中的信息prop.setProperty("wangwu","39");FileOutputStream fos = new FileOutputStream("Info.txt");prop.store(fos,"haha");//将集合中的数据输出到流中prop.list(System.out);fos.close();fis.close();}//load方法原理:将info.txt中键值数据存到集合中进行操作。public static void method_1() throws IOException{BufferedReader bufr = new BufferedReader(new FileReader("Info.txt"));String line = null;Properties prop = new Properties();while ((line=bufr.readLine())!=null){//利用=将键与值分割String[] arr = line.split("=");//调用方法将键和值存入到集合中prop.setProperty(arr[0],arr[1]);}bufr.close();}//设置和获取元素public static void setAndGet(){Properties prop = new Properties();prop.setProperty("zhangsan","30");prop.setProperty("lisi","39");String value = prop.getProperty("lisi");System.out.println(value);Set<String> names = prop.stringPropertyNames();for(String s : names){System.out.println(s);}}}


11.11打印流

 

为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。该流提供了打印方法,可以将各种数据类型的数据都原样打印

 

字节打印流:

PrintStream

构造函数可以接收的参数类型:

1.      file对象    File

2.      字符串路径 String

3.      字节输出流 OutputStream

 

字符打印流:

PrintWriter

构造函数可以接收的参数类型:

1.      file对象    File

2.      字符串路径 String

3.      字节输出流 OutputStream

4.      字符输出流 Writer

PrintWriter(OutputStream out, booleanautoFlush)    autoFlush为true时,println方法会

PrintWriter(Writer out, boolean autoFlush)          自动刷新缓存


11.12 序列流SequenceInputStream

 

SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

import java.io.*;import java.util.*;class  SequenceDemo{public static void main(String[] args) throws IOException{Vector<FileInputStream> v = new Vector<FileInputStream>();v.add(new FileInputStream("1.txt"));v.add(new FileInputStream("2.txt"));v.add(new FileInputStream("3.txt"));Enumeration<FileInputStream> en = v.elements();SequenceInputStream sis = new SequenceInputStream(en);FileOutputStream fos = new FileOutputStream("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();}}


11.13对象的序列化

 

 

ObjectInputStream   ObjectOutputStream

 

将堆内存中的对象存入的文件当中,对象内的变量数据也被保存;读取文件的可以读取到所存储的对象,直接调用之前的数据。实现了Serializable接口的对象才能被序列化。

 

在需要序列化的对象中添加static final long serialVersionUID = 42L语句,即使本地的该对象有所修改,也可以读取被序列化的对象,否则会报出InvalidClassException异常。

 

static 修饰的变量不能被序列化,因为static修饰的内容存在于方法区;transient修饰的变量也不能被序列化,即使变量存在于堆内存中。


11.14管道流

 

PipedInputStream        PipedOutputStream

 

管道输入流和管道输出流通过不同线程运行。管道流是多线程和IO流的结合应用

import java.io.*;class Read implements Runnable{private PipedInputStream in;Read(PipedInputStream in){this.in = in;}public void run(){try{byte[] buf = new byte[1024];//当没有读取到数据时read方法会阻塞,即线程等待。int len = in.read(buf);String s = new String(buf,0,len);System.out.println(s);in.close();}catch (IOException e){throw new RuntimeException("管道读取流失败");}}}class Write implements Runnable{private PipedOutputStream out;Write(PipedOutputStream out){this.out = out;}public void run(){try{out.write("piped lai le".getBytes());out.close();}catch (IOException e){throw new RuntimeException("管道输出流失败");}}}class  PipedStreamDemo{public static void main(String[] args) throws IOException{PipedInputStream in = new PipedInputStream();PipedOutputStream out = new PipedOutputStream();in.connect(out);Read r = new Read(in);Write w = new Write(out);new Thread(r).start();new Thread(w).start();}}


11.15RandomAccessFile

 

该类不是IO体系中的子类,而是直接继承自Object。但是它是IO包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组中的元素进行操作。可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。

 

能够完成读写的原理就是内部封装了字节输入流和输出流。该类只能操作文件,操作模式通常有只读r和读写rw。

 

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

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

 

该类可以通过多个线程同时对一个文件进行读写操作,下载就是利用此原理

import java.io.*;class RandomAccessFileDemo {public static void main(String[] args) throws IOException{//writeFile2();//writeFile();//readFile();}public static void readFile() throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","r");//调整对象中的指针,来读取想要读取的内容,往前往后都能调整//raf.seek(8);//跳过指定的字节数,来读取想要读取的内容,只能往后跳//raf.skipBytes(8);byte[] buf = new byte[4];raf.read(buf);String name = new String(buf);//从此文件读取一个有符号的 32 位整数int age = raf.readInt();System.out.println("name="+name);System.out.println("age="+age);raf.close();}//向指定位置写入数据public static void writeFile2() throws IOException{//创建对象时与输出流不同,不会覆盖已有文件RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");raf.seek(8*3);raf.write("周期".getBytes());raf.writeInt(103);raf.close();}public static void writeFile() throws IOException{RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");raf.write("李四".getBytes());//按4个字节写入int数字raf.writeInt(97);raf.write("王五".getBytes());raf.writeInt(99);raf.close();}}


11.16DataStream

 

可以用于操作基本数据类型的数据的流对象


11.17ByteArrayStream

 

ByteArrayInputStream   : 在构造的时候,需要接收数据源,而且数据源是一个字节数组

ByteArrayOutputStream  : 在构造的时候,不用定义数据目的,因为该对象中已经内部封

装了可变长度的字节数组,这就是数据目的地

 

因为这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭

ByteArrayStream是用流的思想来操作数组

import java.io.*;class  ByteArrayStream{public static void main(String[] args) {//数据源ByteArrayInputStream bis = new ByteArrayInputStream("ABCDE".getBytes());//数据目的ByteArrayOutputStream bos = new ByteArrayOutputStream();int by = 0;while ((by=bis.read())!=-1){bos.write(by);}System.out.println(bos.toString());//将字节数组输出流中的数据写入到一个文件当中bos.writeTo(new FileOutputStream("a.txt"));}}


0 0
原创粉丝点击