黑马程序员--IO流和字符编码

来源:互联网 发布:专科学软件专业 编辑:程序博客网 时间:2024/05/17 03:04

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------




IO流和字符编码

  File类的常见方法。

  1,创建。

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

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

                boolean mkdir():创建文件夹。

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

  2,删除。

                boolean delete();删除失败。返回false。

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

  3,判断。

                boolean exists():文件是否存在。

                isFile();是否是一个标准文件。

                isDirectory();是否是一个目录。

                isHidden();是否是一个隐藏文件。

                isAbsolute();是否为绝对路径名。

  4,获取信息。

                getName(); 获得文件名

                getPath();  封装什么路径就返回什么路径。

                getParent();     获得上级目录

该方法返回的是绝对路径的父目录。如果获取的是相对路径,返回Null

 

                getAbsolutePath();无论封装的是什么路径,返回的都是绝对路径名、

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

                length();返回由此抽象路径名表示的文件的长度。

 

 

File对象的简单应用:

package com.itheima;

 

import java.io.File;

 

public class FileDemo {

    public static void main(String[] args) {

       //创建一个File对象,文件地址为E:\FileTest.txt  大小200字节。

       Filefile = new File("E:\\FileTest.txt");

       //判断file是否是文件

       if(file.isFile()){

           //获得文件名

           System.out.println(file.getName());

           //获得上级目录

           System.out.println(file.getParent());

           //获得E:\FileTest.txt大小

           System.out.println(file.length());

       }

    }

}

 

IO流:

Java对数据的操作是通过流的方式进行的,IO流是用来处理设备之间的数据传输,Java用于操作流的对象都在Java.IO包中。

Java流按操作数据分为两种:字节流和字符流。

 

字节流字符流继承简图:



字节流:

InputStream:字节流读取对象。

         InputStream的实现子类常用的有:FileInputStream,

                   FileInputStream中常用方法有:

                            int read(); 读取1个字节数据,然后返回该字节转换成的0-255范围的int值,读取完为-1

int read(byte[]b); 读取流中数据写入字节数组,返回本次读入的长度int值

int read(byte[]b,int off,int len) 读取len长度的字节数,写入b的off开始的字节数组中

void close(); 关闭流

 

 

OutputStream:字节流输出对象。

         OutputStream的实现子类常用的有:FileOutputStream

FileOutputStream中常有方法有:

write(int b); 将b.length 个字节从指定的 byte 数组写入此输出流。

                       (注:此处写入的是最后8个字节。)

write(byte[]b); 将byte数组写入到输出流中。

write(byte[]b,int off,int len); 将byte数组写入流中,从off开始,len结束。

void flush();刷新此输出流并强制写出所有缓冲的输出字节。

void close();关闭前会自行刷新一次。

 

字符流:

字节流和字符流的区别:字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。并且字节流可以更好的保留数据原始性,在拷贝文件时,字符流是将一个二进制找到其对应的编码,然后再将其切入,而字节流确实直接将源数据拷贝过去,保证了数据的原始性。

字符读取流抽象对象:Reader;

Reader抽象类中常有子类有:BufferedReader,FileReader,InputStreamReader(为转换流,下处会讲到。)

         在BufferedReader中常有方法有:

                   close() :关闭该流并释放与之关联的所有资源。

read()读取单个字符。

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

readLine() :读取一个文本行。

 

 

         字节流输出对象:Writer

                   Writer抽象类中常用子类有:BufferedWriter,FileWriter,OutputStreamWriter(为转换流,下处会讲到。)

                            在BufferedWriter中常用的方法有:

close() 关闭此流,但要先刷新它。à必须关闭,如处理异常需要在最后的finally块中执行关闭动作。

flush()  刷新该流的缓冲。

newLine() 写入一个行分隔符。à因为操作平台不同,所以换行可能不一样,Java提供了newLine()方法,可以方便去插入换行符。

write(char[] cbuf, int off, int len) 写入字符数组的某一部分。

write(int c) 写入单个字符。

write(String s, int off, int len) 写入字符串的某一部分。

和从BufferedWriter父类Writer继承的方法:append (char c),append (CharSequence csq,int start,int end),append (CharSequence csq)

, write (String str,int off,int len), write (String str)

 

字符流与字节流的转换:

InputStreamReader字节流通向字符流的桥梁
OutputStreamWriter 是字符流通向字节流的桥梁

 

流的异常处理:

需要在finally块中加入关闭语句,但是在之前要判断流对象是否为空。

例如:

BufferedReader bufr =null;

       BufferedWriter bufw = null;

      

       try {

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

           bufw = new BufferedWriter(new FileWriter("b.txt"));

          

           String line = null;

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

              bufw.write(line);

              bufw.newLine();

              bufw.flush();

             

           }

       } catch (FileNotFoundExceptione) {

           // TODO Auto-generatedcatch block

           e.printStackTrace();

       } catch (IOExceptione) {

           // TODO Auto-generatedcatch block

           e.printStackTrace();

       }finally{

           if(bufr!=null){

              try {

                  bufr.close();

              } catch (IOExceptione) {

                  // TODO Auto-generatedcatch block

                  e.printStackTrace();

              }

           }

           if(bufw!=null){

              try {

                  bufw.close();

              } catch (IOExceptione) {

                  // TODO Auto-generatedcatch block

                  e.printStackTrace();

              }

           }

       }

 

 

 

那么如何确认应该使用哪一种流呢?

通过三个明确来完成。

 

  1,明确源 和 目的。

                源:输入流。InputStream/Reader 。

                目的:输出流。OutputStream/Writer。

  2,明确操作的数据是否是纯文本。

                是:字符流。

                不是:字节流。

 

  3,当体系明确后再明确要使用哪个具体的对象。

                通过设备来进行区分。

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

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

示例一:从C盘复制itheima.txt到E盘中。

 

 

package com.itheima;

 

import java.io.*;

 

/*

  1,明确源目的。

        源:输入流。InputStream/Reader

        目的:输出流。OutputStream/Writer

  2,明确操作的数据是否是纯文本。

        是:字符流。

 

  3,当体系明确后再明确要使用哪个具体的对象。

        通过设备来进行区分。

        源设备:硬盘。C:

        目的设备:硬盘。E:

 

 */

package com.itheima;

 

import java.io.*;

 

/*

  1,明确源目的。

        源:输入流。InputStream/Reader

        目的:输出流。OutputStream/Writer

  2,明确操作的数据是否是纯文本。

        是:字符流。

 

  3,当体系明确后再明确要使用哪个具体的对象。

        通过设备来进行区分。

        源设备:硬盘。C:

        目的设备:硬盘。E:

 

 */

 

public class CopyTxtTest {

    public static void main(String[] args)  {

       //得到c:itheima.txtFile对象。

       File in = new File("c:\\itheima.txt");

       //判断是否是为文件。

       if(in.isFile()){

           //创建BufferedReader对象。因为要在finally块中执行close()语句所以定义在外面。

           BufferedReaderbufr =null;

           //创建BufferedWriter对象。

           BufferedWriter bufw =null;

           try {

             

              //获取到in

              bufr = newBufferedReader(new FileReader(in));

              //获取到out

              bufw = new BufferedWriter(new FileWriter("e:\\itheima.txt"));

              String line =null;

              //line等于bufr.readLine()当不为空时开始循环,到文件末尾。

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

                  //写出一行到out.

                  bufw.write(line);

                  //换行符。

                  bufw.newLine();

                  //将缓冲区中的数据刷新到out中。

                  bufw.flush();

              }

           } catch (IOExceptione) {

              // TODO Auto-generatedcatch block

              e.printStackTrace();

           }finally{

              //检查bufw是否为空

              if(bufw!=null){

                  try {

                     //bufw不为空,关闭。

                     bufw.close();

                  } catch (IOExceptione) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

                  }

              }

              //检查bufr是否为空。

              if(bufr!=null){

                  try {

                     //bufr不为空,关闭。

                     bufr.close();

                  } catch (IOExceptione) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

                  }

              }

           }

       }

    }

}

 

 

示例二:将c盘中1.MP3复制到e盘中。

 

package com.itheima;

 

import java.io.*;

 

/*

 *

  1,明确源目的。

        源:输入流。InputStream/Reader

        目的:输出流。OutputStream/Writer

  2,明确操作的数据是否是纯文本。

        否:字符流。

 

  3,当体系明确后再明确要使用哪个具体的对象。

        通过设备来进行区分。

        源设备:硬盘。C:

        目的设备:硬盘。E:

 */

public class CopyMp3Test {

    public static void main(String[] args) {

       File file = new File("c:\\1.mp3");

       CopyMp3(file);

    }

 

    private static void CopyMp3(File file) {

       if(file.isFile()){

           InputStream in =null;

           OutputStream out = null;

           try {

              in = new FileInputStream(file);

              String str = file.getName();

              out = new FileOutputStream("e:\\"+str);

             

              byte[]buf = newbyte[1024];

             

              intlen = 0;

              while((len =in.read(buf))!=-1){

                  out.write(buf, 0,len);

              }

             

           } catch (FileNotFoundExceptione) {

              // TODO Auto-generatedcatch block

              e.printStackTrace();

           } catch (IOExceptione) {

              // TODO Auto-generatedcatch block

              e.printStackTrace();

           }finally{

              if(in!=null){

                  try {

                     in.close();

                  } catch (IOExceptione) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

                  }

              }

              if(out!=null){

                  try {

                     out.close();

                  } catch (IOExceptione) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

                  }

              }

           }

       }

    }

}

 

管道读取流和管道写入流可以像管道一样对接上,管道读取流就可以读取管道写入流写入的数据。
注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据的read方法会让线程等待。

        public static void main(String[] args) throws IOException
        {
                PipedInputStream pipin = new PipedInputStream();
               PipedOutputStream pipout = new PipedOutputStream();
               pipin.connect(pipout);
               new Thread(new Input(pipin)).start();
               new Thread(new Output(pipout)).start();
         }

RandomAccessFile类

(1)自身具备读写方法(很牛逼!又可以读又可以写)
(2)通过skipByte(int x)和seek(int x)来达到随机访问文件
(3)该类不是IO体系子类,而是直接继承Object,但它是IO包中的成员,因为它具备读写方法
(4)该类内部封装了数组,而且通过指针对数组的元素进行操作,可以通过getFilePoint获取指针位置,同时可以通过seek改变指针位置
(5)该类可以完成读写的原理是:内部封装了字节输入输出流
(6)构造函数:RandomAccessFile(File file,String mode),RandomAccessFile(Stringname, String mode),可已从它的构造函数中看出,该类只能操作文件(也有字符串),而且操作文件还有模式。
          模式传入值:”r“:以只读方式打开;”rw“:打开以便读写
          如果模式为只读,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常,如果模式为rw,且该对象的构造函数要操作的文件不存在,会自动创建,如果存在,则不会覆盖,也可通过seek方法修改。
package com.itheima;

 

import java.io.IOException;

import java.io.RandomAccessFile;

 

public class RamdomAccessFileDemo {

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

            // readRaf(); 

            readRaf2(); 

            // writeRaf(); 

        } 

     

        // 写入数据 

        public static void writeRaf() throws IOException { 

            // 创建对象,写入数据 

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

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

            raf.writeInt(99); 

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

            raf.writeInt(97); 

            raf.close(); 

        } 

     

        // 读取数据 

        public static void readRaf() throws IOException { 

            // 创建对象,读取数据 

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

            byte[]b = newbyte[4]; 

            raf.read(b); 

            String name = new String(b); 

            intage = raf.readInt(); 

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

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

            raf.close(); 

        } 

     

        // 读取数据 

        public static void readRaf2() throws IOException { 

            // 创建对象,读取数据 

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

            // 调整对象中的指针 

            // raf.seek(8); 

            // 跳过指定字节数 

            raf.skipBytes(8); 

            byte[]b = newbyte[4]; 

            raf.read(b); 

            String name = new String(b); 

            intage = raf.readInt(); 

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

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

            raf.close(); 

        } 

}

 

装饰设计模式:

 

装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供加强工功能,那么自定义的类称为装饰类。

 

装饰模式和继承有什么不同?

         装饰模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系,装饰类因为是增强已有关系,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常都是一个体系中。

 

 

装饰设计模式的基本格式。

示例:

package com.itheima;

 

import java.io.IOException;

import java.io.Reader;

 

public class MyBufferedReader extends Reader{

    private Readerr ;

    //通过构造方法得到传入的类对象。

    public MyBufferedReader(Readerr) {

       super();

       this.r =r;

    }

   

    public String myReadLine()throws IOException{

       StringBuffer sb = new StringBuffer();

       int ch = 0;

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

           if(ch=='\r')

              continue;

           if(ch=='\n'){

              returnsb.toString();

           }else{

              sb.append((char)ch);

           }

       }

       if(sb.length()!=0){

           returnsb.toString();

       }

       return null;

    }  

    @Override

    public void close() throws IOException {

       // TODO Auto-generatedmethod stub

       r.close();

    }

 

    @Override

    public int read(char[]arg0, intarg1, intarg2) throws IOException {

       // TODO Auto-generatedmethod stub

       returnr.read(arg0,arg1, arg2);

    }

 

}

 

 

 

 

字符编码:

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

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

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

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

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

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

可以通过getBytes(charsetName),newString(byte[],charsetName)  传入字符编码。

0 0
原创粉丝点击