``Day18
06~概述
读  就是输入流  读入到流中
写  就是输出流   写出去
IO(Input Output)流
IO 流用来处理设备之间的数据传输;Java对数据的操作是通过流的方式;Java用于操作流的对象都在IO包中。
方向:输入  输出
单位:字节  字符
功能:节点  处理流
 
字符流:
FileReader  BufferedReader
FileWriter  BufferedWriter
字节流:
FileInputStream      BufferedInputStream
FileOutputStream     BufferedOutputStream
 
字符流由来:字符流的对象里面融合了编码表
通用字节流,字符流基于字节流(文字用字符流,图片用字节流)
 
IO流常用基类
字节流的抽象基类:InputStream  OutputStream
字符流的抽象基类:Reader    Writer
注意:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀
如:InputStream的子类FileInputStream
的子类FileReader
 
07-IO流(FileWriter)
public class FileWriterDemo 
{
       public static void main(String[]args)  throws IOException
       {
              //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件
              //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖
              //其实该步骤就是在明确数据要存放的目的地
              FileWriterfw = new FileWriter("demo.txt");
              
              //调用write方法,将字符串写入到流中
              fw.write("abcd");
              
              //刷新流对象中的缓冲中的数据,将数据刷到目的地中。fw.flush();
              //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据
              //和flush区别:flush刷新后,流可以继续使用;close刷新后会关闭流。
              fw.close();
              fw.write("haha");
       }
 
}
 
08-IO流(IO异常处理方式)
import java.io.*;
public class FileWriterDemo2 
{
       public static void main(String[]args) 
       {
              FileWriterfw = null;
              //在创建流对象和使用流对象的方法时,都可能产生IOException异常
              try
              {
                     fw=new FileWriter("demo.txt");
                     fw.write("adada");
              }
              catch(IOException e)
              {
                     System.out.println("catch:"+e.toString());
              }
              finally   //不管产不产生异常都要关闭流,释放内存资源
              {
                     try
                     {
                            if(fw!=null)
                                   fw.close();
                     }
                     catch(IOException e)
                     {
                            System.out.println(e.toString());
                     }
              }
       }
}
 
09-IO流(文件的续写)
import java.io.*;
//演示对已有文件的数据续写
public class FileWriterDemo3
{
       public static void main(String[]args)  throws IOException
       {
              //当传入参数true后,代表不覆盖已有文件,并在一条有文件末尾处进行数据续写
              FileWriterfw = new FileWriter("demo.txt", true);
              
              fw.write("sad\r\ntyjhs\\otyj");   // \r\n换行,\\转义,输出单个\
              fw.close();       
       }
}
 
10-IO流(文本文件读取方式一)
import java.io.*;
//文本文件读取
public class FileReaderDemo 
{
       public static void main(String[]args)  throws IOException 
       {
              //创建一个文件读取流对象,和指定名称的文件相关联
              //要保证该文件是已经存在的,如果不存在,会发生FileNotFoundException
              FileReaderfr = new FileReader("demo.txt");
              //方式一:read():一次读取一个字符,返回的是读到的字符的值,而且会自动往下读
              int ch = 0;
              while((ch =fr.read())!=-1)
              {
                     System.out.print((char)ch);
              }
       }
}
11-IO流(文本文件读取方式二)
计算机存储信息的最小单位是位(bit,比特);
存储器中所包含的存储单元的数量称为存储容量,其计量基本单位是字节(Byte。简称B);
8个二进制位称为一个字节(8bit=1B),此外还有KB,MB,GB,TB等,它们的关系是1024倍。
 
 
              //方式二:read(charp[])返回的是读到的字符个数
              //定义一个字符串数组,用于存储读到的字符,大小2KB
              char[] buf = new char[1024];  
              int num = 0;
//注意:num是每次fr流读取到的字符串长度。当一次buf装满时,就全部输出
//接着继续读,到最后只读取到几个字符而没有将数组装满时,输出的是数组中从0 开始到num结束
              while((num=fr.read(buf))!=-1)
              {
                     System.out.println(newString(buf,0,num));
              }
              fr.close();
两种方法的区别是:第一种read()读取单个字符,读一个打印一下;
第二种read(char[] cbuf)将字符串读入数组,读完打印,好点
注:将字符串读入数组时,如果数组长度小于字符串,下次读取时会接着上一次读取的后面,只是会换行,看起来不舒服,返回的int数据不是数组长度,而是此次读取字符串的长度
 
13-IO流(拷贝文本文件)
要求:将e盘下的文件数据存储到d盘的一个文件中
步骤:
1 在d盘下创建一个文件,用于存储c盘文件中的数据
2 定义读取流和c盘文件相关联
3 通过不断的读写完成数据的存储
4 关闭资源
 
第一种方式:读一个写一个字符
public static void copy_1() throws IOException
       {
              //创建目的地
              FileWriterfw = new FileWriter("D:\\RuntimeDemo_Copy.txt");
              //与已有文件相关联
              FileReaderfr = new FileReader("E:\\JAVA\\入学考试\\day19_IO\\src\\CopyDemo.java");
              int ch = 0;
              while((ch =fr.read())!=-1)
              {
                     fw.write(ch);
              }
              fw.close();
              fr.close();
       }
 
 
第二种方式:先读,存在数组中,然后全部写、关流时记得分开关
       //现将读取到的字符存入数组,然后全部写入。关闭流时记得分关
       public static void copy_2() 
       {
                     FileWriterfw = null;
                     FileReaderfr = null;
                     try
                     {
                             fw = new FileWriter("D:\\RuntimeDemo_Copy.txt");
                             fr = new FileReader("E:\\JAVA\\入学考试\\day19_IO\\src\\CopyDemo.java");
                             char[] buf = new char[1024];
                             int len = 0;
                             while((len =fr.read(buf))!=-1)
                             {
                                   System.out.println(len);
                                    fw.write(buf,0,len);
                             }
                     }
                     catch(IOException e)
                     {
                            throw new RuntimeException("读写失败");
                     }
                     finally
                     {
                            if(fr!=null)
                                   try{fr.close(); } catch(IOException e){}
                            if(fw!=null)
                                   try{fw.close(); } catch(IOException e){}
                     }
       }
day19
01-IO流(BufferedWriter)
缓冲区的出现是为了提高流的操作效率,所以在创建缓冲区之前,必须先有流对象。
缓冲区中提供了一个跨平台的换行符newLine();
import java.io.*;
public class BufferedWriterDemo
{
       public static void main(String[]args)  throws IOException
       {
              //创建一个字符写入流对象
              FileWriterfw = new FileWriter("buf.txt");
              //为了提高字符写入流效率,加入了缓冲技术
              //只要将需要缓冲的流对象作为参数传递给缓冲区的构造函数即可
              BufferedWriterbufw = new BufferedWriter(fw);
              for(int x=0;x<5;x++)
              {
                     bufw.write("abcd"+x);
                      //跨平台的换行符,windows版本中jdk封装的是\r\n,linx中封装\n
                     bufw.newLine();  
                     bufw.flush();    //只要用到缓冲区就要记得刷新
              }
              bufw.close();//其实关闭缓冲区就是在关闭缓冲区中的流对象
       }
}
 
02-IO流(BufferedReader)
将缓冲指定文件的输入,如果没有缓冲,则每次调用read()或readLing()都会导致从文件中读取字节,并将其转换为字符后返回,而这是及其低效的
字符读取流缓冲区:
该缓冲区提供了一次读一行的方法readLine(),方便对文本数据的获取,当返回null时,表示读到文件末尾;该方法返回回车符之前的数据类容,并不返回回车符
import java.io.*;
public class BufferedReaderDemo
{
       public static void main(String[]args) throws IOException
       {
              //创建一个读取流对象和文件相关联
              FileReaderfr = new FileReader("buf.txt");
              //为了提高效率,加入缓冲技术;将字符读取流对象作为参数传递给缓冲对象的构造方法
              BufferedReaderbufr = new BufferedReader(fr);
              Stringline = null;
              while((line=bufr.readLine())!=null)
              {
                     System.out.println(line);
              }
              bufr.close();
       }
}
 
03-IO流(通过缓冲区复制文本文件)
public class BuffereCopyDemo 
{
       public static void main(String[]args)  throws IOException
       {
              BufferedReaderbufr =null;
              BufferedWriterbufw = null;
              try
              {
                     bufr= new BufferedReader(new FileReader("E:\\JAVA\\入学考试\\day19_IO流\\src\\BuffereCopyDemo.java"));
                     bufw= new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
                     Stringline = null;
                     while((line=bufr.readLine())!=null)
                     {
                            bufw.write(line);
                            bufw.newLine();
                            bufw.flush();
                     }
              }
              catch(IOException e){throw new IOException("读写失败");}
              finally
              {
                     try
                     {
                            if(bufr!=null)
                                   bufr.close();
                     }
                     catch(IOException e){throw new IOException("读取关闭失败");}
                     try
                     {
                            if(bufw!=null)
                                   bufw.close();
                     }
                     catch(IOException e){throw new IOException("写入关闭失败");}
              }
       }
}
 
 
04-IO流(readLine的原理)
readLine()方法的原理:无论是读一行还是读多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read方法一次读一个。内部封装数组,当读到\r\n时将数组变成String返回
 
05-IO流(MyBufferedReader)
明白了BufferedReader类中的特有方法readLine的原理后,可以自定义一个类中包含一个和readLine功能一致的方法来模拟一下BufferedReader
//自定义BufferdReader
class MyBufferedReader extends Reader
{
       private FileReader r;
       MyBufferedReader(FileReaderr)
       {
              this.r = r;
       }
       //可以一次读一行数据的方法
       public StringmyReaderLine() throws IOException
       {
              //定义一个临时容器,原BufferedReader封装的是字符数组
              //为了掩饰方便,定义一个StringBuilder容器,因为最终还是要将数据变成字符串
              StringBuildersb = new StringBuilder();
              int ch = 0;
              while((ch=r.read())!=-1)
              {
                     if(ch=='\r')
                            continue;
                     if(ch=='\n')
                            return sb.toString();
                     else
                            sb.append((char)ch);
              }
              if(sb.length()!=0)
                     returnsb.toString();  //如果最后一行没有换行,数据已经读到sb里面,要返回它
              return null;     //当读到末尾时返回空
       }
       //覆盖Reader类中的抽象方法
       public void close() throws IOException
       {
              r.close();
       }
 
       public int read(char[] arg0, int off, int len) throws IOException 
       {
              return r.read(arg0, off,len);
       }
}
 
06-IO流(装饰设计模式)
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供加强功能;那么自定义的该类称为装饰类。装饰类通常会通过构造方法接收被装饰的对象
class Person   //被装饰类
{
       public void chifan()
       {
              System.out.println("吃饭");
       }
}
class SuperPerson   //装饰类
{
       private Person p;
       SuperPerson(Personp)
       {
              this.p = p;
       }
       public void superChifan()
       {
              System.out.println("开胃酒");
              p.chifan();
              System.out.println("甜点");
              System.out.println("来一根");
       }
}
 
07-IO流(装饰和继承的区别)
继承体系:   臃肿,扩展性差
MyReader    //专门用于读取数据的类
    |——MyTextReader
缓冲类
    |——MyMediaReader
缓冲类
    |——MyDataReader
缓冲类
 
装饰优化后体系:
MyReader    //专门用于读取数据的类
    |——MyTextReader
    |——MyMediaReader
    |——MyDataReader
缓冲类
 
  classMyBufferedReader
{
    MyBufferedReader(MyTextReadertext){}
 
    MyBufferedReader(MyMediaReadermedia){}
}
上面这个类扩展性很差,找到其参数共同类型,通过多态可以提高扩展性
classMyBufferedReader
{
    MyBufferedReader(MyReaderr)
{}
}
装饰类特点:
1 装饰模式比继承要灵活,避免了继承体系的臃肿。而且降低了类与类之间的关系。
2 装饰类因为增强已有对象,具备的功能和已有的是相同的(复制被装饰类的方法),只不过提供了更强的功能,所以装饰类和被装饰的类通常是属于一个体系中的
 
09-IO流(LineNumberReader)也是一个包装类
import java.io.*;
public classLineNumberReaderDemo 
{
       public static void main(String[]args)  throws IOException
       {
              FileReaderfr = new FileReader("buf.txt");
              LineNumberReaderlnr = new LineNumberReader(fr);
              Stringline = null;
              lnr.setLineNumber(100);   //设置行号从100开始,打印时101开始
              while((line =lnr.readLine())!=null)
              {
                     System.out.println(lnr.getLineNumber()+"::"+line); //打印行号和内容
              }
              lnr.close();
       }
}
、
10-IO流(MyineNumberReader)
class MyLineNumberReaderextends MyBufferedReader
{ 
       private int lineNumber;      //私有属性,行号,默认0
       MyLineNumberReader(Readerr)
       {
              super(r);
       }
       public StringmyReadLine() throws IOException
       {
              lineNumber++;  //读取一行数据时,行号自增
              return super.myReaderLine();
       }
       public void setLineNumber(int lineNumber)     //设置行号
       {
              this.lineNumber = lineNumber;
       }
       public intgetLineNumber()  //获取行号
       {
              return lineNumber;
       }
}
 
*****************************************************************************************************
11-IO流(字节流File读写操作)
字符流:FileReader    FileWriter
        BufferedReader   BufferedWriter
字节流:InputStream   OutputStream
需求:想要操作图片数据,这时就要用到字节流
 
       //读(输入流)一次读一个字节
       public static void readFile()  throws IOException
       {
              FileInputStreamfis = new FileInputStream("fos.txt");
              int ch = 0 ;
              while((ch=fis.read())!=-1)
              {
                     System.out.print((char)ch);
              }
       }
       //读(输入流)一次读多个字节,放进字符数组
       public static void readFile_2()  throws IOException
       {
              FileInputStreamfis = new FileInputStream("fos.txt");
              byte[] buf = new byte[1024];   //1kb
              int len=0;
              while((len=fis.read(buf))!=-1)
              {
                     System.out.print(newString(buf,0,len));
              }
              fis.close();
       }
字节流类有一个特殊方法,available()返回要读的文件中 字节数(文件大小)
数据不是很大时用,如果读一个电影,就会内存溢出(数组存在内存中)
       //字节输入流(读)特有的方法
       public static void readFile_3()  throws IOException
       {
              FileInputStreamfis = new FileInputStream("fos.txt");
              byte[] buf = new byte[fis.available()];   //定义一个刚刚好的缓冲区,不用再循环
              fis.read(buf);
              System.out.println(new String(buf));
              fis.close();
       }
12-IO流(拷贝图片)
字符流也可以处理媒体文件,但有可能看不了,乱码 
复制一个图片:
思路:
1 用字节读取流对象和图片关联
2 用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3 通过循环读写,完成数据的存储
4 关闭资源
import java.io.*;
public class CopyPic 
{
       public static void main(String[]args)  throws IOException
       {
              FileInputStreamfis = null;
              FileOutputStreamfos = null;
              try
              {
                     fos= new FileOutputStream("e:\\2.jpg");     //写入流(输出流)
                     fis= new FileInputStream("e:\\1.jpg");     //读取流(输出流)
                     byte[] buf = new byte[1024];
                     int len = 0;
                     while((len =fis.read(buf))!=-1)
                     {
                            fos.write(buf,0,len);
                     }
              }
              catch(IOException e)
              {
                     throw new IOException("复制图片失败");
              }
              finally
              {
                     try
                     {
                            if(fis!=null)
                                   fis.close();
                     }
                     catch(IOException e)
                     {
                            throw new IOException("读取关闭失败");
                     }
                     try
                     {
                            if(fos!=null)
                                   fos.close();
                     }
                     catch(IOException e)
                     {
                            throw new IOException("写入关闭失败");
                     }
              }
       }
}
 
 
13-IO流(字节流的缓冲区)
需求:演示MP3的复制,通过缓冲区 BufferedInputStream  BufferedOutputStream
 
       //通过字节流的缓冲区完成复制
       public static void copy_1() throws IOException
       {
              //字节缓冲输入流,读取需要复制的文件
              BufferedInputStreambufis = new BufferedInputStream(new FileInputStream("e:\\范玮琪 - 那些花儿.mp3"));
          //字节缓冲输出流,存储需要复制的文件
              BufferedOutputStreambufos = new BufferedOutputStream(new FileOutputStream("e:\\2.mp3"));
              int by = 0;
              while((by=bufis.read())!=-1)
              {
                     bufos.write(by);
              }
              bufis.close();
              bufos.close();
       }
14-IO流(自定义字节流的缓冲区-read和write的特点)
11111111——>提升成int类型,但结果还是-1,因为前面都是补的1.只要前面补上0,既可以保留元字节数据不变,又可以避免-1的出现。
classMyBufferedInputStream
{
       private InputStream in;
       private byte[] buf= new byte[1024];   //定义缓冲区,字节数组
       private int pos = 0,count = 0;     //指针和计数器
       MyBufferedInputStream(InputStreamin)
       {
              this.in = in;
       }
       //一次读一个字节,从缓冲区字节数组获取
       public int myRead() throws IOException
       {
              //通过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,避免-1发生,write方法写时只取最后8位
              }
              else if(count>0)
              {
                     //取数据
                     byte b = buf[pos];
                     count--;
                     pos++;
                     return b&0xff;   //255的十六进制形式
              }
              return -1;
       }
       public void  myClose() throws IOException
       {
              in.close();
       }
} 
 
15-IO流(读取键盘录入)
读取键盘录入:
System.out :对应的是标准输出设备,控制台
System.in :对应标准的输入设备:键盘
需求:通过键盘录入数据,当录入一行数据后,就将该行数据进行打印;如果录入的数据是over,那么停止录入
import java.io.*;
public class ReadIn 
{
       public static void main(String[]args)  throws IOException
       {
              InputStreamin = System.in;
              StringBuildersb = new StringBuilder();
              while(true)
              {
                     int ch = in.read();
                     if(ch=='\r')
                            continue;
                     if(ch=='\n')
                     {
                            Strings = sb.toString();
                            if("over".equals(s))
                                   break;
                            System.out.println(s.toUpperCase());
                            sb.delete(0,sb.length());   //清空字符串缓冲对象的内容
                     }
                     else
                            sb.append((char)ch);
              }
       }
 
16-IO流(读取转换流)InputStreamReader  字节流通向字符流的桥梁
java的IO流分两种流 
字节流 InputStream OutputStream 
字符流 Reader Writer 
他们都是抽象类 
具体实现 
字节流 FileInputStream FileOutputStream 
字符流 FileReader FileWriter  字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点.
所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列.
字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。字节流转换成字符流可以用 InputSteamReaderOutputStreamWriter 
 
键盘输入的是字符,
通过刚才的键盘录入一行数据并打印其大写,发现就是读一行数据的原理。也就是readLine方法。能不能直接使用readLine来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法是字节流ImputStream的方法。能不能将字节流转成字符流再使用字符缓冲区的readLine方法?
 
import java.io.*;
public class TransStreamDemo 
{
       public static void main(String[]args)  throws IOException
       {
              //获取键盘录入流对象
              InputStreamin = System.in;
              //将字节流对象转换成字符流对象,使用转换流InputStreamReader
              InputStreamReaderisr = new InputStreamReader(in);
              //为了提高效率,将字符串进行缓冲区技术搞笑操作。使用BufferedReader
              BufferedReaderbufr = new BufferedReader(isr);
              
              String  line = null;
              while((line=bufr.readLine())!=null)
              {
                     if("over".equals(line))
                            break;
                     System.out.println(line.toUpperCase());
              }
              bufr.close();
       }
}
 
17-IO流(写入转换流) OutputStreamWriter字符流通向字节流的桥梁
System.out是标准输出流(字节流),输出到控制台(屏幕上),转换为字符流
转换为BufferReader可用newline方法
 
//键盘录入常见写法
              BufferedReaderbufr = 
                            new BufferedReader(newInputStreamReader(System.in));
              BufferedWriterbufw = 
                            new BufferedWriter(newOutputStreamWriter(System.out));
       
              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();
 
18-IO流(流操作规律-1)
当具体使用哪一个流对象时,用三个明确来完成
1 明确源和目的
源:输入流,InputStream     Reader
目的:输出流:OutputStream   Writer
2 操作的数据是否是纯文本   是:字符流   ,不是:字节流
3 当体系明确后,在明确要使用哪个具体的对象,通过设备来进行区分
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
 
示例: 将一个文本文件中数据存储到另一个文本文件中,复制文件
源:1因为是源,所以使用读取流。InputStream   Reader
是不是操作文本文件。  是,这时就可明确选择Reader(字符流);体系明确
接下来明确使用该体系中那个对象?
明确设备:硬盘  上一个文件
体系中可以操作文件的对象是FileReader
是否需要提高效率:是   加入Reader体系中缓冲区BufferedReader 
     FileReader fr = new FileReader(“a.txt”);
     BufferedReader bufr = newBufferedReader(fr);
   
目的:1OutputStream   Writer
是否是纯文本。  是  Writer
设备:硬盘   一个文件
体系中可以操作文件的对象FileWriter
是否需要提高效率: 是  加入Writer体系中的缓冲区BufferedWriter 
        FileWriter fw = new  FileWriter(“b.txt”);
        BufferedWriter  bufw = new BufferedWriter(fw);
 
 
19-IO流(流操作规律-2)
其实转换流的由来是转码
比如要读取一个txt文件,默认是GBK码表,这时可以读取,因为他使用的是默认的GBK码表;但是如果一个txt文件采用的是UTF-8编码时,FileReader就不可以读了。这时要用InputStreamReader(,”UTF-8”)并给他传一个编码方式,这样就可以读了。所以FileReader是他的子类。InputStreamReader更通用,用FileReader把码表封装好了更方便。
 
20-IO流(改变标准输入输出设备)
              //改变标准输入流
              System.setIn(new FileInputStream("PersonDemo.java"));
              //改变标准输出流、
              System.setOut(new PrintStream("zz.txt"));
 
21-IO流(异常的日志信息)
其实网络上有一个工具(log4j)专门用来建立日志信息
import java.util.*;
import java.io.*;
import java.text.*;
public class ExceptionInfo 
{
       public static void main(String[]args) 
       {
              try
              {
                     int[] arr = new int[2];
                     System.out.println(arr[3]);
              }
              catch(Exception e)
              {
                     try
                     {
                            //格式化时间
                            Dated = new Date();
                            SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
                            Strings = sdf.format(d);
                            
                            PrintStreamps = new PrintStream("exception.log");
                         ps.println(s);
                            System.setOut(ps);
                     }
                     catch(IOException ex)
                     {
                            throw new RuntimeException("日志文件创建失败");
                     }
                     e.printStackTrace(System.out);
              }
       }
}
 
day19-22-IO流(系统信息)
import java.util.*;
import java.io.*;
public class SystemInfo 
{
       public static void main(String[]args)  throws IOException
       {
              //获取系统属性信息,Properties是Map集合的子类
              Propertiesprop = System.getProperties();   
              //System.out.println(prop);     不换行,很乱
              // list将属性列表输出到指定的输出流。
              prop.list(new PrintStream("sysinfo.txt"));
       }
}
 
********************************************************File,Properties,Sequence*********************************************
day20
01-IO流(File概述)、   FileDemo
File类
用来对文件或者文件夹封装成对象;
方便对文件与文件夹的属性信息进行操作;
对象可以作为参数传递给流的构造函数;
了解File类中的常用方法。
 
//将a.txt封装成fie对象,可以将已有的和未出现的文件或者文件夹封装成对象
              Filef1 = new File("a.txt");    //封装相对路径
              
              Filef2 = new File("e:\\abc","b.txt") ;  //绝对路径。父目录,子目录
              Filed= new File("e:\\abc");
              Filef3 = new File(d,"c.txt");
              
              //封装什么就打印什么
              System.out.println("f1 :"+f1);   //f1 :a.txt
              System.out.println("f2 :"+f2);    //f2 :e:\abc\b.txt
              System.out.println("f3 :"+f3);    //f3 :e:\abc\c.txt
              //跨平台的分隔符(File类属性)
              File f4= new File("e:"+File.separator+"abc"+File.separator+"b.txt") ;
 
02-IO流(File对象功能-创建和删除、判断、获取)
File类常见方法:
1、创建
文件::::   
注意:使用构造方法只是将一个文件封装成对象,并不会在硬盘中创建文件
boolean createNewFile();
在指定位置创建文件,如果该文件已存在,则不创建,返回false。
和输出流不一样,输出流对象一建立就创建文件,而且文件已经存在,会覆盖
 
文件夹::::
boolean mkdir()    创建文件夹(一级)
boolean mkdirs()    创建多级文件夹
 
 
2、删除
boolean delete();     f.delete(); 删除失败返回false
void deleteOnExit(); 当虚拟机正在运行时,可能有一些流正在操作想要删除的文件,那样就删不掉,所以提供此方法,当虚拟机终止时,请求删除此抽象路径名表示的文件或目录
 
3、判断
    
boolean
canExecute() 
测试应用程序是否可以执行此抽象路径名表示的文件。boolean
canRead() 
测试应用程序是否可以读取此抽象路径名表示的文件。boolean
canWrite() 
测试应用程序是否可以修改此抽象路径名表示的文件。int
compareTo(File pathname) 
按字母顺序比较两个抽象路径名。boolean  exists();  文件是否存在
boolean  isDirectory();    判断此抽象路径名表示的文件是否是一个目录
boolean  isFile();       判断文件对象是否是一个标准文件
注意:在判断文件对象是否是文件或者目录时,必须要首先判断该文件对象封装的内容是否存在。通过exists判断。只有当此内容存在且是文件或者目录时返回true
判断此文件是否是一个隐藏文件
判断此抽象路径名是否为绝对路径名,即使文件不存在也可判断
 
 
 
4、获取信息
getName();
getPath();          获取路径,封装什么就获取什么
getParent();        获取此抽象路径名父目录的路径名字符串,如果此路径名没有指定父目录,则返回null
getAbsolutePath();    返回此抽象路径名的绝对路径名字符串
getAbsoluteFile()     返回此抽象路径名的绝对路径名形式。是File对象
lastModified();      返回此抽象路径名标示的文件最后一次被修改时间
length();            返回次抽象路径名表示的文件的长度(内容)
 
5、操作
BooleanrenameTo(File  dest)    重命名此抽象路径名表示的文件。成功true
如果需要被重命名的文件不存在,返回false
 
05-IO流(File对象功能-文件列表) FileDemo2
listRoots();  列出可用的文件系统根
              //列出机器上所有盘符
              File[]files = File.listRoots();
              for(File f : files)
              {
                     System.out.println(f);
              }
 
list();   返回一个字符串数组,这些字符串是此抽象路径名表示的目录中的子目录和文件。。调用list方法的File对象必须是封装了一个目录而且该目录必须存在,不存在会发生空指针异常。如果此抽象路径名不表示一个目录,那么此方法将返回 null
File f =new File("c:\\");
               // 列出抽象路径名表示的文件下的所有文件,包含隐藏文件
              String[]names = f.list();  
              for(String name :names)
              {
                     System.out.println(name);
              }
 
 
 
 
06-IO流(File对象功能-文件列表2)
        String[]  list (FilenameFilter filter)返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
//列出指定路径下的符合要求的文件
       public static void listDemo_1()
       {
              Filedir =new File("E:\\JAVA\\入学考试");
              //带参数的list,过滤符合要求的文件。
              //通过过滤类的方法判断文件是否符合要求
              String[]arr = dir.list(new FilenameFilter()
              {
                     public boolean accept(File dir,String name) 
                     {
效果跟list一样  
                            //当文件名后缀为.jpg的时候,返回true,符合要求
                            return name.endsWith(".jpg");
                     }             
              });  
              for(String name : arr)
              {
                     System.out.println(name);
              }
       }
 
 File[] listFiles()      返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
       public static void listDemo_2()
       {
              Filedir =new File("c:\\");
              //返回此抽象路径名表示的目录下的所有文件的抽象路径名数组
              File[]files = dir.listFiles();  
              for(File f : files)
              {
                     System.out.println(f);    //c:\Program Files
                     System.out.println(f.getName()+":"+f.length());  //Program Files:20480
              }
       }
 
 
07-IO流(列出目录下所有内容-递归) FileDemo3
需求:定目录下文件及文件夹,包含子目录中的内容;也就是列出指定目录下所有内容
分析:因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。也就是函数自身调用自身。这种表现形式,或编程手法称为递归
 
//列出指定目录下所有的内容,包含子目录的内容
       public static void showDir(File dir)
       {
               //返回抽象目录下所有目录及文件的抽象路径名数组
              File[]files = dir.listFiles();   
              for(int x=0;x<files.length;x++)
              {
                     if(files[x].isDirectory())    //判断此抽象路径名表示的文件是否是一个目录
                            showDir(files[x]);      //是一个目录就递归调用本方法
                     else
                            System.out.println(files[x]);
              }
       }
 
 
注意:1 限定条件,要有结束判断,不然一直递归
注意递归次数,递归调用会导致栈内存中不断开辟空间,导致内存溢出
       //递归运算n的累加
       public static int getSum(int n)
       {
              if(n==1)
                     return 1;
              return n+getSum(n-1);   //5+4+3+2+1
       }
 
       //递归  转换二进制
       public  static void toBin(int num)
       {
              if(num>0)
              {
                     toBin(num/2);
                     System.out.println(num%2);  //最后输出
              }
       }
 
08-IO流(列出目录下所有内容-带层次)
       //根据目录深度划分层次
       public static String getLevel(int level)
       {
              StringBuildersb = new StringBuilder();
              sb.append("|--");
              for(intx=0;x<level;x++)
              {
                     sb.insert(0,"      ");  //从0角标开始插入空格
              }
              return sb.toString();
       }
       
       //递归列出指定目录下所有的内容,包含子目录的内容
       public static void showDir(File dir,int level)
       {
              System.out.println(getLevel(level)+dir.getName());
              
              level++;    //每次递归调用,深度+1
               //返回抽象目录下所有目录及文件的抽象路径名数组
              File[]files = dir.listFiles();   
              for(int x=0;x<files.length;x++)
              {
                     if(files[x].isDirectory())    //判断此抽象路径名表示的文件是否是一个目录
                            showDir(files[x],level);      //是一个目录就递归调用本方法
                     else
                            System.out.println(getLevel(level)+files[x]);
              }
       }
 
09-IO流(删除带内容的目录) RemoveDir
删除一个带内容的目录
删除原理:在windows中,删除目录是从里面往外删除的
public static void removeDir(Filedir)
       {
              File[]files = dir.listFiles();
              for(int x =0;x<files.length;x++)
              {
                     if(files[x].isDirectory())
                            removeDir(files[x]);
                     else
                            System.out.println(files[x].toString()+":"+files[x].delete());
              }
              System.out.println(dir+":dir:"+dir.delete());
       }
 
10-IO流(创建java文件列表) JavaFileList
练习:将一个指定目录下的java文件的绝对路径存储到一个文本文件中,建立一个java文件列表文件
思路:
1、对指定的目录进行递归;
2、获取递归过程所有的java文件的路径;
3、将这些路径存储到集合中;
4、将集合中的数据写入到一个文件中。
import java.io.*;
import java.util.*;
/*
将一个指定目录下的java文件的绝对路径存储到一个文本文件中,建立一个java文件列表文件
 */
public class JavaFileList 
{
       public static void main(String[]args)  throws IOException
       {
              Filedir = new File("E:\\JAVA\\入学考试\\day20_IO");
              List<File>list = new ArrayList<File>();
              fileToList(dir,list);
              //System.out.println(list.size());
              Filefile = new File(dir,"javaList.txt");   //封装路径为对象,但不一定存在
               //也可以直接传File对象,FileWriter有构造方法可直接接受File对象
              writeToFile(list,file.toString());    
       }
       
       //将指定目录下的所有java文件放入List集合中
       public static void fileToList(Filedir, List<File> list)
       {
              File[]files = dir.listFiles();  //获取此抽象路径名下的所有抽象路径名数组
              
              for(File file :files)    //遍历数组
              {
                     if(file.isDirectory())   //当此子路径为目录时,递归
                            fileToList(file,list);
                     else
                     {    //不是目录时判断,如果是java文件,加入list中
                            if(file.getName().endsWith(".java"))
                                   list.add(file);
                     }
              }
       }
       
       //将list集合中的文件对象名写入到文件中
       public static voidwriteToFile(List<File> list, String javaListFile) throws IOException
       {
              BufferedWriterbufw  = null;
              try
              {
                     bufw  = new BufferedWriter(new  FileWriter(javaListFile));
                     for(File f : list)
                     {
                            Stringpath = f.getAbsolutePath();  //获取文件绝对路径
                            bufw.write(path);     //将此路径写入到流中
                            bufw.newLine();    //换行
                            bufw.flush();        //刷新流,让流中数据写入到文本
                     }
              }
              catch(IOException e)
              {
                     //捕获到异常,但是处理不了,抛出去;
                     //也可抛RuntimeException,让程序停下来
                     throw e;     
              }
              finally
              {
                     try
                     {
                            if(bufw!=null)
                                   bufw.close();
                     }
                     catch(IOException e)
                     {
                            throw e;
                     }
              }
       }
 
}
 
11-IO流(Properties简述)
1、Properties是Hashtable的子类;也就是说它具备Map集合的特点,而且里面存储的键值对都是字符串。
2、是集合和IO技术相结合的集合容器。
3、该对象特点:可以用于键值对形式的配置文件
 
12-IO流(Properties存取) PropertiesDemo
Object   setProperty(String key, String value)     调用 Hashtable 的方法 put。
Set<String>stringPropertyNames()  返回此属性列表中的键集
String getProperty(String key)    用指定的键在此属性列表中搜索属性。
       //设置和获取元素
       public static void setAndGet()
       {
              Propertiesprop = new Properties();  //创建一个属性集对象
              
              prop.setProperty("zhangsan", "30");   //设置(添加)属性
              prop.setProperty("lisi", "39");
              
              //System.out.println(prop);    //{zhangsan=30, lisi=39}
              Stringvalue = prop.getProperty("lisi");
              //System.out.println(value);     //39
              
              Set<String>names = prop.stringPropertyNames();
              for(String s : names)
              {
                     System.out.println(s+":"+prop.getProperty(s));
              }
       }
 
13-IO流(Properties存取配置文件) PropertiesDemo
演示:如何将流中的数据存储到集合中?
想要将info.txt中的数据存储到集合中进行操作
思路:1、用一个流和info.txt文件相关联;
、读取一行数据,将该行数据用“=”进行切割;
、等号左边作为键,右边作为值,存入到Properties集合中即可。
 
public static void method_1() throws IOException
       {
              BufferedReaderbufr = new BufferedReader(new FileReader("info.txt"));
              Stringline = null;
              Propertiesprop = new Properties();    //创建属性集对象
              while((line=bufr.readLine())!=null)
              {
                     String[]arr = line.split("=");    //用=切割,左边是键右边是值
                     prop.setProperty(arr[0],arr[1]);
              }
              bufr.close();
              System.out.println(prop);
       }
******Properties中封装了方法,这样操作更简单
void load(InputStream inStream)从输入流中读取属性列表(键和元素对)。
void list(PrintStream out)    将属性列表输出到指定的输出流。
void store(OutputStreamout, String comments)将此 Properties 表中的属性列表(键和元素对)写入输出流。
*********************************
       public static void loadDemo() throws IOException
       {
              Propertiesprop = new Properties();
              FileInputStreamfis = new FileInputStream("info.txt");
              
              prop.load(fis);       //将流中的数据加载进集合
              prop.setProperty("wangwu", "60");    //新增一个键值对
              
              FileOutputStreamfos = new FileOutputStream("info.txt");
              //将属性集合写入fos流所对文件,haha为注释信息
              prop.store(fos,"haha");    
              prop.list(System.out);   //将属性列表输出到指定的输出流。
              
              fos.close();
              fis.close();
       }
 
14-IO流(Properties练习)、
练习:用于记录应用程序运行次数;如果使用次数已到,那么给出注册提示
 
分析:用计数器。可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。可是随着改程序的退出,该计数器也在内存中消失;消磁启动程序,又重新从0记数。
需求:程序即使结束,该计数器的值也存在,下次程序启动会先加载该计数器的值并加1后再重新存储起来。
所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式,这样便于阅读和操作数据。键值对数据是map集合,数据是以文件形式存储,使用io技术。Map+io——>properties
配置文件可以实现应用程序数据的共享,通常有两种(properties  xml)
public class RunCount 
{
       public static void main(String[]args) throws IOException 
       {
              Propertiesprop = new Properties();      //属性集对象
              
              Filefile = new File("count.ini");         //将要操作的文件封装成对象
              if(!file.exists())
                     file.createNewFile();
              
              FileInputStreamfis = new FileInputStream(file);     //读取流
              
              prop.load(fis);     //将流中的属性列表读入属性集中
              
              int count = 0;    //计数器
              Stringvalue = prop.getProperty("time");    //第一次time不存在时返回null
              if(value!=null)
              {
                     count= Integer.parseInt(value);   // 将字符串参数作为有符号的十进制整数进行解析
                     if(count>=5)     //使用次数已到
                     {
                            System.out.println("您好,使用次数已到,请购买!");
                            return;           //退出程序
                     }
              }
              count++;     //使用一次+一次
              
              prop.setProperty("time", count+"");     //设置属性集
              
              FileOutputStreamfos = new FileOutputStream(file);
              prop.store(fos,"");  //将属性列表写入输出流
              
              fos.close();
              fis.close();
       }
}
 
15-IO流(PrintWriter)
IO包中的其他流:
1、打印流  可直接操作输入流和文件
(字符输出流) 与 PrintStream (字节输出流)
 
、序列流  对多个流进行合并
      SequenceInputStream
 
、操作对象  操作的对象需要实现Serializable(标记接口) io包中
与ObjectOutputStream
 
打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印出
 
字节打印流:PrintStream
构造函数可以接收的参数类型:
1、           file对象。File
2、           字符串路径。String
3、           字节输出流。OutputStream
     
字符打印流:PrintWriter
构造函数可以接收的参数类型:
1、           file对象。File
2、           字符串路径。String
3、           字节输出流。OutputStream
4、           字符输出流。Writer
 
import java.io.*;
public class PrintStreamDemo 
{
       public static void main(String[]args)  throws IOException
       {
              //键盘录入
              BufferedReaderbufr =
                            new BufferedReader(newInputStreamReader(System.in));
              //打印在控制台上
              //PrintStream out= System.out;
              PrintWriterout = new PrintWriter(System.out,true);   //构造方法传true可自动刷新
              //PrintWriterout1= 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();
              }
              out.close();
              bufr.close();
       }
}
 
16-IO流(合并流)
SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。 
import java.io.*;
import java.util.*;
 
public class SequenceInputStreamDemo
{
       public static void main(String[]args)  throws IOException
       {
              //Vector集合中有枚举,将流对象封装进集合
              Vector<FileInputStream>v = new Vector<FileInputStream>();
              
              v.add(new FileInputStream("a.txt"));
              v.add(new FileInputStream("info.txt"));
              v.add(new FileInputStream("javaList.txt"));
              
              Enumeration<FileInputStream>en = v.elements();
              //合并流,输入流,传入参数为字节输入流对象
              SequenceInputStreamsis = new SequenceInputStream(en);
              //字节输出流
              FileOutputStreamfos = new FileOutputStream("HeBing.txt");
              byte[] buf = new byte[1024];
              int len = 0;
              while((len =sis.read(buf))!=-1)
              {
                     fos.write(buf,0,len);
              }
              sis.close();
              fos.close();
       }
}
 
17-IO流(切割文件)
有合并(SequenceInputStream)就有切割,一个输入流,对多个输出流
将一个mp3文件切割成1MB的几份,分别放入零散的文件:
public static void splitFile() throws IOException
       {
              FileInputStreamfis = new FileInputStream("范玮琪 - 那些花儿.mp3");
              FileOutputStreamfos = null;
              
              byte[] buf = new  byte[1024*1024];    //1MB
              int len = 0;
              int count =1;
              while((len=fis.read(buf))!=-1)
              {   //每次循环会在splitFiles中创建一个文件,写入1M的数据
                     fos= new FileOutputStream("E:\\JAVA\\入学考试\\day20_IO\\splitFiles\\"+(count++)+".part");
                     fos.write(buf,0, len);
                     fos.close();
              }
              fis.close();
       }
 
 
将切割后的零散文件合并成一个文件,并将这个文件存入到新的mp3文件中:
       public static void merge() throws IOException
       {
              //获取源(串联起来的)
              ArrayList<FileInputStream>al = new ArrayList<FileInputStream>();
              for(int x=1;x<=5;x++)
              {    //循环将碎片文件用读取流关联并加到list集合
                     al.add(new FileInputStream("splitFiles\\"+x+".part"));
              }
              finalIterator<FileInputStream> it = al.iterator();
              
              Enumeration<FileInputStream>en = new Enumeration<FileInputStream>()
        {
                     //new一个枚举接口子类对象,并实现里面的方法。
                     //匿名内部类只能访问final修饰的外部内成员,迭代器用final修饰
                     public boolean hasMoreElements() 
                     {
                            return it.hasNext();
                     }
                     public FileInputStreamnextElement() 
                     {
                            return it.next();
                     }
              };
              SequenceInputStreamsis = new SequenceInputStream(en);
              //输出流,,写入文件
              FileOutputStreamfos = new FileOutputStream("splitFiles\\整合音乐.mp3");
              byte[] buf = new byte[1024];   //1KB
              int len = 0;
              while((len=sis.read(buf))!=-1)
              {
                     fos.write(buf,0,len);
              }
              sis.close();
              fos.close();
       }
 
day21
01-IO流(对象的序列化)
序列化:将堆中的对象序列化,存储到硬盘上
反序列化:将硬盘上文件中存储的对象读取出来(根据那个对象所对应的类文件);当类文件发生改变,改变前系列化的对象就不能被反序列化。因为类实现了
Serializable,生成了对应的UID序列。为了避免,可以在类中自己生成UID。
注意:类中的静态成员不能被序列化,因为静态成员存在于方法区中
如果非静态的成员不想被序列化,可加上transient关键字修饰
不能被序列化:保证属性值在堆内存中存在,而不再文本文件中存在
import java.io.*;
/**
操作对象  操作的对象需要实现Serializable(标记接口) 被
与ObjectOutputStream
可直接读取和写入对象
*/
public class ObjectStreamDemo 
{
       public static void main(String[]args)  throws Exception
       {
              writeObj();
              readObj();
       }
       //将自定义类的对象写入到硬盘上的文件中(对象的序列化,持久化)
       public static void writeObj() throws IOException 
       {
              ObjectOutputStreamoos = 
                            newObjectOutputStream(new FileOutputStream("obj.txt"));
              oos.writeObject(new Person("lisi",39));    //age不能被序列化
              oos.close();
       }
       
       //将硬盘上的文件中的对象读取出来(对象反序列化)
       public static void readObj() throws Exception
       {
              ObjectInputStreamois = 
                            new ObjectInputStream(new FileInputStream("obj.txt"));
              Personp = (Person)ois.readObject();    //抛出异常ClassNotFoundException
              
              System.out.println(p);    //lisi::0
              ois.close();
       }
       
}
 
class Person implements Serializable   //给类定义标记
{
       //为了让这个类改变后,都能反序列化本类对象,
       //不让虚拟机给本类生成UID,本类自己定义UID
       public static final long serialVersionUID = 42L;
 
       private String name;       //自己生成UID时可以改变修饰符(类文件)
       transient private int age;   //transient关键字修饰后不能被序列化
       static String country = "cn";    //静态成员不能序列化,因为存在于方法区中
       Person(Stringname, int age)
       {
              this.name = name;
              this.age = age;
       }
       public String toString()
       {
              return this.name+"::"+this.age; 
       }
}
 
02-IO流(管道流)
IO包中其他类
RandomAccessFile:随机访问文件,自身具备读写的方法;
通过skipBytes(intx),seek(int x)来达到随机访问。
管道流:PipedInputStream和PipedOutputStream
输入和输出可以直接进行连接,通过结合线程使用。
其他流联系是通过数组,读取流把读到的数据存入数组中,写入流再把数组中的数据写入文件。
 
PipedInputStream管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。
PipedOutputStream可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。
不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。(因为read方法是阻塞式方法,当没读到数据时,就会等待,如果是一个线程,就会死在那里。两个线程同时操作,一个线程等待后,另一个线程可以运行)
 
通俗理解:一般的流是输出(写入)流将数据写入文件,输入(读取)流关联这个文件,然后读取文件中数据。而管道流直接通过其特有方法,将两个流连接,这样读取流直接读取写入流写入的数据,不用通过文件这个中转站。
 
import java.io.*;
//读取,读入写入流写的数据
class Read implements Runnable
{
       private PipedInputStream in;
       Read(PipedInputStreamin)
       {
              this.in = in;
       }
       public void run()
       {
              try
              {
                     byte[] buf = new byte[1024];
                     System.out.println("读取前。。。没有数据阻塞");
                     int len = in.read(buf);
                     System.out.println("读到数据。。。阻塞结束");
                     
                     Strings = 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(PipedOutputStreamout)
       {
              this.out = out;
       }
       public void run()
       {
              try
              {
                     System.out.println("写入数据,请等待6秒");
                     Thread.sleep(6000);
                     
                     out.write("piped laile".getBytes());
                     out.close();
              }
              catch(Exception e)
              {
                     throw new RuntimeException("管道输出流失败");
              }
       }
}
 
public class PipedStreamDemo 
{
       public static void main(String[] args)  throws IOException
       {
              PipedInputStreamin = new PipedInputStream();
              PipedOutputStreamout = new PipedOutputStream();
              in.connect(out);  //读取流连接写入流   ,两个流中都有connect方法
              
              Readr = new Read(in);
              Writew = new Write(out);
              new Thread(w).start();
              new Thread(r).start();
       }
}
 
03-IO流(RandomAccessFile)   应用(多线程下载)
所谓随机就是可以通过改变文件指针任意读取文件中数据(数据最好有规律)
1、该类不算是IO体系中子类,而是直接继承自Object
2、但是它是IO包中成员,因为它具备读和写功能。内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获取文件指针位置,同时可以通过               seek改变指针的位置。从构造函数看出该类只能操作文件数据。
3、其实完成读写的原理就是内部封装了字节输入流和输出流;
4、而且操作文件还有模式:只读r  读写rw等。。
如果模式为只读,不会创建文件,会去读取一个已存在的文件,当文件不存在时出现异常。。如果模式为rw,操作的文件不存在,会自动创建,存在时则不会覆盖
import java.io.*;
public classRandomAccessFileDemo 
{
       public static void main(String[]args)  throws IOException
       {
              writeFile();
              readFile();
       }
       //读文件
       public static void readFile() throws IOException
       {
              RandomAccessFile  raf = new RandomAccessFile("ran.txt","r"); //可读
              //调整对象中文件指针,从脚标8处开始读
              //raf.seek(8*1);  
              //跳过指定的字节数,但是不可往回跳
              raf.skipBytes(8);
              byte[] buf = new byte[4];   //一次读4个字节
              raf.read(buf);              //读取数据到数组中
              Stringname =  new String(buf);
              int age =raf.readInt();     //读取四个字节的一个int型整数
              System.out.println("name="+name+"   "+"age="+age); //name=wangwu   age=75
              
              raf.close();
       }
       //写文件
       public static void writeFile() throws IOException
       {
              //创建对象,rw的意思是此对象可读可写,并关联一个文件
              RandomAccessFile  raf = new RandomAccessFile("ran.txt","rw");
              //往文件中写数据
              raf.write("李四".getBytes());
              raf.writeInt(97);   // 按四个字节将 int 写入该文件
              raf.write("王五".getBytes());
              raf.writeInt(99);   
              
              raf.seek(8*3);    //指针移到第四个位置开始写
              raf.write("麻子".getBytes());
              raf.writeInt(33);   
              raf.close();   //关闭流对象
       }
}
 
04-IO流(操作基本数据类型的流对象DataStream)
DataInputStream与DataOutputStream:
可以用于操作基本数据类型的数据的流对象;将基本数据类型与流相结合,所以初始化时要有流
import java.io.*;
public class DataStreamDemo 
{
       public static void main(String[]args)  throws IOException
       {
              //writeData();
              //readData();
              writeUTFDemo();
              readUTFDemo();
              
              //用utf-8编码方式写入数据;还可用gbk(默认)
              OutputStreamWriterosw =
 newOutputStreamWriter(newFileOutputStream("UTF.txt"),"utf-8");
              osw.write("你好");
              osw.close();
       }
       
       //用UTF-8修改版存入的数据只能用对应的读取流的readUTF方法读取
       public static void readUTFDemo() throws IOException
       {
       //如果用此方法读取utf-8,或出现异常,因为utf-8中两个汉字占6个字节,utf-8修改版占8个字节
              DataInputStreamdis = new DataInputStream(new FileInputStream("UTFData.txt"));
              System.out.println(dis.readUTF());
              dis.close();
       }
       
       //特有方法: 以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。
       public static void writeUTFDemo() throws IOException
       {
              DataOutputStreamdos = 
new DataOutputStream(new FileOutputStream("UTFData.txt"));
              dos.writeUTF("你好"); //按照UTF-8 修改版将数据写入文件
              dos.close();
       }
       
       //读取流
       public static void readData() throws IOException
       {
              DataInputStreamdis = new DataInputStream(new FileInputStream("data.txt"));
              
              int num =dis.readInt();
              boolean b =dis.readBoolean();
              double d =dis.readDouble();
           System.out.println("num="+num+";b="+b+";d="+d);
              dis.close();
       }
       
       //写入流
       public static void writeData() throws IOException
       {
              DataOutputStreamdos = new DataOutputStream(new FileOutputStream("data.txt"));
       
              dos.writeInt(234);   //写入int数据,四个字节
              dos.writeBoolean(true);
              dos.writeDouble(9887.543);   //一共13个字节
              dos.close();
       }
}
 
05-IO流(操作字节数组的流对象ByteArrayStream)
操作基本数据类型:DataInputStream与DataOutputStream:
操作字节数组:ByteArrayInputStream与ByteArrayOutputStream
操作字符数组:CharArrayReader与CharArrayWriter
操作字符串:StringReader与StringWriter
 
1、ByteArrayInputStream:在构造的时候,需要接收数据源。数据源是个字节数组;
2、ByteArrayOutputStream:在构造的时候,不用定义数据目的地,因为该对象内部封装了可变长度的字节数组,这就是数据目的地。
3、这两个流对象操作的都是数组,并没有使用系统资源,所以不用进行close()关闭,关闭了也可以使用。
4、这两个类中只有一个方法会抛异常 writeTo(OutputStream out)
将byte数组输出流的全部内容写入到指定输出流参数中(文件)
其实和out.write(buf,0,len)效果一样
import java.io.*;
/**
操作字节数组:ByteArrayInputStream与ByteArrayOutputStream
 */
public class ByteArrayStream 
{
       public static void main(String[]args)  throws IOException
       {
              //数据源
              ByteArrayInputStreambis = new ByteArrayInputStream("ABCDEFG".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());
              
              bos.writeTo(new FileOutputStream("byte.txt"));  //将数组中数据写到指定输出流的文件中
       }
}