java基础12 IO

发布时间:2016-12-7 0:05:17 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"java基础12 IO",主要涉及到java基础12 IO方面的内容,对于java基础12 IO感兴趣的同学可以参考一下。

IO中的流对象 InputStream OutputStream 字节流   BufferedInputStream BufferedOutputStream 字节缓冲区   ByteArrayInputStream ByteArrayOutputStream 操作字节数组   DataInputStream DataOutputStream     FileInputStream FileOutputStream 操作图片、音视频等文件   FilterInputStream FilterOutputStream     ObjectInputStream ObjectOutputStream 操作对象   PipedInputStream PipedOutputStream           Reader Writer 字符流   BufferedReader BufferedWriter 字符流缓冲区   CharArrayReader CharArrayWriter 操作字符数组   StringReader StringWriter 操作字符串   FileReader FileWriter 操作文本文件的   InputStreamReader OutputStreamWriter 转换流   PipedReader PipedWriter     FilterReader FilterWriter           LineNumberInputStream     LineNumberReader           PrintStream 字节打印流   PrintWriter 字符打印流         PushbackInputStream     PushbackReader           SequenceInputStream     StringBufferInputStream 操作字符串的字节流         Console     File 用于封装文件   FileDescriptor     FilePermission     ObjectInputStream.GetField     ObjectOutputStream.PutField     ObjectStreamClass     ObjectStreamField     RandomAccessFile     SerializablePermission     StreamTokenizer                目的 源      内存 文件 控制台 Sokcet 内存         文件         Socket         IO 一、字符流 1、 FileWriter (1)、FileWriter    FileWriter的继承结构是: lang.object>io.Writer> io.OutputStreamWriter    构造方法摘要 FileWriter(File file)            根据给定的 File 对象构造一个 FileWriter 对象。   FileWriter(File file, boolean append)            根据给定的 File 对象构造一个 FileWriter 对象。   FileWriter(FileDescriptor fd)            构造与某个文件描述符相关联的 FileWriter 对象。   FileWriter(String fileName)            根据给定的文件名构造一个 FileWriter 对象。   FileWriter(String fileName, boolean append)            根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。     从类 java.io.OutputStreamWriter 继承的方法 close, flush, getEncoding, write, write, write 从类 java.io.Writer 继承的方法 append, append, append, write, write   使用FileWriter对象,写入数据的步骤:1 导包,2 创建一个FileWriter对象。需要注意的是:该对象一被初始化就必须要有要操作的对象,如果该目录下已有指定的要操作的同名文件,原有文件将被覆盖。3 使用write方法向目标文件中写入数据fw.write("abc"); 4 刷新fw.flush() ; 5 fw.write("def") ;会写在abc后面;6 fw.flush();关闭流资源,关闭前会刷新fw.close();   (2)、文件的续写, API中FileWriter有构造函数FileWriter(String fileName, boolean append) 。可用于在文件的原有数据上加入数据,而不去覆盖原文件。如果参数append为 true,则将数据写入文件末尾处,而不是写入文件开始处。   (3)、文本文件的读取方式1,读取单个字符就操作        Reader不用刷新,使用Reader的read方法读取的是字符。可以一次读取单个字符然后操作,或是将读取到的字符缓存入字符数组然后操作,不能直接读字符串。Reader使用的是默认的字符编码,使用System.getPorperties()可以得到系统信息。read()返回类型是int 可以根据需要将其强转成(char)。        特点:此方法会自动往下读,读到流的末尾返回-1,并且一直阻塞        使用read()方法读取一次读取单个字符。示例代码        FileReader fr = new FileReader(c:\\demo.txt);        int ch = 0 ; while((ch = fr.read())!=-1){        //对读取的字符进行操作 }   (4)、文本文件的读取方式2, 读取单个字符,将其存入指定大小的字符数组,待将数组装满,再对结果操作        read(char[] cbuf) 返回的是读到的字符个数,数据类型是int 。使用此方法可以将数据缓冲入cbuf中。 通常为了方便,要将得到的cbuf转换为String类型。方法是new String(cbuf,0,num) ,其中num是read的返回值,这样就将字节数组cbuf中的0~num个字节转成了一个字符串,num是读到的字符个数,即cbuf中的有效字符个数,避免了无效字符的产生。 特点:读到末尾返回-1一直阻塞        示例代码        FileReader fr = new FileReader(c:\\demo.txt);        //定义一个指定大小的字符数组,用以缓存read读到的字符        byte[] cbuf = new byte[1024] ; int num = 0 ; while((num = fr.read(cbuf))!=-1){        //对读取的字符进行操作 } (5)、拷贝文本文件   2 bufferedWriter bufferedReader (1)、BufferedWriter BufferedReader        字符流缓冲区1、缓冲区的出现提高了对数据的读写效率,在创建缓冲区钱,要操作的流对象必须存在。2、对应类:BufferedWriter和BufferedReader3、缓冲区使用时要结合流4、在流的基础上对流的功能进行了增强5、出现了新的方法。 BufferedWriter BufferedReader是Writer和Reader的子类。继承了它们的读写方法,同时有自己更加功能更实用的方法。 BufferedWriter的void write(int c) ,写入单个字符,write(char[] cbuf, int off, int len) 写入字符数组的某一部分,write(String s, int off, int len) 写入字符串的某一部分,newLine()写入一个行分隔符,这个方法在各种平台通用。有自己的刷新的关闭方法。 BufferedReader的readLine()方法可以一次读取一行,但不包含终止符,如果读到流的末尾返回null。他的结束标记是回车符,返回类型是String。   (2)、通过缓冲区复制文本文件, readLine方法读取的数据不包含行终止符,所以读取一行后,要加入换行符; 并且写入后一定要刷新,如果不刷新,数据将保留在缓冲区中,刷新后数据才被写进目标; 缓冲区提高了FileWriter的效率,但真正和文件相关联并对文件进行操作的是FileWriter缓冲区的关闭,实际上关闭的是调用底层资源的流对象。   (3)、readLine()方法的原理,        无论是读一行,获者读取多个字符。都必须在硬盘上一个一个字符读取,所以最终使用的还是一次读取一个的read方法,。readLine方法内部封装了一个数组,使用read方法读取一个字符后,并没有将这个字符返回给下一步的操作者,而是将其存储在数组中,直到读到换行符的\r时,再调用一次read方法读取一个字符,如果这个字符是\n,就将数组中的数据一次性返回给下一步的操作者。   4、MyBufferedReader        MyBufferedReader{ private Reader r ;        MyBufferedReader(Reader r){               this.r = r ; } public String myReadLine(){ StringBuilder sb = new StringBuilder(); int ch; while((ch = read() )!=-1) {//使用传入的功能 if(ch == ’\r’)        coutinue; if(ch == ‘\n’){        return sb.toString();       } else sb.append((char)ch); //添加前要转换为char, } return null ;       } }   2 装饰设计模式 (1)、装饰设计模式, 当想要对已有的对象的功能进行增强时,可以定义一个类,将想要增强的类传入,并基于已有的功能,提供新的更强大的功能 。这种方法我们称之为装饰设计模式。增强类称之为装饰类。 装饰类基于被装饰类,并且通常装饰类和被装饰类属于同一个体系。   (2)、装饰和继承的区别 装饰设计模式的由来 是专门用于读取文本数据的类,它有一些子类。在使用MyReader子类读文本时,发现效率低,想到了缓冲技术,由MyReader的子类衍生出了一些用于缓冲的子类。 下面是它的继承体系。               MyReader                      |--MyTextReader                             |--MyBufferTextReader                      |--MyMediaReader                             |--MyBufferMediaReader                      |--MyDataReader                             |--MyBufferDataReader        如果MyReader的每个直接子类都需要增强,这样产生的继承体系,臃肿复杂,这个时候就需要对现有的体系进行优化。思路是可以定义一个类,将需要缓冲的MyReader的直接子类作为参数传入。        MyReader直接子类原来的功能是读,定义的装饰类增强了读取的功能,所以装饰类的功能也是读取,因此也应该是MyReader体系中的一员,所以它应该继承MyReader。                      class MyBufferedReaer() extends MyReader                      {                             private Reader r ;                             MyBufferedReaer(MyReader r)                             {                                    this.r = r ;                             }                             //增强功能                      } 这样,原来的体系就变得简单起来,MyReader直接子类和装饰类的关系由继承变成了组合               MyReader                      |--MyTextReader                      |--MyMediaReader                            |--MyDataReader                      |--MyBufferBufferReader   装饰类对原有对象的功能进行了增强,它具备的功能和原有对象的功能都可以达到同样的目的。但是装饰类的功能使用起来更加方便。 所以装饰类和被装饰类通常都是属于同一个体系.   (3)、自定义装饰类        在定义装饰类时,定义的增强功能因为原有功能而有可能产生异常时,不能捕捉,而应该抛出,让调用者处理。 4 LineNumberReader: (1)、LineNumberReader        LineNumberReader是BufferedReader子类,是可以跟踪行号的缓冲字符输入流。 此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。并且有readLine()方法。 (2)、MyLineNumberReader import java.io.*; class MyLineNumberReader extends BufferedReader {        private int lineNumber ;        MyLineNumberReader(Reader r)        {               super(r) ;        }        public String myReadLine() throws IOException        {               //每调用一次myReadLine() lineNumber自增1 ; lineNumber++ ;               return super.readLine();        }        //特有方法        public void setLineNumber(int lineNumber)        {               this.lineNumber = lineNumber ;        }        public int getLineNumber()        {               return lineNumber;        } } 二 字节流 1 FileInputStream FileOutputStream: 字节流的read方法读取的是字节,可以读取单个字符,或是将读取的字符存入字节数组。available()方法返回字符的个数( \r 和\n分别是一个字节)。可以使用这个方法定义一个大小等于源的缓冲区。 (1)、字节流File读写操作        字节流write方法不用刷新。        一次读一个字节 FileInputStream fis = new FileInputStream(“c:\\demo.txt”);        FileOutputStream fos = new FileOutputStream(c:\\demo_1.txt) ; int len = 0 ; while((len= fis.read())!=-1){ fos.write(len);        } 读入字节数组中,然后写入目标 FileInputStream fis = new FileInputStream(“c:\\demo.txt”);        FileOutputStream fos = new FileOutputStream(c:\\demo_1.txt) ; byte[] b = new byte[1024]; int num = 0 ; while((num= fis.read(b))!=-1){ fos.write(b,0,num);        }        available()方法的使用 FileInputStream fis = new FileInputStream(“c:\\demo.txt”);        FileOutputStream fos = new FileOutputStream(c:\\demo_1.txt) ; byte[] b = new byte[fis.available()]; fis.read(b); fos.write(b); (2)、拷贝图片        2 BufferedInputStream BufferedOutputStream: (1)、字节流缓冲区   (2)、自定义字节流的缓冲区 read和write的特点   读取字节时,如果读到连续八个1,连续的八个1对应的是整数-1,程序会错误地以为是结束标记,会停止读取,导致目标文件不完整,复制失败。 为什么返回的是int而不是byte 11111111 ——>提升为一个int类型,那不还是-1吗?是-1的原因是,在八个1前面补了1,那么在八个1前面补0,就可以避免这种-1,即可以保留原字节数据不变,由可以避免-1的出现 所以用int接收byte,将其类型提升。然后使用&255的方式,在原数据前补0 ,避免了读到连续八个一,等于-1,和结束标记相等 的情况。如下图 byte:-1 ——> int:-1 ; 00000000 00000000 00000000 11111111 255, 11111111 11111111 11111111 11111111 -1   取最后4位:&15() 取最后8位&255 import java.io.*; class MyBufferedInputStream  {        private InputStream in ;        private byte[] buf = new byte[1024*1024];        private int pos = 0 , count = 0;              MyBufferedInputStream(InputStream in)        {               this.in = in ;        }        //一次读一个字节,从缓冲区(字节数组)获取        public int myRead() throws Exception        {               //通过in对象读取硬盘上数据,并存储buf中               if(count == 0 )               {                      count = in.read(buf);                      if(count<0)                             return -1;                      pos = 0 ;                      byte b = buf[pos];                                           count -- ;                      pos++ ;                      return b&255/*255的十六进制表现形式*/ ;               }               else if(count>0)               {                      byte b = buf[pos];                      count -- ;                      pos++ ;                      return b&255;               }               return -1 ;        }        public void myClose()throws Exception        {               in.close();        }        public static void copyMp3()throws Exception        {               MyBufferedInputStream bis =                      new MyBufferedInputStream(new FileInputStream("c:\\王麟 - 当爱情离开的时候.mp3"));               BufferedOutputStream bos =                      new BufferedOutputStream(new FileOutputStream("c:\\王麟 - 当爱情离开的时候_copy.mp3"));                             //byte[] buf = new byte[1024*1024];               //int len = 0 ;               int by = 0 ;               while((by = bis.myRead())!=-1)               {                      bos.write(by);               }               bis.myClose();               bos.close();        }               public static void main(String[] args) throws Exception        {               long start = System.currentTimeMillis();               System.out.println(start);               copyMp3();               long end = System.currentTimeMillis();               System.out.println(end);               System.out.println("用时"+(end-start)+"毫秒");                      } } (3)、读取键盘录取        使用字节流进行键盘录入               InputStream in = System.in;               StringBuilder sb = new StringBuilder();               while(true)               {                      String s = null ;                      int ch = in.read();                      if(ch == '\r')                             continue ;                      if(ch == '\n')                      {                             s = sb.toString();                                                         if("over".equals(s))                                    break ;                             System.out.println(s.toUpperCase());                             sb.delete(0,sb.length());                      }                                   else                      {                             sb.append((char)ch);                      }               }              三 转换流      InputStreamReader OutputStreamWriter 四 流的常规操作 OutputStreamWriter可以指定编码表 怎么选择流对象? 1明确源和目的        源:输入流 InputStream Reader        目的:输出流 OutputStream Writer 2操作的数据是否是存文本        是:用字符流        否:字节流 3当体系明确后,再明确使用哪个具体的对象        源:内存,硬盘,键盘        目的:内存,硬盘,控制台 五 其他操作 1、 改变标准输入输出设备        static void setIn(InputStream in)            重新分配“标准”输入流。 static void setOut(PrintStream out)            重新分配“标准”输出流。        2、 异常的日志信息        异常的日志信息,以下是异常日志信息的建立方式。但真正开发时,不用这样的方法,在网络上有一个专门建立java日志信息的工具包log4j。 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 (Exception e)               {                                          try                      {                             Date d = new Date();                             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");                             String s = sdf.format(d);                                                         PrintStream ps = new PrintStream("c:\\ExceptionInfo.txt");                             ps.println(s);                                   System.setOut(ps);                                    }                      catch (IOException e2)                      {                                   throw new RuntimeException("创建异常日志文件失败");                      }                      e.printStackTrace(System.out);               }        } } 3、 系统信息 System类中的static Properties getProperties() 方法可以得到系统信息。Properties类可以 和流相结合 import java.util.*; import java.io.*; class  GetProperties {        public static void main(String[] args) throws IOException        {               Properties prop  = System.getProperties();               System.setOut(new PrintStream("systeminfo.txt"));               prop.list(System.out);        } }   五 流操作文件:File对象        创建, 删除, 判断, 获取, 文件列表-1, 文件列表-2, 列出目录下所有内容--递归, 列出目录下所有内容--带层次, import java.io.*; 递归的英文是单词recursion 在列出目录的过程中,因为目录中还有目录,只要使用同一个列出目录功能的函数即可完成。在列出过中出现的还是目录的话,还可以再次调用本功能,也就是函数自身调用自身。这种表现形式,或者编程手法称为递归。 递归要限定循环条件,如if等。要不然会死循环;而且要注意递归次数,避免内存溢出。 下面是使用递归的思想列出一个目录下的所有文件和目录 class  RecursionDemo {        public static void main(String[] args)        {               File f = new File("F:\\1115java\\javawork");                     showDir(f);               //showDirlist(f);        }               public static void showDir(File f)        {               int x = 0;               so.p("          "+f);               File[] files = f.listFiles();                     for(File f2 : files ){                      x++ ;                      //如果是目录,调用showDir方法.                      if(f2.isDirectory())                      {                             showDir(f2);                      }                      //如果不是目录,打印。                      else                             so.p("file"+x+" :"+f2);               }        }        //插入层级目录        public static String getLevel(int level)        {               StringBuilder sb = new StringBuilder();               sb.append("|————");               for(int x = 0; x<level ;x++ )               {                      sb.intsert(0,"   ");               }        }          public static void showDirlist(File f)        {               int x = 0;               String[] strs = f.list();                            for(String str : strs ){                      x++ ;                                   so.p("strs"+ x+" :"+str);               }        } } 删除带内容的目录, 创建java文件列表 六 Properties 1、Properties的继承结构 java.lang.Object > java.util.Dictionary<K,V> > java.util.Hashtable<Object,Object>  >java.util.Properties   2、存取 3、存取配置文件 4、练习 七 其他流对象 1、PrintWriter,PrintStream :可以直接操作输入流和文件。 2、序列流(对多个留进行合并) SequenceInputStream有构造函数SequenceInputStream(Enumeration<? extends InputStream> e) Vector集合可以得到Enumeration 1、所以我们可以将文件封装成读取流        FileInputStream(File file) FileInputStream(String name);//InputStream是抽象的 2、再将读取流封装成Vector集合        Vector<FileInputStream> v = new Vector<FileInputStream>()        v.add(new FileInputStream(String name)) 3、再由Vector集合的elements()方法 得到Enumeration        Enumeration<FileInputStream> e = v.elements(); 3、切割流 为了达到切割文件的目的,可一讲一个输出流切成几个部分 思路 1将要操作的对象封装成流对象 2建立一个字节数组,这个字节数组的大小将成为切割后单个文件的大小标准。 3建立循环,循环一次,建立一个流,写入规定大小的数据,然后关闭流 import java.io.*; class  slitFile {        public static void main(String[] args) throws Exception        {               splitFile();               System.out.println("Hello World!");        }        public static void splitFile()throws Exception        {               //1将操作对象封装成流对像               FileInputStream fis = new FileInputStream("c:\\1.jpg");               //2               byte[] b = new byte[1024*10];               //3               int count = 1;               int len = 0;               while((len = fis.read(b))!=-1)               {                      FileOutputStream fos = new FileOutputStream("c:\\"+(count++)+".part");                      fos.write(b,0,len);                      fos.close();               }        } } 4、对象的序列化(对象的持久化存储、对象可串行性) (1)、使用到的流对象ObjectInputStream 与ObjectOutputStream(OutputStream.out)。在ObjectOutputStream类中有写入基本数据类型的write方法,写入对象的writeObject()方法。 (2)、标记接口Serializable 和uid。 类通过实现java.io.Serializable接口以启用其序列化功能。接口Serializable中没有方法, 没有方法的接口通常称为标记接口。    每个类在编译时会声明一个uid,uid是根据类中成员的数字签名生成的。在类中属性改变时,uid会改变。 使用标记接口Serializable,显示声明了所标记类的serialVersionUID : ANY-ACCESS-MODIFIER/*任何访问修饰符*/ static final long serialVersionUID = 42L;    uid可以自己设置数值。 抛出异常: java.io.NotSerializableException        (3)、将对象存储为文件后,已经编码。用记事本打开后是乱码。        (4)、存储代码               class demo{                      public static void main(){               writeObj() ;        //写入 } public static void writeObj(){        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“c:\\demo.txt”)) ;        oos.writeObject(new Person(“ lisi ” , 39)) ; } //读取 public static void readObj() throws ClassNoFoundException{        ObjectInputStream ois  =  new ObjectInputStream(new  FileInputStream(“obj.txt”)) ;                             Person p = (Person)ois.readObject() ;                             ois.close() ; } }   5、管道流        PipedinputStream和PipedOutputStream (1)、管道输入流应该链接到管道输出流,使用单个线程可能产生死锁        (2)、管道流链接方式 1、PipedinputStream(PipedOutputStream) 2、connetct()方法        (3)、 读到管道流中,从管道流写入控制台 管道流的示例代码 class Read implements Runnable{        private PipedinputStream in ;        Read(){        this.in = in ; } public void run(){        try{        Byte[] buf = new byte[1024] ;        int len = in.read( buf ) ;        String s = new String(buf ,0 ,len) ;                                    in.close() ; } Catch(IOException e){        Throw new RuntimeException(“管道流读取失败”) ; } } } class Write implements Runnable{        private PipedOutputStream Out ;        Read(){        this.in = in ; } public void run(){        try{                                    out.write(“ …… ”.getBytes() ) ;                                    out.close() ; } Catch(IOException e){        Throw new RuntimeException(“管道流写入失败”) ; } } } Class PipedStreamDemo{        Public static void main(){               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() ; } }   6、RandomAccessFile        (1)、随机访问文件,自身具备读写的方法 。通过skipBytes(int x ), seek(int x ) 来达到随机访问。        (2)、直接继承自Object。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。        (3)、该类只能操作文件,RandomAccessFile(String name ,String mode)               Mode 可以取r(只读)、rw(读取写入)、rws()、rwd()        (4)、方法:  读取基本数据类型,readInt( ) , readLine() ,写入 基本数据类型        (5)、示例               class RandomAccessFileDemo{                      public static void main(String[] args) throws IOException{                             writeFile() ; } public static void writeFile() throws IOException {        RandomAccessFile raf = new RandomAccessFile(“ran.txt ” , “rw”) ;        raf.write(“李四”.getBytes()) ;        raf.write(97) ;        raf.close() ; } } 打开ran.txt,里面是“李四a”如果年龄写入的是258,这时会丢失数据。 调整对象中的指针。seek(int x) (6)、skipBytes(int x )跳过指定字节数 ; (7)、随机写入,实现数据分段写入   7、操作基本数据类型的流对DataStream,        (1)、DataInputStream 与 DataOutputStream 可用于操作基本数据类型的流对象。       (2)、构造:DataOutputStream(OutputStream out ) , (3)、方法:a、写入基本数据类型。 (4)、特殊方法writeUTF(String str) :以一种方式写入字符串,只能用对应的方式读出来。用转换流读不出来 演示代码 基本数据类型的读取与写入: Class DataStreamDemo{        Public static void main(){               DataInputStream dis = new DataInputStream(new FileInputStream(“data.txt”));               int num = dis.readInt() ;               boolean b = dis.readBoolean() ;               double d = dis.readDouble() ; } Public static void writeData(){        DataOutputStream dos = new DataOutputStream(new FileOutputStream(“demo.txt”)) dos.writeInt(234) ; dos.writeBoolean(true) ; dos.writeDouble(9887.54) ; dos.close() ; } }       WriteUTF ——utf—8修改版 普通写入: OutputStreamWrite osw = new OutputStreamWriter(new FileOutputStream(“utf.txt”) , “utf-8”) ;        osw.write(“你好”) ;        osw.close() ; WriteUTF 的使用,写入要用readUTF DataOutputtream dos = new DataOutputStream(new FileOutputStream(“utfdata.txt”)) ; dos.writeUTF(“你好”) ; dos.close() ;        readUTF中的EOFException异常。读取所有字节前达到末尾。 8、操作字节数组中数据ByteArrayInputStream 与ByteOutputStream ByteArrayInputStream将源数据存储进内部缓冲区,一建立对象就要有数据源存在,而且数据源是一个字节数组。ByteArrayOutputStream对象中封装了一个随数据写入自动增长的byte数组。这个数组就是目的。可以使用toByteArray() 和toString()获取数据。 未调用底层资源,关闭流无效。不会产生IO异常。

上一篇:Linux下DDNS客户端的使用
下一篇:Ubuntu下vsftp安装和配置

相关文章

关键词: java基础12 IO

相关评论