IO<二>

File:

 File类是io包中唯一代表磁盘文件本身的对象,File类定义了一些与平台无关的方法来操作文件,

 可以通过调用File类中的方法,实现创建.删除.重命名文件等,File类是对象主要用来获取未文件本身

 的一些信息,如文件所在的目录,文件的长度.文件的读写权限等.数据流可以将数据系写入到文件中,

 而文件也是数据流最常用的数据媒体.

 

构造方法:

 

 File(File parent, String child)// parent:子路径字符串  child:父路径字符串

         根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。

 

 File(String pathname) //pathname指包括文件路径(包文件名)

     通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。

 

 File(String parent, String child) //

     根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

 

 File(URI uri)

     通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。

 

---------------------------------------------------------------------------------------------

 

 File类常见方法:

 

  1,创建。

 

  boolean | createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。

       和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。

 

  boolean | mkdir():创建文件夹。

 

  boolean | mkdirs():创建多级文件夹。

 

   演示:

   File f=new File("file.txt");    

   sop("create:"+f.createNewFile());//创建文件 

   sop("mkdir:"+f.mkdir());//创建文件夹  

   sop("mkdir:"+f.mkdirs());//创建多级的文件夹

    

   ps:sop代表打印语句.

  ------------------------------------------------

  2,删除。

 

  boolean | delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。

 

  void | deleteOnExit();在程序退出时删除指定文件。

 

 

   演示:

   File f=new File("file.txt");

   f.deleteOnExit();//程序退出时删除指定文件

   sop("create:"+f.createNewFile());//创建文件

   sop("delete:"+f.delete());//删除文件

 

  ------------------------------------------------

  3,判断。

 

  boolean | exists():文件是否存在.

 

  boolean | isFile():判断是否是文件

 

  boolean | isDirectory():是否是一个目录

 

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

 

  boolean | isAbsolute()::测试此抽象路径名是否为绝对路径名。

 

 

   演示:

   File f = new File("d:\\java1223\\day20\\file2.txt");

   sop("dir:"+f.isDirectory());

   sop("file:"+f.isFile());

   sop(f.isAbsolute());

   //记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在。

   //通过exists判断。

 

     -----------------------------------------------

  4,获取信息。

  String | getName():返回由此抽象路径名表示的文件或目录的名称。

 

  String | getPath():将此抽象路径名转换为一个路径名字符串。

 

  String | getParent():返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。如果相对路径中有上一层目录那么该目录就是返回结果。

 

  String | getAbsolutePath():返回此抽象路径名的绝对路径名字符串。

 

  long | lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。

 

  long | length():返回由此抽象路径名表示的文件的长度.

 

 

   演示:

   File f = new File("file.txt");

   sop("path:"+f.getPath());

   sop("abspath:"+f.getAbsolutePath());

   sop("parent:"+f.getParent());//该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。

          //如果相对路径中有上一层目录那么该目录就是返回结果。

 

 

  其他:

  static File[] | listRoots():列出可用的文件系统根。

 

  File[] | listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

 

  String[] | list():返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录

 

   importjava.io.*;

class FileMethod

{

       publicstatic void sop(Object obj)

       {

              System.out.println(obj);

       }

       publicstatic void main(String[] args) throws IOException

       {

 

              //methodCreate();

              //methodDel();

              methodList();

       }

       publicstatic void methodCreate()throws IOException

       {

              Filef = new File("file.txt");

              booleanb = f.createNewFile();

              sop("create:"+ b);

              Filedir = new File("abc");

              Filedir2 = new File("ab.txt");

              b= dir2.mkdir();

              sop("mkdir2:"+ b);

              b= dir.mkdir();

              sop("midir:"+ b);

              Filedirs = new File("abc\\aa\\bb\\cc");

              b= dirs.mkdirs();

              sop("mkdirs:"+ b);

       }

       publicstatic void methodDel()throws IOException

       {

              Filef = new File("file.txt");

              booleanb = f.delete();

              sop("delete:"+ b);

              Filef2 = new File("Demo.txt");

              f2.createNewFile();

              f2.deleteOnExit();//为避免由于在执行后面的程序发生异常,这里如果创建了一个临时文件,需要在程序结束时删除。

       }

 

       publicstatic void methodList()throws IOException

       {

              Filef = new File("D:\\File");

              String[]arr =  f.list(new FilenameFilter(){

                     publicboolean accept(File dir,String name)

                     {

                            returnname.endsWith(".bmp");

                     }

              });

              sop("len:"+ arr.length);

              for(Stringname : arr)

              {

                     sop("bmp文件为:" + name);

              }

       }

}

递归:

对于每次循环都是用同一个功能的函数,即函数自身调用自身,这种表现形式或手法,称为递归。

 

注意:

 

1、限定条件,是作为结束循环用的,否则是死循环

 

2、注意递归的次数,尽量避免内存溢出。因为每次调用自身的时候都会先执行下一次调用自己的发那个发,所以会不断在栈内存中开辟新空间,次数过多,会导致内存溢出。

 

列出指定目录下文件或文件夹,包含子目录,即列出指定目录下所有内容

 

分析,因为目录中还有目录,只有使用同一个列出目录功能的函数完成即可,在列出过程中出现的还是目录的话,还可以再调用本功能,这就是利用递归原理。

 

public class ListFileDemo {

      

       publicstatic void main(String[] args) {

              Filef = new File("d:"+File.separator+"java");

              getFile(f,0);

       }

      

       publicstatic void getFile(File f,int level){

              if(!f.exists())//先判断文件或目录是否存在

                     newIOException("找不到文件");

              if(f.isDirectory()){//判断是不是目录

                     File[]files = f.listFiles();//是就获取目录下的文件

                     for(Filef1 : files){              

                            if(f1.isDirectory()){//在循环目录的过程中判断是否还是目录,是                                                                //的话递归调用本方法

                                   level++;

                                   getFile(f1,level);

                                   }    

                        System.out.println(getLevel(level)+f1);//不是目录就打印

                           

                     }

 

              }

       System.out.println(getLevel(level)+f);//不是目录就打印

             

       }

       //获取层级目录,打印出层次效果

       publicstatic String getLevel(int level){

              StringBuildersb = new StringBuilder();

              sb.append("|--");

               for(int x =0; x<level; x++) 

               {                    

                   sb.insert(0,"|  "); 

               } 

               return sb.toString(); 

       }

 

}

 

用递归删除文件:删除一个带内容的目录。

分析,在window中,删除目录从里面往外删除的。既然是从里往外删除。就需要用到递归。

 

import java.io.*;

class FileBack

{

       publicstatic void main(String[] args)

       {

              Filef = new File("D:\\File\\f");

              removeDirs(f);

       }

       //删除文件夹所有内容

       publicstatic void removeDirs(File f)

       {

              //将文件存入File数组

              File[]files = f.listFiles();

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

              {

                     //如果是文件夹,调用自身

                     if(files[i].isDirectory())

                            removeDirs(files[i]);

                     else

                            System.out.println(files[i].getName()+ ":files:" + files[i].delete());

              }

              System.out.println(f.getName()+ ":-dir-:" + f.delete());

       }

}

将一指定目录中的java文件的绝对路径,存到一个文本文件中,建立一个java文件列表文件

 

思路:

 

1、对指定目录进行递归

 

2、获取递归过程所有的java文件的路径

 

3、将这些路径存储到集合中

 

4、将集合中的数据写到一个文件中

import java.util.*;

import java.io.*;

class WriterToFiles

{

       publicstatic void main(String[] args)

       {

              Filef = new File("D:\\JAVA");

              List<File>list = new ArrayList<File>();

              Filedir = new File(f,"javalist.txt");

              filesToList(f,list);

              writeToFile(list,dir.toString());

 

       }

       //对指定目录进行递归

       publicstatic void filesToList(File f,List<File> list)

       {

              File[]files = f.listFiles();

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

              {

                     //如果是文件夹,再调用自身

                     if(files[i].isDirectory())

                            filesToList(files[i],list);

                     else

                     {

                            //获取递归过程所有的java文件的路径

                            if(files[i].getName().endsWith(".java"))

                                   //将这些路径存储到集合中

                                   list.add(files[i]);

                     }

              }

       }

       //将集合中的数据写到一个文件中

       publicstatic void writeToFile(List<File> list,String javaListFile)

       {

              BufferedWriterbufw = null;

              try

              {

                     bufw= new BufferedWriter(new FileWriter(javaListFile));

                     //遍历集合,获取文件路径,并写入文件中

                     for(Filef : list)

                     {

                            Stringpath = f.getAbsolutePath();

                            bufw.write(path);

                            bufw.newLine();

                            bufw.flush();

                     }

              }

              catch(IOException e)

              {

                     thrownew RuntimeException("文件路径获取失败");

              }

              //最终关闭写入流资源

              finally

              {

                     try

                     {

                            if(bufw!=null)

                            bufw.close();

                     }

                     catch(IOException e)

                     {

                            thrownew RuntimeException("文件路径获取失败");

                     }

              }

       }

}

Properties

Properties是hashtable的子类。

也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。

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

该对象的特点:可以用于键值对形式的配置文件。

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

常用方法:

Object setProperty(String key,Stringvalue):

       调用Hashtable的put方法,设置键值对

String getProperty(String key):

Set<String> stringPropertyNames:

      获取集合中所有的键

void load(InputStream in):

     从输入流中读取属性列表(键和元素对)。

void load(Reader reader):

       按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

          void list(PrintStream out) 

      将属性列表输出到指定的输出流。

 voidlist(PrintWriter out)  

       将属性列表输出到指定的输出流。

Store(OutputStream out,String comments):

Store(Writer writer,String comments)

 

//load方法

       publicstatic void loadMthod()throws IOException

       {

              Propertiespop =new Properties();

              FileInputStreamfis = new FileInputStream("info.txt");

              //将流中的数据加载进集合

              pop.load(fis);

             

              pop.setProperty("zz","25");

              pop.setProperty("ww","24");

              FileOutputStreamfos = new FileOutputStream("info.txt");

              pop.store(fos,"hehe");

              pop.list(System.out);

              fis.close();

              fos.close();

 

       }

 

 

举例:

 

如何将六种的数据存储到集合中?

 

将文本文件中的键值数据存到集合中:

 

1、用一个流和文件关联

 

2、读取一行数据,将改行数据用“=”切割

 

3、将等号左边作为键,右边作为值,存入到Properties集合即可

 

//将流中的数据存储到集合中

       publicstatic void method()throws IOException

       {

              BufferedReaderbufr = null;

              try

              {

                     Propertiespop = new Properties();

                     bufr= new BufferedReader(new FileReader("info.txt"));

                     Stringline = null;

                     while((line=bufr.readLine())!=null)

                     {

                            String[]arr = line.split("=");

                            pop.setProperty(arr[0],arr[1]);

                     }

                     System.out.println(pop);

              }

              catch(IOException e)

              {

                     thrownew RuntimeException("文件操作失败");

              }

              finally

              {

                     try

                     {

                            if(bufr!=null)

                                   bufr.close();

                     }

                     catch(IOException e)

                     {

                            thrownew RuntimeException("关闭流资源操作失败");

                     }

              }           

       }

 

 

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

import java.io.*;

import java.util.*;

class RunCountDemo

{

 public static void main(String[] args)

 {

  count();//调用count方法

 }

 public static void count()

 {

  //给对象初始化属性类

 Properties prop=null;

 File file=null;

 FileInputStream fis=null;

 FileOutputStream fos=null;

  try

  {

 

  prop=new Properties(); //创建Properties属性类对象

  

  file=new File("count.ini");//创建File文件对象

  

  if(!(file.exists()))//对file进行判断是否存在.如果不存在创建一个.

   file.createNewFile();

 

  fis=new FileInputStream(file); //建立字节输入流对象.和文件相关联

  

  prop.load(fis);//将流转换成Properties

 

  int count=0;//计数器

 

  String value=prop.getProperty("timp"); //获取timp的值.

 

  if(value!=null)//判断是否为空

   {

   count=Integer.parseInt(value); //如果不等于空的话将值转换成Integet对象进行操作

   if(count>=5)//如果判断等于>=5程序跳出

    {

    System.out.println("使用次数已经到");

    return ;

    }

   }

  count++;//计数器加加

 

  fos=new FileOutputStream(file);//创建字符输出流.和文件相关联

 

  prop.setProperty("timp",count+"");//设置键值.

 

  prop.store(fos,"haha");//将流流中的数据存储到指定的文件中

 

  }

 catch (IOException e)//异常处理

  {

  throw new RuntimeException("配置文件创建失败"+e.toString());

  }

 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("关闭输出流失败");

   }

 

  }

 }

}

打印流:

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

 

 字节打印流:

 PrintStream

 

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

  1,file对象。File

  2,字符串路径。String

  3,字节输出流。OutputStream

  4,PrintStream(OutputStream out,boolean autoFlush)

 //autoFlush - boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区

 

 字符打印流:

 PrintWriter

 

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

 1,file对象。File

 2,字符串路径。String

 3,字节输出流。OutputStream

 4,字符输出流,Writer。

 5,PrintWriter(OutputStream out,boolean autoFlush)

//autoFlush - boolean 变量;如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区

演示:

import java.io.*;

 

class PrintDemo

{

       publicstatic void main(String[] args) throws IOException

       {

              //键盘录入,创建读取流对象

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

              //使用打印流,将文件输出

              //输出到屏幕

              PrintWriterout = new PrintWriter(new FileWriter("a.txt"),true);

              Stringline = null;

              while((line=bufr.readLine())!=null)

              {

                     if("over".equals(line))

                            break;

                     out.println(line.toUpperCase());

                     //out.flush();

              }

              bufr.close();

              out.close();

       }

}

合并流

SequenceInputStream是能对多个流进行合并成一个读取流,它在构造时需要传入Enumeration,而这个只用Vector中有,所以这个多个读取流要加入Vector集合中。

 注意:它只是对读取流进行合并。

它使用步骤:

1.     创建Vector<InputStream>

2.     将要合并的InputStream加入Vector

3.     通过Vector获取Enumeration

4.     创建SequenceInputStream,将Enumeration作为参数传入。

 

 

import java.io.*;

import java.util.*;

class SequenceDemo

{

 public static void main(String[] args) throwsIOException

 {

 Vector<FileInputStream> v=new Vector<FileInputStream>();//建立枚举

 

 v.add(new FileInputStream("d:\\1.txt"));

 v.add(new FileInputStream("d:\\2.txt"));//添加对象

 v.add(new FileInputStream("d:\\3.txt"));

 

 Enumeration<FileInputStream> en=v.elements();//使用枚举的elements,.返回Enumeration,SequenceInputStream就可以使用了

 

 SequenceInputStream sis=new SequenceInputStream(en);

 

 FileOutputStream fos=new FileOutputStream("d:\\4.txt");//建立字符输出流.和文件相关联

 

 byte[] buf=new byte[1024];//建立字符数组还缓冲

 

  intlen=0;

 while((len=sis.read(buf))!=-1)

  {

  fos.write(buf,0,len);

  }

 fos.close();//关闭流

 sis.close();

 }

}

 

切割流资源:

1、先关联文件FileInputStream

 

2、定义写入流变量:FileOutputStream

 

3、创建数组,并定义切割所需的大小|

 

4、循环读写数据,并每次创建一个新写入流,创建完后并写入文件中

 

5、关闭流资源

 

 

/*

需求:切割一个MP4文件.,并合并

 

 步骤..

  切割:

  1.建立字符输入流和文件相关联

  2.建立输出流.输出的时候分三个文件存储.

 

 合并:

  1.使用枚举的elements.返回Enumeration,因为合并流需要

  2.往枚举里添加字节输入流对象.

  3.建立输出流.和文件路径文件名关联.

  4.输出.

 

*/

import java.io.*;

 

import java.util.*;

class SplitFile

{

 public static void main(String[] args)

 {

 //split()

 merge();

 }

 public static void merge()//合并文件

 {

 FileOutputStream fos=null;//初始化字节输入流对象

 SequenceInputStream sis=null;//初始化字节输入流对象合并流

  try

  {

  Vector<FileInputStream> v=new Vector<FileInputStream>();//建立枚举

  for(int x=0;x<3;x++)

   {

   v.add(new FileInputStream("d:\\"+x+".mp4"));//for循环添加遍历对象.

   }

 

  Enumeration<FileInputStream> en=v.elements();使用枚举的elements,.返回Enumeration,SequenceInputStream就可以使用了

 

  sis=new SequenceInputStream(en);//建立合并流,往合并流中传入

 

  fos=new FileOutputStream("d:\\4.mp4");//建立字符输出流对象.并指定文件

 

  byte[] buf=new byte[1024*1024*10];//建立字符数组10M的

 

  int len=0;

  while((len=sis.read(buf))!=-1)

   {

   fos.write(buf,0,len);//往容器中存数据.

   }

   }

 catch (IOException e)//异常

  {

  throw new RuntimeException("文件合并失败");

  }

 finally

  {

  try

   {

   if(fos!=null)

    fos.close();

   }

  catch (IOException e)

   {

   System.out.println("关闭流资源失败");

   }

  try

   {

   if(sis!=null)

    sis.close();

   }

  catch (IOException e)

   {

   System.out.println("关闭流资源失败");

   }

  }

 //fos.close();

 //sis.close();

 

 }

 

 

 

 

 public static void split()//切割

 {

 FileInputStream fis=null;//初始化对象

 FileOutputStream fos=null;

  try

 {  

  fis=new FileInputStream("d:\\VID_20130414_181841.mp4");//字符输入流指定文件

  byte[] buf=new byte[1024*1024*10];

 

  int len=0;

  int count=0;//定义变量来当名字

 

  while((len=fis.read(buf))!=-1)

   {

   fos=new FileOutputStream("d:\\"+(count++)+".mp4");//指定路径和文件名字

   fos.write(buf,0,len);//开始输出.

   fos.close();

   }

  }

 catch (IOException e)

  {

  throw new RuntimeException("文件切割失败");

  }

 finally

  {

  try

   {

   if(fis!=null)

    fis.close();

   }

  catch (IOException e)

   {

   System.out.println("关闭流资源失败");

   }

  }

 

 

 }

}

 

 

对象序列化

数据可以封装成对象,对象运行时是在堆内存中的,如果对象的数据需要存储在硬盘上,那么就要用到对象的序列化流。对象序列化(也叫对象的可串行性)其实就是对象持久化,把内存中的对象,变成硬盘上的文件内容。IO中供对象序列化的流对象为ObjectInputStream和ObjectOutputStream。

注意:

1.   用ObjectOutputStream写入的的文件,只能用ObjectInputStream来重构读取。

2.   被序列化的对象必须实现Serializable接口。

3.   对象的静态成员和被transient关键字修饰的成员不能被序列化。(当对象在堆内存的私有对象不希望被序列化时,可以使用transient关键字)。

此外,序列化的文件一般以.ojbect作为类型后缀名,一个文件中可以存放多个不同类型的序列化对象。

Serializable接口

在对对象进行序列化时,必须实行Serializable接口,否则使用ObjectOutputStream写入时,会出现NotSerializableException异常。

Serializable接口并没必须要实现的方法,类定义时仅标示一下实现即可。实现Serializable的类,都有serialVersionUID,如果你没有在类中显式定义一个serialVersionUID,那么编译器会根据该类中的成员生成一个具有唯一性的serialVersionUID。

显式定义serialVersionUID的好处:如果你在对类对象进行了序列化之后,又修改了这个类,那么再次读取修改前序列化的对象时,编译器可以识别;如果没有显式定义,你修改后的类经过编译器编译后会生成一个新的serialVersionUID,这个serialVersionUID跟修改前类的serialVersionUID不同,当你再次读取时,编译器会报出InvalidClassException异常。所以,如果类对象需要序列化,建议显式定义serialVersionUID。

 

import java.io.*;

//创建Person类,实现序列化

class Person implements Serializable{

       //定义自身的序列化方式

       publicstatic final long serialVersionUID = 42L;

       //定义私有属性

       privateString name;

       privateint age;

       transientString id;

       staticString country = "cn";

       //构造Person类

       Person(Stringname,int age,String id,String country){

              this.name= name;

              this.age= age;

              this.id= id;

              this.country= country;

       }

       //覆写toString方法

       publicString toString(){

              returnname+ ":" + age + ":" + id + ":" + country;

       }

}

//对象序列化测试

class ObjectStreamDemo{

       publicstatic void main(String[] args){

              //对象写入流

              writeObj();

              //对象读取流

              readObj();

       }

       //定义对象读取流

       publicstatic void readObj(){

              ObjectInputStreamois = null;

              try{

                     //创建对象读取流

                     ois= new ObjectInputStream(new FileInputStream("obj.txt"));

                     //通过读取文件数据,返回对象

                     Personp = (Person)ois.readObject();

                     System.out.println(p);

              }catch(Exception e){

                     thrownew RuntimeException("写入文件失败");

              }

              //最终关闭流对象

              finally{

                     try{

                            if(ois!=null)

                                   ois.close();

                            }catch(IOException e){

                            thrownew RuntimeException("写入流关闭失败");

                     }

              }

       }

       //定义对象写入流

       publicstatic void writeObj(){

              ObjectOutputStreamoos = null;

              try{

                     //创建对象写入流

                     oos= new ObjectOutputStream(new FileOutputStream("obj.txt"));

                     //写入对象数据

                     oos.writeObject(newPerson("lisi",25,"01","cn"));                   

              }catch(Exception e){

                     thrownew RuntimeException("写入文件失败");

              }

              //关闭流资源

              finally{

                     try{

                            if(oos!=null)

                                   oos.close();

                            }catch(IOException e){

                            thrownew RuntimeException("写入流关闭失败");

                     }

              }

       }

}

 

 

 

管道流

管道流分为字节管道流(PipedInputStream和PipedOutputStream)和字符管道流(PipedReader和PipedWriter):它是IO技术和多线程技术的结合。在一条线程上写入的数据可以在另外一条线程上读取,它们是一对对配合使用的。如果在一条线程上使用管道读取和写入流会发生死锁的情况。

其使用步骤:

1.   分别定义写入和读取的Runnable接口子类,把相应的管道流作为构造参数传入给定义的私有管道流成员。

2.   将配对的管道流通过connect()方法连接起来。

3.   启动线程

 

import java.io.*;

 

class Read implements Runnable//多线程

{

 private PipedInputStream in;//将PipedInputStream私有

 Read(PipedInputStream in)

 {

 this.in = in;//初始化

 }

 public void run()//覆盖run方法

 {

  try

  {

  byte[] buf = new byte[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 PipedOutputStream out;

 Write(PipedOutputStream out)

 {

 this.out = out;

 }

 public void run()

 {

  try

  {

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

  Thread.sleep(6000);//等待6秒

  out.write("piped lai la".getBytes());//将字符串转成字节数组

  out.close();

  }

 catch (Exception e)

  {

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

  }

 }

}

 

class PipedStreamDemo

{

 public static void main(String[] args) throwsIOException

 {

 

 PipedInputStream in = new PipedInputStream();//管道流

 PipedOutputStream out = new PipedOutputStream();

 in.connect(out);//两个流连接上

 

 Read r = new Read(in);//传入in

 Write w = new Write(out);

  newThread(r).start();//开启线程

  newThread(w).start();

 }

}

RandomAccessFile 类

一、概述:

 

1、RandomAccessFile称之为随机访问文件的类,自身具备读写方法。

 

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

 

3、可以完成读写的原理:内部封装了字节输入流

 

4、构造函数:RandomAccessFile(File file,String mode),可已从它的构造函数中看出,该类只能操作文件(也有字符串),而且操作文件还有模式。

 

模式传入值:”r“:以只读方式打开;”rw“:打开以便读写

 

如果模式为只读,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常,如果模式为rw,且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖,也可通过seek方法修改。

 

二、特有方法:

 

1、seek(int n):设置指针,可以将指针设置到前面或后面

 

2、skipBytes(int n):跳过指定字节数,不可往前跳

 

三、使用步骤:

 

1、创建RandomAccessFile对象

 

2、将数据写入到指定文件中

 

3、读取数据,读入到指定文件中

 

注意:尧都区后面的数据,需要调用数组指针,通过改变角标位置,取出相应的数据

 

a.调整对象的指针:seek()

 

b.跳过指定字节数

 

 

import java.io.*; 

class RandomAccessFileDemo  

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

   { 

       //writeFile_2(); 

       //writeFile(); 

       //readFile(); 

       RandomAccessFile raf = newRandomAccessFile("raf1.txt","rw"); 

       raf.write("hha".getBytes()); 

 

   } 

   //读取,模式设置为“r” 

   public static void readFile() throws IOException 

   { 

       RandomAccessFile raf = newRandomAccessFile("raf.txt","r"); 

       //调整对象中的指针,seek前后都能设置,所以比skipBytes使用范围广。 

       //raf.seek(8*0);//里边存入的数据都是8个字节为一组,如果没有规律,读取就困难了 

         

        //跳过指定的字节数,只能往后走,不能往回走。 

       raf.skipBytes(8); 

 

       byte [] buf = new byte[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 = newRandomAccessFile("raf.txt","rw"); 

       raf.seek(8*0);//修改数据,网络分段下载原理,要重点掌握。 

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

       raf.writeInt(103);       

       raf.close(); 

   } 

   //写入,模式设置为“rw” 

   public static void writeFile() throws IOException 

   { 

       RandomAccessFile raf = newRandomAccessFile("raf.txt","rw"); 

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

//     raf.write(97);write(int x)方法只写入低8位。如果写入的数字在byte取值范围内,那么可以read()正常读取,如果超出,读取时就会出现数据错乱。 

       raf.writeInt(97);//要把四个字节都写入,所以用writeInt 

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

       raf.writeInt(99); 

       raf.close(); 

   } 

 

 

 

 

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

一、概述:

 

1、操作基本数据类型的流对象:DataInputStream和DataOutputStream

 

2、这两个读写对象,可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法

 

二、特有方法:

 

                          写                            读

 

int型                 writeInt(intn)                   int readInt()

 

boolean型      writeBoolean(booleanb)         boolean readBoolean()

 

double型        writeDouble(doubled)            double readDouble()

 

 

操作数组和字符串

一、操作字节数组的对象:ByteArrayInputStream和ByteArrayOutputStream

 

1、这个对象并没有调用底层资源,所以不用关闭流资源

 

2、存入的是缓冲区,并未用到键盘和硬盘灯,所以不需要抛任何IO异常

 

3、对象中封装了数组

 

4、构造函数:

 

1)ByteArrayInputStream:在构造函数的时候,需要接受数据源,而且数据源是一个字节数据。

 

2)ByteArrayOutputStream:在构造函数的时候,不用定义数据目的,因为该对象中已经在内部封装了可变长度的字节数组,这就是数据的目的地

 

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

 

6、其实就是用流的思想操作数组

 

7、特有方法:writeTo(OutputStream out) 这个方法用到了字节输出流,有异常存在,需要抛IO异常

 

 

二、对应的字符数组和字符串:

 

字符数组流对象:CharArrayReader和CharArrayWriter

 

字符串流对象:   StringReader和StringWriter

 

 

示例:

 

import java.io.*;

class ArrayStreamDemo

{

       publicstatic void main(String[] args)

       {

              //数据源

              ByteArrayInputStreambais = new ByteArrayInputStream("ABCDEFF".getBytes());

              //数据目的

              ByteArrayOutputStreambaos = new ByteArrayOutputStream();

              intby = 0;

              //读取和写入数据

              while((by=bais.read())!=-1)

              {

                     baos.write(by);

              }

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

 

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

             

              try

              {

                     //方法,此处抛异常,所以上面需要抛出去

                     baos.writeTo(newFileOutputStream("a.txt"));

              }

              catch(IOException e)

              {

                     thrownew RuntimeException("写入文件失败");

              }

             

       }

}

 

 

编码的练习及总结:

 

一、概述:

 

1、字符流的出现为了方便操作字符,更重要的是加入了编码的转换,即转换流。

 

2、通过子类进行转换

 

3、在两个对象进行构造时,可加入编码表

 

4、可传入编码表的有:

 

1)转换流:InuputStreamReader和OutputStreamWriter

 

2)打印流:PrintStream和PrintWriter,只有输出流

 

5、常见的编码表:

 

1)ASCII:美国标准信息交换码表。用一个字节的7位表示

 

2)IOS8859-1:拉丁码表;欧洲码表。用一个字节的8位表示

 

3)GB2312:中国的中文编码表

 

4)GBK:中国的中文编码表升级,融合了更多的中文文字字符。打头的是两个高位为1的两个字节编码。为负数

 

5)Unicode:国际标准码,融合了多种文字

 

6)UTF-8:最多用三个字节表示一个字符的编码表,包括:一位、两位、三位表示的字符

 

     UTF-8有自己的字节码:

 

一个字节:0开头

 

两个字节:字节一  ---> 110     位数:10 ~ 6

 

                    字节二 --->  10      位数:5 ~ 0

 

三个字节:字节一  ---> 110     位数:15 ~ 12

 

                    字节二  --->  10     位数:11 ~ 6

 

                    字节三 --->  10      位数:5 ~ 0

 

二、编码和解码:

 

四、特别注意:

 

对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,可以找到对应的符号,但不再是”联通“了。

“联通”编码问题的原因:

        //boBinaryString(int)它接受的是int,byte类型的b参与运算时会类型提升为int,我们需要的是提升后的低8位,所以&255

            

            对联通的结果进行GBK编码时,其二进制码为:

           11000001

           10101010

           11001101

           10101000 

            编码的结果符合UTF-8的格式,所以再次打开记事本时,它会把它按照UTF-8的格式进行解码,结果就是两个乱码。

 

 

import java.util.*;

 

class EncodeDemo

{

       publicstatic void main(String[] args) throws Exception{

              CodeDemo();

              //编译成功,解码失败后的解决方式

              CodeBack();

       }

       publicstatic void CodeDemo()throws Exception{

              Strings = "你好";

              byte[]b1 = s.getBytes();

              Strings1 = new String(b1);

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

 

              byte[]b2 = s.getBytes("GBK");//默认编码

              Strings2 = new String(b2);

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

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

 

              byte[]b3 = s.getBytes("UTF-8");//国际编码

              Strings3 = new String(b3);

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

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

 

              byte[]b4 = s.getBytes("ISO8859-1");//欧洲编码

              Strings4 = new String(b4);

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

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

       }

       //编码与解码

       publicstatic void CodeBack()throws Exception{

              String s = "你好";

              System.out.println("原数据:" + s);

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

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

              Strings1 = new String(b1,"ISO8859-1");

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

             

 

              System.out.println("----对s1进行ISO8859-1编码-----");

              //对s1进行ISO8859-1编码

              byte[]b2 = s1.getBytes("ISO8859-1");//欧洲编码

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

             

              Strings2 = new String(b2,"GBK");

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

       }

 

}

 

 

 

 

/*

有5个学生,每个学生有三门课的成绩。

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

输入的格式:如zhangsan,30,40,60计算出总成绩。

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

 

1.描述学生对象。

2.定义一个学生对象的工具类

 

思想:

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

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

    所以可以使用TreeSet。

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

 

*/ 

import java.io.*; 

import java.util.*; 

//使用TreeSet需要将其中的元素实现Comparable接口 

class Student implementsComparable<Student> 

   private String name; 

   private int ma,cn,en; 

   private int sum; 

   Student(String name,int ma,int cn,int en) 

   { 

       this.name = name; 

       this.ma = ma; 

       this.cn = cn; 

       this.en = en; 

       sum =ma+cn+en; 

 

   } 

   //Comparable接口要实现compareTo方法。 

   public int compareTo(Student s ) 

   { 

       //注意,一般自然信息定义的都是升序,即成绩从低到高的顺序 

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

       if(sum==0) 

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

       return num; 

   } 

   public String getName() 

   { 

       return name; 

   } 

   public int getSum() 

    { 

       return sum; 

   } 

   //学生类也有可能存入HashSet中,所以要复写hashCode和equals方法。 

   public int hashCode() 

   { 

       return name.hashCode()+sum*78; 

   } 

   public boolean equals (Object obj) 

   { 

       if(!(obj instanceof Student)) 

           throw new ClassCastException("类型不匹配"); 

       Student s = (Student)obj; 

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

   } 

   //复写toString方法,提供学生类特有的字符串表现形式。 

   public String toString() 

   { 

       return "Student["+name+","+ma+","+cn+","+en+"]"; 

   } 

//定义学生信息录入和存储工具类 

class StudentInfoTool 

   //函数重载,提供一个默认的方法,对学生对象按照定义的自然顺序进行排序 

   public static Set<Student> getStudents()  throws IOException 

   { 

       return getStudents(null); 

    } 

     

   //定义录入工具,并将键盘录入的结果存入Set集合中,因为要排序,所以要用TreeSet。 

   //这里加入比较器作为参数,是为了让集合可以按照不同的要求进行排序,比如按照某一单科成绩或总分从高到底 

   public static Set<Student> getStudents(Comparator<Student>cmp)  throws IOException 

   { 

       //定义缓冲区,包装键盘录入流对象 

       BufferedReader bufr =  

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

       String line =null; 

       //定义要集合,用于存储录入的学生信息。 

       Set  <Student>stus =null; 

       if(cmp==null) 

           stus = new TreeSet<Student>(); 

       else 

           stus = new TreeSet<Student>(cmp); 

       //也可以用三元运算符进行优化 

//     Set<Student>stus=(cmp==null)?(new TreeSet<Student>()):(newTreeSet<Student>(cmp)); 

         

//     循环读取录入的信息,注意定义结束标记。 

       while((line =bufr.readLine())!=null) 

       { 

           if("over".equals(line)) 

                break; 

           //用","进行切割---其实这里可以将录入信息line用正则表达式过滤一下,对于非法的信息不写入,并进行提示,防止录入非法的数据。 

             

           String [] info = line.split(","); 

           Student stu =new Student(info[0],Integer.parseInt(info[1]), 

                       Integer.parseInt(info[2]), Integer.parseInt(info[3])); 

           stus.add(stu); 

       } 

       //关闭流资源 

       bufr.close(); 

       return stus; 

   } 

   //将学生信息存入磁盘文件中,也可以将要写入的文件已参数形式传入 

   public static void write2File(Set<Student> stus) throwsIOException 

   { 

       BufferedWriter bufw = new BufferedWriter(newFileWriter("stuinfo.txt")); 

       for(Student stu: stus) 

       { 

           bufw.write(stu.toString()+"\t"); 

           //这里写入的数据是int类型的值,并且write会截取其低8位,所以要把它转成字符串,否则会出现乱码 

           bufw.write(stu.getSum()+""); 

           bufw.newLine();//写入跨平台的换行符 

           bufw.flush();//字符缓冲区一定要记得刷新动作 

       } 

       //关闭资源。 

        bufw.close(); 

   } 

 

class StudentInfoTest 

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

   { 

       //通过Collections集合工具类的反转命名方法,获得一个逆序比较器 

       Comparator<Student> cmp = Collections.reverseOrder(); 

        //如果没有传入逆序比较器,学生会按照自然顺,即总成绩从低到高的排序,这与我们的现实生活习惯不符合。 

       Set <Student> stus = StudentInfoTool.getStudents(cmp); 

       //将集合中的学生信息写入文件。 

       StudentInfoTool.write2File(stus); 

 

   } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值