java_IO流

来源:互联网 发布:小学英语课文朗读软件 编辑:程序博客网 时间:2024/06/02 07:52

IO

IO流:

       一、字节流:

              1InputStream 读入字节数据。

              2OutputStream 写出字节数据。

       二、字符流:

              1Reader 读入字符数据。

              2Writer 写入字符数据。

字符流:

FileWriter练习:

public class WriterTest{

   //创建文件流对象,必须处理或者抛出异常。

   public static void main(String[] args){

      //在外部创建文件流引用,不指定对象,方便内部处理异常。

      FileWriter fw = null;

      try{

         //创建一个文件流对象,并初始化路径。必须初始化,FileWriter没有空数构造函数。

         fw = new FileWriter("d:\\WriterTest.txt"); 

         fw.write("fanbotest");//向流中写入数据。些时写入流中,并没写入指定文件中。

         fw.flush();//刷新流中的数据至指定文件中。

      }catch(IOException e){

         System.out.println(e.toString());

      }finally{

         try{

            if(fw !=null)

                fw.close();//关闭流,并将流中数据刷新到指定文件中。

         }catch(IOExceptione){

            System.out.println(e.toString());

         }

      } 

   }

}

此例中,fw = new FileWriter("d:\\WriterTest.txt");如果此路径下已存在指定文件,那么此时创建的FileWriter流对象会将原有的文件覆盖掉。

要在原文件中续写内容,需要修改构造参数,如:

fw = new FileWriter("d:\\WriterTest.txt",true);  这时续写的内容会自动添加到原有文件的末尾。

注意:在向文件中续写内容时,要想换行,Windows只识别\r\n

FileRader

       read()read(char[] cbuf)read(char[] int off,int len)read(CharBuffer target)read方法的返回值都是int。参数是字符数组的,返回值是字符个数。当文件读到尾末时,返回值为-1

文件读入方式一:读一个打印一个。

例如:

   // 创建文件读入流,并指定路径需读的文件。

      FileReader fr = new FileReader("F:\\abc.txt");

      //循环读,直到读到尾末返回-1时结束,此时文件读完。

      while(fr.read()!=-1){

         System.out.println((char)fr.read());

      }

      fr.close();

文件读入方式二:读一个存一个,存满了一次全打印。

例如:

// 创建文件读入流,并指定路径需读的文件。

      FileReader fr = new FileReader("F:\\abc.txt");

      //定义一个字符数组,将取到的字符存入。

      char[] ch =newchar[1024];

      int len = 0;

      //循环读,直到读到末尾返回-1

      while((len =fr.read(ch))!=-1){

         //将字符数组中的字符变成字符串,一次打印。

         System.out.println(len+"  "+new String(ch,0, len));

      }

      fr.close();

文件的拷贝练习:

//练习拷贝一个txt文件。

package IO_Test;

import java.io.FileReader;

import java.io.FileWriter;

import java.io.IOException;

 

public class ReaderTest_01 {

   public static void main(String[] args) {

      //创建读和写的文件流引用。

      FileWriter fw = null;

      FileReader fr = null;

      try{

         //创建目的文件和源文件。

         fw = new FileWriter("D:\\copytest.txt");

         fr = new FileReader("F:\\abc.txt");

         //字符数组用来存储源文件中的字符数据。

         char[] ch =newchar[1024];

         int len = 0;

         while((len = fr.read(ch))!=-1){

            fw.write(ch, 0, len);//将字符数组数据写入目的文件。

         }

      }catch(IOException e){

         //捕到异常时,说明文件读写失败了,这时就让程序停止,抛出去让程序员处理。

         throw new RuntimeException("文件错误。");

      }finally{

         if(fw !=null){

            //注意:读入流和写出流在关闭时,要分别try

            try{

                fw.close();

            }catch(IOException e){

            }

         }

         if( fr !=null){

            try{

                fr.close();

            }catch(IOException e){              

            }

         }

      }

   } 

}

BufferedWriter:

缓冲区的出现是为了提高效率。

缓冲区在创建之前,必须先有流对象,也就是缓冲区没有空参数的构造函数。

只将流对象传入缓冲区的构造参数即可。

记住:只要用到缓冲区,就要刷新。

关闭缓冲区时,同时也关闭了流对象。

缓冲区多了一个newLine()方法:行分隔符,在Windows和linux里通用,跨平台的。Windows只识别\r\n,linux只识别\n。

BufferedReader

BufferReader有一个readLind方法,可以一次读取一行数据。非常效率。返回值为String,返回的数据只包括回车符以前的数据,并不包含量终止符。如果读到末尾,返回null

示例:

   //创建读入流对象,指定操作文件。

      FileReader fr = new FileReader("d:\\BufferedTest.txt");

      //定义缓冲区,将流传入构造参数。

      BufferedReader br = new BufferedReader(fr);

      String str = null;

      //读出缓冲区数据,一行一行的读。

      while((str = br.readLine())!=null){

         System.out.println(str);

      }

      br.close();

装饰设计模式:

       对已有的对象进行功能增强。

       定义类,将已有的对象传入,基于已有的功能,添加更强的功能。这个自定义的类叫做装饰类。

       装饰类通常通过构造方法,接收被装饰的对象。

示例:

package ZhuangShiSheJi;

 

public class ZhuangShiTest {

   public static void main(String[] args) {

      //建立原有类对象。

      Person p = new Person();

      //建立装饰类对象,将原类对象传进来。

      SuperPerson sp = new SuperPerson(p);

      sp.superEat();//调用新类新方法。

   }

}

//原有的类。

class Person{

   public void eat(){

      System.out.println("吃饭");

   }

}

//装饰类。

class SuperPerson{

   //建立原有类引用。

   private Personp;

   //将原类引用作为参数传进来。

   SuperPerson(Person p){

      this.p = p;

   }

   //建立新的装饰函数。比原有类的函数功能强大。

   public void superEat(){

      System.out.println("喝点小酒");

      p.eat();

      System.out.println("吃点心");

      System.out.println("抽根烟");

   }

}

装饰类和继承的区别:

装饰设计模式比继承更灵活,辟免了继承体系的臃肿,而且降低了类与类之间的关系。

装饰类因为增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强功能,所以装饰类和被装饰类通常都是属于一个体系中的。

如:

       MyReader//专门用于读取数据的类。

              |--MyTestReader

                     |--MyBufferTextReader

              |--MyMediaReader

                     |--MyBufferMediaReader

              |--MyDataReader

                     |--MyBufferDataReader

       MyReader//专门用于读取数据的类。

              |--MyTestReader

              |--MyMediaReader

              |--MyDataReader

              |--MyBufferReader

LineNumberReader

它是一个装饰类,跟踪行号的缓冲字符输入流。

setLineNumber(int):设置当前行号,从传入的参数int开始计起。

getLineNumber():获取当前行号。返回值为int

// 创建读入流对象。

FileReader fr = new FileReader("D: \\ExceptionTest.java");

      //创建行号跟踪流对象,并将读入流对象传入。

      LineNumberReader lnr = new LineNumberReader(fr);

      String line = null;

      //设置行号从100开始递加。

      lnr.setLineNumber(100);

      while((line = lnr.readLine())!=null){

         //打印出指定文件的每行内容,并将行号打印在前面。

         System.out.println(lnr.getLineNumber()+"  "+line);

      }

      lnr.close();

   }

字节流:

InputStream读入    OutputStream写出

在使用字节流写出数据时,不用刷新,不关闭流,也可以写出数据。

OutputStream

//创建字节文件写出流,并指定目的文件。

      FileOutputStream os = new FileOutputStream("d:\\OutputStreamTest.txt");

      //将字符串转换成字节数组,并写入指定文件中。

      os.write("fanbo_test_OutputStream".getBytes());

   os.close();

使用字节流读入文件有三种方式:

一、一个字节一个字节的读。

//创建文件读入流,并指定源文件。

      FileInputStream fis = new FileInputStream("d:\\OutputStreamTest.txt");

      int ch = 0;

      //一个字节一个字节的读。

      while((ch=fis.read())!=-1){

         //将读到的每个字节转换成字符。

         System.out.println((char)ch);

      }

      fis.close();

二、将源文件按字节读入数组中,再一次取出。

   //创建文件读入流,并指定源文件。

      FileInputStream fis = new FileInputStream("d:\\OutputStreamTest.txt");

      //定义一个字节数组,将源文件的数据读到这里面。

      byte[] b =newbyte[1024];    

      int len = 0;//len取得读到数据的长度。

      while((len = fis.read(b))!=-1){

         //将读入b字节数组的数据转换成字符串打印出。

         System.out.println(new String(b,0,len));

      }

      fis.close();

三、用available方法定义一个刚好够的字节数组。

      //创建文件读入流,并指定源文件。

      FileInputStream fis = new FileInputStream("d:\\OutputStreamTest.txt");

      //avalable()方法可以返回源文件中的字节数。

      int num = fis.available();

      //将字节数组的长度定义为源文件数据的长度。

      byte[] b =newbyte[num];

      //直接把刚好长度的数组读进流。

      fis.read(b);

      //再把数据变成字符串打印出来。

      System.out.println(new String(b));

      fis.close();

   此第三种方法,虽然最简便,但是如果操作一个巨大的文件,比如1G多的电影,这时内存会溢出。不安全。

    所以,这三种读入方法,第二种最适用

拷贝图片:

    用字节流,用字符流也可以拷贝,但是很可能打不开,凡同操作媒体数据,都用字节流,不要用字符流。

代码:

package IO_Test;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

 

public class CopyPictureTest {

   public static void main(String[] args) {

      FileInputStream fis = null;

      FileOutputStream fos = null;     

      try{       

         fis = new FileInputStream("e:\\fanbo.jpg");//源图片。

         fos = new FileOutputStream("d:\\樊波.jpg");//目的图片。

         byte[] b =newbyte[1024];

         int len = 0;

         //读取图片,并写到目的。

         while((len = fis.read(b))!=-1){

            fos.write(b,0,len);

         }

      }catch(IOException e){

         throw new RuntimeException("拷贝图片失败");

      }finally{

         try{

            if(fis!=null)

                fis.close();

         }catch(IOException e){

            System.out.println("读取流关闭失败");

         }

         try{

            if(fos!=null)

                fos.close();

         }catch(IOException e){

            System.out.println("写出流关闭失败");

         }

      }

   }

}

拷贝Mp3

       通过字节流缓冲区拷贝。

部分代码:

   BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e:\\流浪记.mp3"));

      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\copytest.mp3"));

      int ch = 0;

      while((ch = bis.read())!=-1){

         bos.write(ch);

      }

      bis.close();

      bos.close();

readwrite的特点:

read在做类型提升,write在做强转,保证了原数据的不变化。

读取键盘录入:

       System.out:对应的是标准输出设备,控制台。

       System.in:对应的标准输入设备,键盘。返回值类型为:InputStream

回车符:\r-->13    \n-->10

 

练习:需求:通过键盘录入数据,录入一行打印一行,如果录入over,就停止录入。

import java.io.IOException;

import java.io.InputStream;

 

public class SystemInTest {

   public static void main(String[] args)throws IOException {

      //创建读入流,指定键盘录入。

      InputStream is = System.in;

      //创建缓冲区,记录读到的数据。

      StringBuilder sb = new StringBuilder();

      //循环操作读到的数据。

      while(true){

         int ch = is.read();//一个一个读。

         if(ch=='\r')

            continue;//如果读到\r继续循环读。

         if(ch=='\n'){

            String s = sb.toString();//读到\n时,就将读到的所有数据变成字符串。

            if("over".equals(s))

                break;//判断一下,如果字符串是over,就跳出结束。

            System.out.println(s.toUpperCase());//打印字符串。

            sb.delete(0, sb.length());//清空缓冲区。

         }

         else

             sb.append((char)ch);//将读到的数据存到缓冲区里。 

      }

   }

}

此方法较复杂,可以通过使用转换流InputStreamReader,使用readLine方法,更简便。

例如:

//创建键盘录入对象。

      InputStream is = System.in;

      //创建读入转换流,字节流转换为字符流。

      InputStreamReader isr = new InputStreamReader(is);

      //建立字符流缓冲区,它有readLine方法。

      BufferedReader br = new BufferedReader(isr);

      String line = null;

      //循环录入数据,并读入。

      while((line = br.readLine())!=null){

         if("over".equals(line))//判断over结束。

            break;

         System.out.println(line.toUpperCase());//打印出来。

      }

      br.close();

   }

写出流转换:

public class OutputStreamWriterTest {

   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 = null;

      //循环录入一行,输出一行。

      while((line=br.readLine())!=null){

         if("over".equals(line))//结束标记。

            break;

         bw.write(line.toUpperCase());//写出。

         bw.newLine();//换行。

         bw.flush(); //刷新。    

      }

      bw.close();

      br.close();

   }

}

键盘的最常见写法:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

操作流的基本规律:

       三个明确:

一、明确源和目的。

       源:输入流,InputStream    Reader

       目的:输出流,OutputStream    Writer

二、操作的数据是不是纯文本。

       是:字符流。

       不是:字节流。

三、当体系明确后,在明确要使用哪个具体的对象。

       通过设备来进行区分:

       源设备:内存、硬盘、键盘。

       目的设备:内存、硬盘、控制台。

是否要提高效率?是:加入缓冲区。

需求:将键盘录入的数据保存到一个文件中。

       分析:

       源:InputStream  Reader

          是否为纯文件?是,Reader

       设备:键盘,对应的对象是System.in

           System.in对应的是字节流,选Reader是为了操作方便,将字节流转成字符流。

           那么就将System.in转成Reader。用到InputStreamReader

              InputStreamReaderisr = new InputStreamReader(System.in)

       要提高效率吗?要。BufferedReader

              BufferedReader= br = new BufferedReader(isr)

       目的:OutputStream  Writer

           是否为纯文件?是。Writer

       设备:硬盘。使用FileWriter

           FileWriter fw = newFileWriter("d:\\cc.txt")

       需要提高效率:

           BufferedWriter bw = new BufferedWriter(fw)

扩展:

       要想把录入的数据按指定的编码表(utf-8),将数据存到文件中。

       FileWriter是使用的默认编码表,GBK

       这时要使用的对象是转换流。OutputStreamWriter只有转换流,在传参数时,才可以指定编码表。

   OutputStreamWriter osw = new OutputStreamWriter("d:\\aa.txt","utf-8");

记住:转换流是字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。

    当使用转换流,将字定编码的流数据写入到某文件时,要想读取此文件,也得指定同样的编码才可以读取。同样,通过转换流指定编码:InputStreamWriter osw =new InputStreamWriter("d:\\aa.txt","utf-8");

System中有两不常用的方法:(介绍)

一、System.setIn(InputStream  in):将键盘录入更改为指定读取流对象。

    例:System.setIn(“d:\\fanbo.txt”);这时,数据就不在是键盘录入了,而是fanbo.txt中的数据内容。

二、System.setOut(printStream ps):将控制台更改为指定写入流对象。

   例:System.setOut(“e:\\cc.txt”):这时,原来打印在控制台的数据,就存到了cc.txt里面了。

异常的日志信息:

   

系统信息:

 

File

separator :跨平台的分隔符,在windows的绝对路径中\\表示分隔符,如c:\\fanbo\\fan.txt。但是\\不跨平台。可以用separator代替。如”c:”+File.separator+”fanbo”+File.separator+”fan.txt”

创建File对象:

1File f1 = newFile("c:\\abc\\a.txt");

2File f2 = newFile("c:\\abc","a.txt");

3File d = newFile("c:\\abc");

     File f3 = new File(d,"a.txt");

123种创建方式都指向同一个路径。打印f1f2f3,得到所指的路径。

File类常见方法:

、创建

       booleancreatNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流相反,输出流对象一建立就创建文件,如果文件存在,会覆盖。

     static File createTempFile(String XX,StringXX):创建临时文件。

、删除

       booleandelete():删除文件或者目录,目录必须为空才能删除,失败则返回false

       voiddeleteOnExit():在程序退出时删除指定文件

、判断

       booleancanExecute():判断文件是否可以执行。

       booleanexists():文件是否存在。

       booleanmkdir():创建一级目录,就是创建文件夹,只能创建一级。"abc\\ab"就可以,"fdsk\\fdf\\dfsf\\fdfsd"就不可以。

       booleanmkdirs():创建多级文件夹。

       booleanisDirectory():是否是目录。

       booleanisFile():是否是文件。

       对一个文件或者目录判断时,必须要判断该文件对象是否存在,通过exists判断。(很容易出错) 注意:目录也可以是xxx.txt,它就不是文件。

       booleanisHidden():是否是隐藏文件。

       booleanisAbsolute():判断是不是绝对路径,文件不存在也可以判断。

、获取

       StringgetName():获取文件名字。

       StringgetPath():获取相对路径。封装的什么路径,得到的就是什么路径。文件不存在也可以获取。

       StringgetParent():获取父目录。返回的是绝对路径中的父目录,如果是相对路径,返回null。就是上一层目录,只返回一级

       StringgetAbsolutePath():获取绝对路径。文件不存在也可以获取。

       longlastModified():返回时间,最后一次修改时间。

       longlength():返回文件大小。

       booleanrenameTo()改名字,类似剪切

       示例:

       Filef1 = new File("c:\\Test.java");

       Filef2 = new File("c:\\haha.java");

       f1.renameTo(f2);Test.java的名字改为haha.java

       如果File f2 = new File("d:\\haha.java");这时f1调用renameTo方法,就将Test.java改名后,移到了d盘,就是又改名又移动,类似剪切。

File[] listRoots():返回的是File[],可以列出电脑里的有效盘符。

例:File[] f2 =File.listRoots();

      for(File f :f2){

         sop(f);

   }

String[] list():列出指定目录下的所有文件或文件夹名称,包含隐藏文件,调用它必须是该对象封装的是目录。

例:File f1 = new File("e:");

      String[] str = f1.list();

      for(String s : str){

         sop(s);

   }

String[] list(FilenameFilter filter)过滤器文件名。

例:File f1 = new File("f:");

      String[] str = f1.list(new FilenameFilter(){

         public boolean accept(File dir,String name){

            return name.endsWith("docx");

         }

   });

File[] listFiles():返回的是文件,可以对文件进行操作,String[] list()只是返回的文件名,不能进行操作。

例:File f1 = new File("f:");

      File[] str = f1.listFiles();

      for(File s : str){

         sop(s.getName()+"    "+s.length());

      }

练习:列出目录下所有内容。(递归)

递归要注意:

       1、限定条件。

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

package IO_Test;

import java.io.File;

public class DiGuiTest {

   public static void main(String[] args) {

      Filef = newFile("E:");//指定要列出所有目录的父目录。

      getDrictory(f);

   }

   //创建获取方法:获取指定目录下的所有文件。

   public static void getDrictory(File dir){

      File[]files = dir.listFiles();//将指定目录的子目录存到File数组中。

      System.out.println(dir);//打印父目录。

      //循环打印子目录及文件。

      for(int x=0; x<files.length; x++){

         if(files[x].isDirectory())//如果有子目录,就使用递归,将子目录的文件打印。

            getDrictory(files[x]);

         else

            System.out.println(files[x]);//打印子目录。

      }

   }

}

练习:删除带内容的目录。(用到递归)

package IO_Test;

import java.io.File;

public class DeleteTest {

   public static void main(String[] args) {

      File file = new File("d:\\fanbo");//指定要删除的目录及里面的所有内容。

      deleteFile(file);//调删除方法。

   }

   //定义删除方法。

   public static void deleteFile(File f){

      //传入要删除的目录,再将些目录的子目录装进File[]数组。

      File[] files = f.listFiles();

      for(int x=0; x<files.length;x++){

         //判断,如果是目录,就递归。

         if(files[x].isDirectory()){

            deleteFile(files[x]);

         }

         Else

            System.out.println(files[x]+"::--::"+files[x].delete());//删除文件。

      }

      System.out.println(f+"::--::"+f.delete());//将已删掉子文件的空目录也删掉。

   }

}

练习:创建java文件列表。(和毕老师的代码不一样

package IO_Test;

import java.io.File;

import java.io.FileWriter;

import java.io.IOException;

 

public class GetFileDirectoryTest {

   public static void main(String[] args)throws IOException {     

      //定义要创建列表的目录。

      File file = new File("E:\\中关村-黑马程序员\\Java零基础辅导班 - 李若亮");

      //将目录存到当前的txt中。

      FileWriter fw = new FileWriter("E:\\中关村-黑马程序员\\Java零基础辅导班 - 李若亮\\li.txt");    

      getFileDirectory(file,fw);//调用自定义获取方法。

   }

   //制作获取方法,参数为要创建的目录,和要写出的数据流,

   public static void getFileDirectory(File file,FileWriter fw)throws IOException{

      File[] files = file.listFiles();

      for(File f : files){

         if(f.isDirectory())//如果是目录,就递归。

            getFileDirectory(f,fw);

         fw.write(f.getAbsolutePath()); //获取绝对路径,并写到目的txt文件中。

         fw.write("\r\n");//存一个就换行。

      }

   }

}

Propertise

Propertieshashtable的子类。

它具备map集合的特点,它里面存储的健值对都是字符串。就不用泛型了。

是集合和IO技术相结合的集合容器

该对象的特点,可以用于键值对形式的配置文件ini(就是软件的一些属性,比如设置颜色corlor=50)。(文本=红色,背景=绿色)

Properties的存取方法:

       setProperty(Stringstr1,String str2):直接存入键和值。

       getProperty(Stringstr)str为键。返回value值。

       stringPropertyNames():返回值的是Set集合。将键存入到Set集合中。

Properties已经封装好了将配置文件(键值对的文件)中的数据通过流加载进集合。

在加载数据时,需要数据有固定格式:键=值。

直接用load(InputStream is)load(Reader read)两个方法就能将流数据加载进集合。

list(PrintStream ps)将属性列表输出到指定的输出流。如:XXX.list(System.out)就将键值信息打印到控制台上。

store(OutputStream out, String comments)方法,能将集合中修改过的数据存储到流的目的文件中。

练习:用于记录应用程序运行次数,使用次数已到,那么给出注册提示。

 

打印流:

PrintStream:字节打印流。

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

    1file对象。File

    2、字符串路径。String

    3、字节输出流。OutputStream

PrintWriter:字符打印流。很常用。

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

    1file对象。File

    2、字符串路径。String

    3、字节输出流。OutputStream

    4、字符输出流。Writer

打印流:该流提供了打印方法,可以将各种数据类型都原样打印。

示例:

public class PrintStream {

   public static void main(String[] args)throws IOException {

      //创建键盘录入。

      BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));

      //PrintWriter pw = newPrintWriter(System.out);//打印流,直接传入控制台,需要刷新。

      //PrintWriter pw = newPrintWriter(System.out,true);//true参数,可以不用刷新,直接输出。

      //PrintWriter pw = newPrintWriter("d:\\fanbo.txt");//直接传入文件,不能刷新。

      PrintWriter pw = new PrintWriter(new FileWriter("d:\\fanbo.txt"),true);//加上文件写出流,就可以加true自动刷新了。

      String line = null;

      while((line = bfr.readLine())!=null){

         if("over".equals(line))

            break;

         pw.println(line.toUpperCase());

         pw.flush();

      } 

      bfr.close();

      pw.close();

   }

合并流:SequenceInputStream

    将多个流合并成一个流。例如:把三个txt文档的内容合到一个txt文档中,先建立3个读取流,再使用SequenceInputStream流把3个读取流合成一个流。

它有两种构造函数:

1SequenceInputStreamInputStream s1InputStream s2):将2读取流合成一个流。

2SequenceInputStreamEnumeration<InputStream> e):把多个读取流合成一个,参数是枚举,就是先将多个流存到Vector集合中,然后再合成一个。

示例:三流合一流。

public class SequenceInputStreamTest {

   public static void main(String[] args)throws IOException {

      //建立Vector集合,泛型指定存入文件读入流对象。

      Vector<FileInputStream> v = new Vector<FileInputStream>();

      //添加3个文件读入流对象。

      v.add(new FileInputStream("d:\\完美国际名字.txt"));

      v.add(new FileInputStream("d:\\题谷公司地址.txt"));

      v.add(new FileInputStream("d:\\MySQL路径.txt"));

      //枚举。

      Enumeration<FileInputStream> en = v.elements();

      //定义合并流,将en传入,三流变成一流。

      SequenceInputStream sis = new SequenceInputStream(en);

      //定义文件写出流,并指定目的。

      FileOutputStream bis = new FileOutputStream("d:\\三合一.txt");

       byte[] b =newbyte[1024];

       int len = 0;

       while((len = sis.read(b))!=-1){

          bis.write(b,0,len);          

       }

       sis.close();

       bis.close();

   }

}

切割文件:

       和合并流相反,将某文件切割成几份。

示例:

public class SplitFileTest {

   public static void main(String[] args)throws IOException {

      //定义读取流,确定要被切割的源文件。

      FileInputStream fis = new FileInputStream("d:\\许佳慧-预谋.mp3");

      FileOutputStream fos = null;//先声明一个文件写出流。    

      byte[] b =newbyte[1024*1024];//定义一个1M的容器。

      int len = 0;

      int count = 1;

      while((len = fis.read(b))!=-1){

         //将刚好1M的容器数据写入到指定目的。计数器count自增后,下次就另存一个目的文件。

         fos = new FileOutputStream("d:\\"+(count++)+".part");

         fos.write(b, 0, len);

         fos.close();

      }

      fis.close();

   }

}

IO包中的其他类:

ObjectInputStream   ObjectOutputStream

ObjectOutputStream构造时必须有一个流对象。

writeObjectreaderObjet成对使用。

要序列化的对象必须实现Serializable接口,Serializable是一个标记接口,没有方法。

当某个对象已经持久化存到硬盘了,再改动过代码,再存,这时就读不出改过后的对象了,因为改动前已经有一个序列号UID,改动后生成了新的UID,不一样就识别不出来。UID是根据成员属性来生成的序列号。

如果你想改动后仍是原来的对象,那么自定义固定的UID,不让虚拟机自动生成。

如:public static final long serialVersionUID= 42L;

如果对象中有静态成员,将不能被序列化。

如果不是静态成员,又不想被序列化,就加transient修辞。

一般将对象序列存为xxx.object

写出示例:

//创建对象写出流。

      ObjectOutputStreamoos =newObjectOutputStream(new FileOutputStream("d:\\person.object"));

      oos.writeObject(new Person("樊波",20));//指定要写出的对象。

      oos.close();//关流。

读取示例:

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\person.object"));

      Person p = (Person)ois.readObject();//读取对象。

      System.out.println(p);

      ois.close();

管道流:

PipedInputStreamPipedOutputStream

涉及到多线程的IO流,输出流和输入流同时进行。

如何连接?

1、构造函数就对方的流传进来。如:PipedInputStream(PipedOutputStream src);

2、通过方法connect(PipedOutputStreamsrc)连接。

示例:

import java.io.*;

 

class Read implements Runnable

{

   private PipedInputStreamin;

   Read(PipedInputStream in)

   {

      this.in = in;

   }

   public void run()

   {

      try

      {

         byte[] buf =newbyte[1024];

         System.out.println("读取前。。没有数据阻塞");

         int len =in.read(buf);

         System.out.println("读到数据。。阻塞结束");

 

         String s= new String(buf,0,len);

 

         System.out.println(s);

 

         in.close();

 

      }

      catch (IOException e)

      {

         throw new RuntimeException("管道读取流失败");

      }

   }

}

 

class Write implements Runnable

{

   private PipedOutputStreamout;

   Write(PipedOutputStream out)

   {

      this.out = out;

   }

   public void run()

   {

      try

      {

         System.out.println("开始写入数据,等待6秒后。");

         Thread.sleep(6000);

         out.write("piped lai la".getBytes());

         out.close();

      }

      catch (Exception e)

      {

         throw new RuntimeException("管道输出流失败");

      }

   }

}

 

class  PipedStreamTest

{

   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();

   }

}

 

RandomAccessFile:随机读取访问。(重点掌握

随机访问文件,结尾没有父类名,自成一派。

该类不算是IO体系中的子类,而是直接继承自Object。但它是IO包中成员,因为它具备读和写功能。

内部封装了一个数组,而且通过指针对数组中的元素进行操作。

可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。

完成读写的原理就是内部封装了字节输入流和输出流。

通过构造函数可以看出,该类只能操作文件,而且操作文件还有模式。只读r,读写rw

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

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

可以对数据进行分段存储,比如三条线程,分段写进某一文件。

示例:

import java.io.*;

 

class RandomAccessFileDemo

{

   public static void main(String[] args)throws IOException

   {

      //writeFile_2();

      //readFile();

      //System.out.println(Integer.toBinaryString(258));

   }

   public static void readFile()throws IOException

   {

      RandomAccessFile raf = new RandomAccessFile("ran.txt","r");     

      //调整对象中指针。

      //raf.seek(8*1);

      //跳过指定的字节数

      raf.skipBytes(8);

 

      byte[] buf =newbyte[4];

 

      raf.read(buf);

 

      String name = new String(buf);

 

      int age = raf.readInt();

 

      System.out.println("name="+name);

      System.out.println("age="+age);

 

      raf.close();

   }

 

   public static void writeFile_2()throws IOException

   {

      RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");

      raf.seek(8*0);

      raf.write("周期".getBytes());

      raf.writeInt(103);

      raf.close();

   }

   public static void writeFile()throws IOException

   {

      RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");

 

      raf.write("李四".getBytes());

      raf.writeInt(97);

      raf.write("王五".getBytes());

      raf.writeInt(99);

      raf.close();

   }

}

 

DataStream

DataInputStreamDataOutputStream

操作基本数据类型的流对象。

示例:

import java.io.*;

class DataStreamDemo

{

   public static void main(String[] args)throws IOException

   {

      //writeData();

      //readData();

      //writeUTFDemo();

//    OutputStreamWriter osw = new OutputStreamWriter(newFileOutputStream("gbk.txt"),"gbk");

//    osw.write("你好");

//    osw.close();

//    readUTFDemo();

   }

   public static void readUTFDemo()throws IOException

   {

      DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));

      String s = dis.readUTF();

      System.out.println(s);

      dis.close();

   }

   public static void writeUTFDemo()throws IOException

   {

      DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));

      dos.writeUTF("你好");

      dos.close();

   }

   public static void readData()throws IOException

   {

      DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

      int num = dis.readInt();

      boolean b = dis.readBoolean();

      double d = dis.readDouble();

      System.out.println("num="+num);

      System.out.println("b="+b);

      System.out.println("d="+d);

      dis.close();

   }

   public static void writeData()throws IOException

   {

      DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

      dos.writeInt(234);

      dos.writeBoolean(true);

      dos.writeDouble(9887.543);

      dos.close();

      ObjectOutputStream oos = null;

      oos.writeObject(new O());     

   }

}

ByteArrayStream

初始化时必须有源数据。关闭此流无效,此类中的方法在关闭此流后仍可被使用,而不会产生任何IOException

ByteArrayInputStream:构造时,需接收数据源,数据源是一个字节数组。

ByteArrayOutputStream:构造时,不用定义数据目的,因为内部封装了长度可变的字节数组。这就是数据目的。

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

源设备:

       键盘 System.in,硬盘FileStream内存 ArrayStream

目的设备:

       控制台 System.out,硬盘FileStream内存ArrayStream

        //数据源。

      ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());

      //数据目的

      ByteArrayOutputStream bos = new ByteArrayOutputStream();

      int by = 0;

      while((by=bis.read())!=-1){

         bos.write(by);

      }

      System.out.println(bos.size());

      System.out.println(bos.toString());

与之对应的类还有:

1CharArrayReader、CharArrayWriter

2StringReader、StringWriter

功能同理。

转换流的字符编码:

//编码。向指定流文件中写入你好,按UTF-8编码。

OutputStreamWriter osw = newOutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");

      osw.write("你好");

      osw.close();   

      //解码。读取流文件中的数据,按gbk解码。

      InputStreamReader isr = new InputStreamReader(new FileInputStream("utf.txt"),"gbk");

      char[] buf =newchar[10];

      int len = isr.read(buf);

      String str = new String(buf,0,len);

      System.out.println(str);

      isr.close();

    表编码后再用另一种码表解码,会出现乱码。

    表:2个字节一个字符。

    8码表:3个字节一个字符。

字符编码:

编码:字符串变成字节数组。

解码:字节数组变成字符串。

String-->byte[]; str.getBytes(charsetName);字符串变成字节数组,按参数charseName编码。

byte[] -->String: new String(byte[],charsetName);字节数组变成字符串,按参数charseName解码。

注意:

       GBK编码,若用iso8859-1解码,无凝出现乱码,这时将乱码用iso8859-1编码,再用GBK解码,获得原有数据,情况出现在网页向Tomcat服务器传数据。

       若用GBK编码,再用UTF-8解码,无凝出现????乱码,再将乱码用UTF-8编码,再用GBK解码,不能获得原有数据。GBKUTF-8都能识别中文。

      String s = "你好";//原数据。

      byte[] b1 = s.getBytes("GBK");//GBK编码。

      System.out.println(Arrays.toString(b1));

      String s1 = new String(b1,"utf-8");//UTF-8解码。

      System.out.println("s1="+s1);

      byte[] b2 = s1.getBytes("utf-8");//UTF-8编码。

      System.out.println(Arrays.toString(b2));

      String s2 = new String(b2,"gbk");//GBK解码。

      System.out.println("s2="+s2);

联通:

以“联通”两个字打头存入记事本,这时是以默认GBK码表存入数据。当再次打开记事本时,这时去以UTF-8码表解码,出现乱码。

原因:“联通”这两个字在编码时存入时的二进制数字第一位为110****,第二位10****,符合了UTF-8码表的头识别,在打开记事本时,就自动用UTF-8解码了。

 

练习:

/*

有五个学生,每个学生有3门课的成绩,

从键盘输入以上数据(包括姓名,三门课成绩),

输入的格式:如:zhagnsan304060计算出总成绩,

并把学生的信息和计算出的总分数高低顺序存放在磁盘文件"stud.txt"中。

1,描述学生对象。

2,定义一个可操作学生对象的工具类。

思想:

1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。

2,因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。

   所以可以使用TreeSet

3,将集合的信息写入到一个文件中。

*/

 

package IO_Test;

import java.io.*;

import java.util.*;

public class SaveStudentsTest {

   public static void main(String[] args)throws NumberFormatException,IOException {

      TreeSet<Student> trse = new TreeSet<Student>();//创建TreeSet集合,用来存学生。

      StudentTool.setStudent(trse);//调用添加学生信息的函数。

      StudentTool.saveStudent(trse);//调用将学生信息存到指定文档中的函数。

   }

}

//学生工具类,有添加学生信息的功能和将学生信息存到指定文档中的功能。

class StudentTool{

   //添加学生信息的函数

   public static void setStudent(TreeSet<Student> ts)throwsNumberFormatException, IOException{

      //键盘录入。

      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

      String line = null;

      while((line = br.readLine())!=null){

         if("over".equals(line))//over为结束标记。

            break;

         String[] s = line.split(",");//将录入的信息用,号分割。

         //将录入的学生信息包成对象。

         Student stu = new Student(s[0],Integer.parseInt(s[1]),Integer.parseInt(s[2]),Integer.parseInt(s[3]));

         ts.add(stu);//将学生对象存入集合。

      }

   }

   //将学生信息存到指定文档中的函数

   public static void saveStudent(TreeSet<Student> ts)throws IOException{

      //指定写出流对象,指定要写入的文档。

      BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\student.txt"));

      for(Student s : ts){

         bw.write("姓名:"+s.getName()+"   总分:"+s.getSum());//向文档中写入学生姓名和总分。

         bw.newLine();

         bw.flush();

      }

      bw.close();       

   }

}

//学生类。

class Studentimplements Comparable<Student>{

   //属性有姓名,数学分数、语文分数、英语分数,总分。

   private Stringname;

   private int math;

   private int chinese;

   private int english;

   private int sum;

   //构造函数。

    Student(String na,int ma,int ch,int en){

      this.name = na;

      this.math = ma;

      this.chinese = ch;

      this.english = en;

      this.sum = ma+ch+en;

   }

   public String getName(){

      return name;

   }

   public int getSum(){

      return sum;

   }

   public int hashCode(){

      return name.hashCode()+sum*22;

   }

   public boolean equals(Object obj){

      if(!(objinstanceof Student))

         throw new ClassCastException("类型不符");

      Student s = (Student)obj;

      return this.name.equals(s.name) &&this.sum==s.sum

   } 

   public int compareTo(Student s) {

      int num =new Integer(this.sum).compareTo(new Integer(s.sum));

      if(num == 0)

         return this.name.compareTo(s.name);

      return num;

   }

}

 

 



 

0 0
原创粉丝点击