黑马程序员----IO操作

来源:互联网 发布:mysql 删除表某个字段 编辑:程序博客网 时间:2024/05/20 19:19

 

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

 


IO操作

即对输入与输出的操作,通过面向对象的思想把输入与输出的数据的过程转为对流对象(IO流)的操作,简化了对数据操作的复杂度。

 

通过对流的共性的总结,可以获得四类基本抽象流类型:

输入字节流:InputStream

输入字符流:Reader

输出字节流:OutputStream

输出字符流:Writer

同异常一样,他们的子类的名字大多数是用父类坐为后缀。

 

字节:即存储在电子设备中最基本的数据单元,可以理解为一个小盒子byte,多个盒子组合在一起成为一个字符。所以处理字节或二进制对象时使用字节流。(8bits=1byte)未使用缓冲区。

 

字符:即人类可以认知的最基本的单元。比如一个文字,一个字母等,是字节与编码表的组合。处理文字时使用字符流。使用了缓冲区提高效率,要输出就要刷新缓冲区。

 

编码表:即字符与字节的对应关系表,国际上有不同的编码表:

ASCII:美国标准信息交换码

GB2312:中文编码表。

GBK:融合了更多的中文文字符号,是中国的中文编码表升级版。

Unicode:国际标准码,所有文字都用两个字节来表示,java使用的就是unicode。

UTF-8:最多用三个字节来表示一个字符,使用方便。

编码:字符串变成字节数组:str.getBytes(charsetName);

解码:字节数组变成字符串:newString(byte[].charsetName);

 

对流的操作

Eg:

//IO操作常常会伴随着异常的出现,所以必须抛出或try,多数情况下应该try。

      try(InputStream is = new FileInputStream(src);

        OutputStream os = newFileOutputStream(tar);)

//第一步的建立输入输入流对象。

{

        byte[] b = newbyte[1024];//建立缓冲区提高效率。

        int len;

        while ((len = is.read(b)) != -1)    //先读取数据

         {

           os.write(b);//后写入数据

        }

 

         }

 catch (IOException e)

{

        e.printStackTrace();

         }

 

注意:()圆括号内创建的对象必须实现Autocloseable接口,从而对象可以自动关闭资源。

Eg:

public static void copy

{

FileWriter fw = null;

FileReader fr = null;

char[] buf = new char[1024];intlen = 0;

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

{

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){}

}

}

Eg:复制图片:

图片》》字节流

 

public class Demo

{

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

{

      File src = newFile("E:/java.jpg");

     

      File tar = newFile("E:/tar.jpg");

     

      copy(src,tar);

      System.out.println("复制完成!");

   }

 

   public static void copy(Filesrc,File tar) throws Exception

{

      //流对象的创建

      InputStream in = newFileInputStream(src);

      OutputStream os = newFileOutputStream(tar);

      //缓冲区的建立

      byte []c = new byte[1024];

      int len;

//数据的读取

      while((len = in.read(c)) !=-1)

{//数据的存入

        os.write(c);

      }

      //资源的关闭。对于字节流可以不操作,但是养成习惯有必要。

      w.close();

      r.close();

   }

}

 

缓冲字符流:

缓冲区的出现提高了对数据的读写效率。

BufferedWriter

BufferedReader

 

Eg:

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

   BufferedWriterbufw = new BufferedWriter(fw); //创建文件字符写入流的缓冲与流对象关联

   bufw.write(“asdfg1234”);//数据进入缓冲区

   bufw.flush();//使用缓冲区的刷新方法将数据刷到目的地

   bufw.close();//关闭缓冲区也关闭了流资源

 

对于缓冲读取流,具有readline方法方便了对文本文件的的读取。

String s = bufr.readLine();

读取一行并保存在字符串s中,到末尾返回null。事实上市read的原理的修饰版。原理如下:

public String myReadLine() throws IOException

{

StringBuilder sb = newStringBuilder();//字符串容器

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 void myClose() throws IOException

{

r.close();

}

 

拓展:

装饰模式:

如把read装饰成为realine一样,与继承一样的功能,装饰设计模式通过把原有的类,功能进行不修改的拓展(重新创建一个类并引入要拓展的类进行修饰)。其中为了更强的功能,装饰类通常会通过构造方法接受被装饰的对象。

例如:Writer中用于操作文本TextWriter与用于操作媒体的MediaWriter都可以进行装饰后成为BufferTextWriter和BufferMediaWriter,同样是加入缓冲技术,那么直接引入BufferedWriter,在使用的时候对TextWriter嵌套进去进行装饰成为BufferedWriter(new TextWriter)即可,方便灵活。(假如是通过继承来达到同样的目的,那么继承体系将会很臃肿,不便于学习与升级)。

 

Eg:

LineNumberReader原理:

class MyLineNumberReader

{

private Reader r ;

private int lineNumber;

MyLineNumber(Reader r)// 通过构造方法接受被装饰的对象

{

      this.r=r;

}

 

public String myReadLine()throws IOException //文本读取操作

{

lineNumber++;

StringBuilder sb = newStringBuilder();

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 void getLineNumber()//获取行数

{

Return lineNumber;

}

 

public void setLineNumber(intlineNumber)//设置行数

{

this.lineNumber = llineNumber;

}

 

public void myClose()

{

r.close();//关闭流

}

}

   :

字节流:

当要操作图片,字节码数据时要用到字节流。

InputStream

OutputStream

 

Eg:

public static void writeFile() throws IOException

{

FileOutputSream fos = newFileOutputStream(“fos.txt”);

fox.write(“asfdsdgjh”.getBytes());//字符串变成字节数组

fos.close();//不需要flush()。

}

 

Eg:

public static void readFile() throws IOException

{

FileInputSream fis = new FileInputStream(“fos.txt”);

Byte[] buf = new byte[1024];//一次读取多个字节,但可能会溢出数据。

// byte[] buf = newbyte[fis.available()];//一次读取刚好不会溢出的多个字节。

int len = 0;

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

{

System.out.println(newString(buf,0,len));

}

fis.close();

}

 

缓冲字节流:

与缓冲字符流效果一样。

BufferedOutputStream

BufferedIntputStream

 

Eg:

class MyBuffereInputStream//装饰类

{

private InputStream in;

private byte[] buf = newbyte[1024*4];

Private int pos=0,count=0;

MyBuffereInputStream(InputStream  in)

{//通过in对象读取硬盘上数据,并存储buf中。

   this.in= in;

}

 

public int myRead() throwsIOException

{//一次读一个字节,从缓冲区获取。

if(count==0)

{

count=in.read(buf);

pos=0 ;

byte b=buf[pos] ;

count-- ;

pos++ ;

return b&255 ;

}

else if(count>0)

{

byte b = buf[pos] ;

count-- ;

pos++ ;

return b&0xff ;

}

return -1;

}

 

public void myClose()throwsIOException

{

in.close();

}

}

 

字节字符转换流

可以把字节流转换为字符流,以方便使用字符流的方法。

OutputStreamWriter:把字节输出流对象转成字符输出流对象

InputStreamReader:把字节输入流对象转成字符输入流对象

 

提供了最长用的获取键盘输入的方法:

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

BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));

文本--->控制台

BufferedReader bufr = new BufferedReader(new InputStreamReader(newFileInputStream(“1.txt”)));

BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));

控制台-->文本

BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(newFileOutputStream(”demo.txt”)));

 

Eg:

 

InputStream is = new FileInputStream("");//构建一个字节输入流对象

 

Reader r = new InputStreamReader(is); //把字节输入流转成字符输入流

 

内存操作流

当输出的数据进入内存,使用内存操作流,以提升性能。

ByteArrayInputStream:写入内存    CharArrayReader

ByteArrayOutputStream:写出数据     CharArrayWriter

 

Eg:

String s = "String to be input";

//输出流的创建

ByteArrayOutputStream bos = new ByteArrayOutputStream();

//写入内存中

bos.write(s.getBytes());

byte[] bys = bos.toByteArray();//读取的数据源

//创建输入流,明确源。

ByteArrayInputStream bis = new ByteArrayInputStream(bys);

byte[] b = new byte[1024];

int len;

while ((len = bis.read(b)) != -1) //读取数据

{

        String data = new String(b,0, len);

        System.out.println(data);

   }

}

 

打印流

针对任意数据类型的操作所使用的类,比如操作字符串或者是boolean型或者是字符型

PrintWriter

PrintStream

 

注意:

1,在实例化的时候依然需要一个OutputStream的对象。

2,PrintStream和PrintWriter都属于输出流,分别针对字节和字符。,

3,PrintWriter和PrintStream重载的print()和println()用于多种数据类型的输出。其中print()里的参数不能为空;println()可以。

4,PrintStream调用println方法有自动flush功能;

5,PrintWriter和PrintStream输出操作不抛出异常;

6,格式化输出操作使用printf()方法,需要指定输出数据的类型:

String format = "姓名=%s,学号=%s,年龄=%d,成绩=%f";

System.out.printf(format,name,num,age,score);

 

 

Eg:

// 创建字符打印流

PrintWriter pr = new PrintWriter(new FileWriter("out.txt"),true);//必须调用println,print,format这些方法的其中一个才可以实现操作自动刷新

pr.println("我是输入的内容");

pr.println(true);

pr = new PrintWriter(System.out, true);

pr.println(3dfsfsfsd234535);

 

标准流

标准输入流,默认表示的是键盘录入:  System.in  

标准输出流,默认表示的是屏幕输出:  System.out 

 

改变默认值:

System.setIn(new FileInputStream("demoA"));//改变默认打印源

System.setOut(new PrintStream("demoB.txt"));//改变默认打印目的地到文件中

 

文本扫描器Scanner

Eg:

Scanner sc = new Scanner(System.in);

while(sc.hasNext())

{

   String s = sc.next();

   System.out.println(s);

}

 

合并流

用于将两个流进行合并:SequenceInputStream(InputStream s1, InputStream s2) ,根据两个流对象来创建合并流对象,FIFO。

 

Eg:

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

{

      SequenceInputStream si = newSequenceInputStream(

           newFileInputStream("6.4"),

           newFileInputStream("hello.java"));

     

      OutputStream os = newFileOutputStream("sequence.txt");

      int len;

      byte []b = new byte[1024];

      while((len = si.read(b)) !=-1)

{

        os.write(b, 0, len);

      }

}

 

流操作的基本规律总结:

1,明确体系:  数据源:InputStream,Reader

        数据汇:OutputStream,Writer

2,明确数据:数据分两种:字节,字符。

   数据源:是否是纯文本数据呢?是:Reader 否:InputStream

   数据汇:是:Writer 否:OutputStream

到这里就可以明确具体要使用哪一个体系了。

接下来要明确使用这个体系中的哪个对象。

3,明确设备:

   数据源: 键盘:System.in

        硬盘:FileXXX

        内存:数组。

        网络:socket  socket.getInputStream();

   数据汇: 控制台:System.out

        硬盘:FileXXX

        内存:数组

        网络:socketsocket.getOutputStream();

4,明确额外功能: 1,需要转换?是,使用转换流。InputStreamReader OutputStreamWriter

           2,需要高效?是,使用缓冲区。Buffered

           3,需要其他?

复制一个文本文件:

   1,明确体系:  源:InputStream ,Reader

           目的:OutputStream,Writer

   2,明确数据:  源:是纯文本吗?是 Reader

           目的;是纯文本吗?是Writer

   3,明确设备:  源:硬盘上的一个文件。  FileReader

           目的:硬盘上的一个文件。FileWriter

           FileReader fr = newFileReader("a.txt");

           FileWriter fw = new FileWriter("b.txt");

   4,需要额外功能吗?需要,高效,使用buffer

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

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

读取键盘录入,将数据存储到一个文件中:

   1,明确体系:  源:InputStream ,Reader

           目的:OutputStream,Writer

   2,明确数据:  源:是纯文本吗?是 Reader

           目的;是纯文本吗?是Writer

   3,明确设备:  源:键盘,System.in

           目的:硬盘,FileWriter

           InputStream in =System.in;

           FileWriter fw = newFileWriter("a.txt");

   4,需要额外功能吗?

需要,因为源明确的体系是Reader。可是源的设备是System.in。

      所以需要转换流。InputStreamReader

      InputStreamReader isr = newInputStreamReader(System.in);

      FileWriter fw  = new FileWriter("a.txt");

      需要高效用:

BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in));

      BufferedWriter bufw = newBufferedWriter(new FileWriter("a.txt"));

读取一个文本文件,将数据展现在控制台上:

      1,明确体系:  源:InputStream ,Reader

              目的:OutputStream,Writer

      2,明确数据:  源:是纯文本吗?是 Reader

              目的;是纯文本吗?是Writer

      3,明确设备:  源:硬盘文件,FileReader。

              目的:控制台:System.out。

              FileReader fr = newFileReader("a.txt");

              OutputStream out =System.out;

      4,需要额外功能?

        需要一个转换流,OutputStreamWriter

        FileReader fr = newFileReader("a.txt");

        OutputStreamWriter osw =new OutputStreamWriter(System.out);

        需要高效     

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

BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));

读取键盘录入,将数据展现在控制台上:

      1,明确体系:  源:InputStream ,Reader

              目的:OutputStream,Writer

      2,明确数据:  源:是纯文本吗?是 Reader

              目的;是纯文本吗?是Writer

      3,明确设备:  源:键盘:System.in

              目的:控制台:System.out

              InputStream in =System.in;

              OutputStream out =System.out;

      4,需要额外功能,使用转换流。

        为了提高效率,使用Buffer

BufferedReader bufr  =newBufferedReader(new InputStreamReader(Systme.in));

BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));

读取一个文本文件,将文件按照指定的编码表UTF-8进行存储,保存到另一个文件中:

      1,明确体系:  源:InputStream ,Reader

              目的:OutputStream,Writer

      2,明确数据:  源:是纯文本吗?是 Reader

              目的;是纯文本吗?是Writer

      3,明确设备:  源:硬盘:FileReader.

              目的:硬盘:FileWriter

              FileReader fr = newFileReader("a.txt");

              FileWriter fw = newFileWriter("b.txt");

      4,额外功能:

        需要指定编码表,需要转换功能OutputStreamWriter使用字节输出流中的操作文件的流对象FileOutputStream。

        FileReader fr = newFileReader("a.txt");        OutputStreamWriterosw = new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8");

        需要高效

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

BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8"));

 



0 0