黑马程序员_IO流(1)

------- android培训java培训、期待与您交流! ----------


IO流常用基类:

       (1)字节流

              输出字节流:OutputStream:字节写入流抽象类

                            |--->FileOutputStream:字节写入流

                            |--->BufferedOutputStream:字节写入流缓冲区

                            |--->PrintStream:打印流

 

              输入字节流:InputStream:字节读取流抽象类

                            |--->FileInputStream:字节读取流

                            |--->BufferedInputStream:字节读取流缓冲区

       (2)字符流     

              输出字符流:Writer:字符写入流的抽象

                            |--->FileWriter:字符写入流

                            |--->BufferedWriter:字符写入流缓冲区

                            |--->OutputStreamWriter:字符通向字节的转换流(涉及键盘录入时用)

                            |--->OutputStreamWriter:   打印流,可处理各种类型的数据

 

              输入字符流:Reader: 字符读取流的抽象类

                            |--->FileReader:字符读取流

                                   |--->LineNumberReader:跟踪行号的缓冲字符读取流

                            |--->BufferedReader:字符读取流缓冲区

                            |--->InputStreamReader:字节通向字符的转换流(涉及键盘录入时用)

 

IO流其他类:

序列流:

              SequenceInputStream:对多个流进行合并

转换流:

              InputStreamReader:将字符输入流转换成字节输入流

              OutputStreamReader:将字符输出流转换成字节输出流

常见的编码表:

            **ASCII:美国标准信息交换码,用一个字节的七位表示

            **ISO8859-1:拉丁码表,欧洲码表,用一个字节的八位表示

            **GB2312:中文编码表,用两个字节表示

            **GBK:中文编码表升级,融合录入更多的中文字符,用两个字节表示,为避免和老美重复两字节的最高位都是1,即汉字都是用负数表示

            **Unicode:国际标准码,融合了多种文字,所有文字都用两个字节表示

            **UTF-8:用一个字节到三个字节表示。

            注:Unicode能识别中文,UTF-8也能识别中文,但两种编码表示一个汉字所用的字节数不同

            Unicode用两个字节,UTF-8用三个字节,故涉及到编码转换。

            在流中涉及编码表的转换只有转换流

代码示例:

        publicstatic void write() throws IOException

        {

            OutputStreamWriterosw1 = new OutputStreamWriter(newFileOutputStream("gbk.txt"),"GBK");

            osw1.write("你好");

            osw1.close();

 

            OutputStreamWriterosw2 = new OutputStreamWriter(newFileOutputStream("utf-8.txt"),"UTF-8");

            osw2.write("你好");

            osw2.close();

        }

        publicstatic void read() throws IOException

        {

            InputStreamReaderisr = new InputStreamReader(newFileInputStream("gbk.txt"),"GBK");

            byte[]buf = new byte[1024];

            intlen = isr.read(buf);

            sop(newString(buf,0,len));

        }

        编码解码

        编码:字符串变成字节数组:String-->getBytes()-->byte[]()

        解码:字节数组变成字符串:byte[]-->new String(byte[],0,len)-->String

 

 

管道流:

        PipedInputStream

        PipedOutputStream

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

操作字节数组流:

        ByteArrayInputStream

        ByteArrayOutputStream

随机访问文件:RandomAccess(重要!!!)

        **自身具备读写方法(很牛逼!又可以读又可以写)

        **通过skipByte(intx)和seek(int x)来达到随机访问文件

        **该类不是IO体系子类,而是直接继承Object,但它是IO包中的成员,因为它具备读写方法

        **该类内部封装了数组,而且通过指针对数组的元素进行操作,可以通过getFilePoint获取指针位置,同时可以通过seek改变指针位置

        **该类完成读写的原理是内部封装了字节输入输出流

        **构造方法:

        RandomAccessFile(Filefile, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

        RandomAccessFile(Stringname, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

**通过该类的构造看出,该类只能操作文件,而且操作的文件只能有固定模式:

            "r":只读."rw":读写"rws":"red":

        **方法摘要:

        void write(byte[]b) 将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。

voidwrite(byte[] b, int off, int len) 将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。

        voidwrite(int b) 向此文件写入指定的字节。

        intread() 从此文件中读取一个数据字节。

        intread(byte[] b) 将最多 b.length 个数据字节从此文件读入 byte 数组。

        int read(byte[]b, int off, int len) 将最多 len 个数据字节从此文件读入 byte 数组。

        StringreadLine() 从此文件读取文本的下一行。

        longgetFilePointer() 返回此文件中的当前偏移量。

        longlength() 返回此文件的长度。

        voidseek(long pos) 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。

 

Properties:是IO流合集合相结合的集合容器

(1)Properties是HashTable的子类,具备Map集合的特点,里面存储的是键值对

(2)Properties的特点是可以用于存储键值对形式的配置文件

(3)构造方法:

    Properties()

        创建一个无默认值的空属性列表。

    Properties(Propertiesdefaults)

        创建一个带有指定默认值的空属性列表。

(4)方法摘要:

    ObjectsetProperty(String key, String value) 调用 Hashtable 的方法 put。

    StringgetProperty(String key) 用指定的键在此属性列表中搜索属性。

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

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

    voidlist(PrintStream out) 将属性列表输出到指定的输出流。

    voidlist(PrintWriter out) 将属性列表输出到指定的输出流。

    voidstore(OutputStream out, String comments) 以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。

    voidstore(Writer writer, String comments) 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。

    Set<String>stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键

(5)Properties代码示例:

    public staticvoid show()

    {

        Propertiesprop = new Properties();

        prop.setProperty("张三","26");

        prop.setProperty("李四","30");

        prop.setProperty("王五","35");

        sop(prop);

        Stringvalue = prop.getProperty("张三");

 

        Set<String>keys = prop.stringPropertyName();

        for(Stringkey : values)

        {

            sop(key+":"+prop.getPropety(key));

        }

    }

(6)需求:记录应用程序的使用次数,如果使用次数已到,则提示用户注册。

   思路:

   **第一次使用时建立一个配置文件用于记录使用次数

   **每次使用都加载该配置文件,并先判断已使用次数

   **每次使用完使用次数加1,写入配置文件

    public staticvoid main(String[] args) throws IOException{

        Propertiesprop = new Properties();//定义Properties,用来和IO流结合

        File file= new File("library\\time.ini");//配置文件

        if(!file.exists())

            file.createNewFile();//如果文件不存在则创建文件(用于第一次使用时创建文件)

        FileInputStreamfis = new FileInputStream(file);//定义字节读取流,读取配置文件中记录的使用次数

        prop.load(fis);//载入流,以获取文件中配置的键值对

        int count= 0;//定义使用次数

        StringcountValue = prop.getProperty("time");//通过键获取值

        if(countValue!=null){//第一次时countValue为null

            count= Integer.parseInt(countValue);//将字符串次数变成数字次数

            if(count>3){

                System.out.println("您使用次数已到,继续使用请注册!");

                return;

            }

        }

        count++;//如果使用次数未到则次数加1

        prop.setProperty("time",count+"");//配置新的键值对

        FileWriterfos = new FileWriter(file);

        prop.store(fos,"这是应用程序使用次数的配置文件");//将新的键值对写入文件

        fis.close();

        fos.close();   

    }

操作对象的流:

ObjectOutputStream:将对象序列化

ObjectInputStream:对硬盘上存储的对象反序列化

被操作的对象需要实现Serializable (标记接口)

对象序列化:

        **对象实体化:找一个介质,能长期的存储对象。

        **对象的属性在Java程序中,都是存在于对内存中,随着对象的消失而消失,而ObjectOutputStream可以将对象实体化

        **Serializable接口没有一个方法,也就是说其是一个标记接口。比如盖章的猪肉才是安全的。

        **只有实现Serializable接口的子类才能被ObjectOutputStream系列化写入流,当某个类实现该接口后,会被Java自动分配UID号,以便编译器识别,区分不同对象。

        **用ObjectOutputStream系列化的对象存储到文件后,该文件是乱码,也就是不可读的的用ObjectInputStream读取该类对象的属性。

        **由于对象是有Java给对象分配相应的UID号,而UID号是根据对象的属性不同而分配的。当一个类对象被系列化到文件后,如果该类改动了对象的属性,比如将某个成员变量变成私有则该对象再用ObjectInputStream读取时会报异常,也就是说该系列化到文件的对象不能再被使用了

          那么,要想继续使用属性被改动后的对象,我们可以自定义给对象分配UID号,让UID号不随对象的属性变化而变化。

          自定义对象分配UID方法如下:

            publicstatic final long serialVersion UID = 43L;

        **注意:

            静态不能被系列化,因为静态成员变量实在内存的方法区,而ObjectOutputStream只能对对内存里面的数据进行系列化被transient修饰的非静态成员变量也不能被系列化被系列化的对象存储到文件中,该文件是不可读的,所以该文件的扩展名一般不写成.txt,通常后缀名写.object

   

   

LineNumberReader:跟踪行号的缓冲字符输入流

              **构造方法:

              LineNumberReader(Readerin) 使用默认输入缓冲区的大小创建新的行编号 reader。

              **方法摘要:

              intread() 读取单个字符。

              intread(char[] cbuf, int off, int len) 将字符读入数组中的某一部分。

              StringreadLine() 读取文本行。

              longskip(long n) 跳过字符。

              intgetLineNumber() 获得当前行号。

              voidsetLineNumber(int lineNumber) 设置当前行号。

跟踪行号的缓冲字符输入流。默认情况下,行编号从 0 开始。

构造:LineNumberReader(Reader in) 使用默认输入缓冲区的大小创建新的行编号 reader。

方法: getLineNumber() 获得当前行号。

  setLineNumber(intlineNumber) 设置当前行号。

class MyLineNumberReader{

private Reader r;

private intlineNumber;

MyLineNumber(Readerr){----->super(r);

this.r=r;

}public StringmyReadLine() throws IOException{------>return super.myReadLine();

lineNumber++;

StringBuilder sb= 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)

return sb.toString();

return null;

}public voidgetLineNumber(){

Return lineNumber;

}public voidsetLineNumber(int lineNumber){

this.lineNumber = llineNumber;

}public voidmyClose(){---->删

r.close();//关闭流

}

}【重要】

 

 

老师的练习://读取一个.java文件,并打印在控制台上。

   //将C盘一个文本文件复制到D盘。

--->复制原理:

其实就是将C盘下的文件数据存储到D盘的一个文件中。

--->步骤:1、在D盘创建一个文件、用于存储C盘文件中的数据。

2,定义读取流和C盘文件关联。

3,通过不断的读写完成数据的存储。

4,关闭资源。

①public staticvoid copy_1() throws IOException{

//创建目的地

FileWriter fw = new FileWriter(“RuntimeDemo.txt”);

//与已有文件关联

FileReader fr = new FileReader(“RuntimeDemo.java”);

int ch = 0;

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

fw.write(ch);   //核心所在

}fw.close();fr.close();

}②public static void copy_2{

FileWriter fw = null;new Filewriter

FileReader fr = null;

char[] buf = new char[1024];int len = 0;

while((len=fr.rad(buf))!=-1){

fw.write(buf,0,len);

}

}catch(IOException e){

throw new RuntimeException(“读写失败”);

}finally{

if(fr!=null)try{fr.close();}catch(IOExceptione){}

if(fw!=null)try{fw.close();}catch(IOExceptione){}

}//重点掌握!!![下为图例:]

 

流操作的规律:

       ****流操作的难点:流对象很多,不知道具体用哪个

       ****规律:

       (1)第一步:先明确源和目的

              源:

                     文本:用Reader

                     字节:用InputStream

              目的:

                     文本:用Writer

                     字节:用OutputStream

       (2)第二步:明确是不是纯文本

              是:用字符流;

              不是:用字节流

       (3)第三步:明确流体系后,通过设备来明确具体使用哪个流对象

              源设备:

                     键盘:System.in

                     硬盘:文件流File

                     内存:数组流ArrayStream

              目的设备:

                     键盘:System.out

                     硬盘:文件流File

                     内存:数组流ArrayStream

 

       模拟readLine();代码:

public String myReadLine() throwsIOException{//谁调用谁处理

//定义一个临时容器,原BufferReader封装的是字符数组。

//为了演示方便,定义一个StringBuilder容器。因为最终还是要将数据变成字符串。

StringBuilder sb= 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)

return sb.toString(); //有问题的小地方

return null;

}

public voidmyClose() throws IOException{

r.close();

}[很重要!]


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值